summaryrefslogtreecommitdiff
path: root/runtime/jdwp/jdwp_expand_buf.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/jdwp/jdwp_expand_buf.cc')
-rw-r--r--runtime/jdwp/jdwp_expand_buf.cc188
1 files changed, 188 insertions, 0 deletions
diff --git a/runtime/jdwp/jdwp_expand_buf.cc b/runtime/jdwp/jdwp_expand_buf.cc
new file mode 100644
index 0000000000..0a64f28e11
--- /dev/null
+++ b/runtime/jdwp/jdwp_expand_buf.cc
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Implementation of an expandable byte buffer. Designed for serializing
+ * primitive values, e.g. JDWP replies.
+ */
+
+#include "jdwp/jdwp_expand_buf.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/logging.h"
+#include "jdwp/jdwp.h"
+#include "jdwp/jdwp_bits.h"
+
+namespace art {
+
+namespace JDWP {
+
+/*
+ * Data structure used to track buffer use.
+ */
+struct ExpandBuf {
+ uint8_t* storage;
+ int curLen;
+ int maxLen;
+};
+
+#define kInitialStorage 64
+
+/*
+ * Allocate a JdwpBuf and some initial storage.
+ */
+ExpandBuf* expandBufAlloc() {
+ ExpandBuf* newBuf = new ExpandBuf;
+ newBuf->storage = reinterpret_cast<uint8_t*>(malloc(kInitialStorage));
+ newBuf->curLen = 0;
+ newBuf->maxLen = kInitialStorage;
+ return newBuf;
+}
+
+/*
+ * Free a JdwpBuf and associated storage.
+ */
+void expandBufFree(ExpandBuf* pBuf) {
+ if (pBuf == NULL) {
+ return;
+ }
+
+ free(pBuf->storage);
+ delete pBuf;
+}
+
+/*
+ * Get a pointer to the start of the buffer.
+ */
+uint8_t* expandBufGetBuffer(ExpandBuf* pBuf) {
+ return pBuf->storage;
+}
+
+/*
+ * Get the amount of data currently in the buffer.
+ */
+size_t expandBufGetLength(ExpandBuf* pBuf) {
+ return pBuf->curLen;
+}
+
+/*
+ * Ensure that the buffer has enough space to hold incoming data. If it
+ * doesn't, resize the buffer.
+ */
+static void ensureSpace(ExpandBuf* pBuf, int newCount) {
+ if (pBuf->curLen + newCount <= pBuf->maxLen) {
+ return;
+ }
+
+ while (pBuf->curLen + newCount > pBuf->maxLen) {
+ pBuf->maxLen *= 2;
+ }
+
+ uint8_t* newPtr = reinterpret_cast<uint8_t*>(realloc(pBuf->storage, pBuf->maxLen));
+ if (newPtr == NULL) {
+ LOG(FATAL) << "realloc(" << pBuf->maxLen << ") failed";
+ }
+
+ pBuf->storage = newPtr;
+}
+
+/*
+ * Allocate some space in the buffer.
+ */
+uint8_t* expandBufAddSpace(ExpandBuf* pBuf, int gapSize) {
+ uint8_t* gapStart;
+
+ ensureSpace(pBuf, gapSize);
+ gapStart = pBuf->storage + pBuf->curLen;
+ /* do we want to garbage-fill the gap for debugging? */
+ pBuf->curLen += gapSize;
+
+ return gapStart;
+}
+
+/*
+ * Append a byte.
+ */
+void expandBufAdd1(ExpandBuf* pBuf, uint8_t val) {
+ ensureSpace(pBuf, sizeof(val));
+ *(pBuf->storage + pBuf->curLen) = val;
+ pBuf->curLen++;
+}
+
+/*
+ * Append two big-endian bytes.
+ */
+void expandBufAdd2BE(ExpandBuf* pBuf, uint16_t val) {
+ ensureSpace(pBuf, sizeof(val));
+ Set2BE(pBuf->storage + pBuf->curLen, val);
+ pBuf->curLen += sizeof(val);
+}
+
+/*
+ * Append four big-endian bytes.
+ */
+void expandBufAdd4BE(ExpandBuf* pBuf, uint32_t val) {
+ ensureSpace(pBuf, sizeof(val));
+ Set4BE(pBuf->storage + pBuf->curLen, val);
+ pBuf->curLen += sizeof(val);
+}
+
+/*
+ * Append eight big-endian bytes.
+ */
+void expandBufAdd8BE(ExpandBuf* pBuf, uint64_t val) {
+ ensureSpace(pBuf, sizeof(val));
+ Set8BE(pBuf->storage + pBuf->curLen, val);
+ pBuf->curLen += sizeof(val);
+}
+
+static void SetUtf8String(uint8_t* buf, const char* str, size_t strLen) {
+ Set4BE(buf, strLen);
+ memcpy(buf + sizeof(uint32_t), str, strLen);
+}
+
+/*
+ * Add a UTF8 string as a 4-byte length followed by a non-NULL-terminated
+ * string.
+ *
+ * Because these strings are coming out of the VM, it's safe to assume that
+ * they can be null-terminated (either they don't have null bytes or they
+ * have stored null bytes in a multi-byte encoding).
+ */
+void expandBufAddUtf8String(ExpandBuf* pBuf, const char* s) {
+ int strLen = strlen(s);
+ ensureSpace(pBuf, sizeof(uint32_t) + strLen);
+ SetUtf8String(pBuf->storage + pBuf->curLen, s, strLen);
+ pBuf->curLen += sizeof(uint32_t) + strLen;
+}
+
+void expandBufAddUtf8String(ExpandBuf* pBuf, const std::string& s) {
+ ensureSpace(pBuf, sizeof(uint32_t) + s.size());
+ SetUtf8String(pBuf->storage + pBuf->curLen, s.data(), s.size());
+ pBuf->curLen += sizeof(uint32_t) + s.size();
+}
+
+void expandBufAddLocation(ExpandBuf* buf, const JdwpLocation& location) {
+ expandBufAdd1(buf, location.type_tag);
+ expandBufAddObjectId(buf, location.class_id);
+ expandBufAddMethodId(buf, location.method_id);
+ expandBufAdd8BE(buf, location.dex_pc);
+}
+
+} // namespace JDWP
+
+} // namespace art