/* * 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 == nullptr) { 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 == nullptr) { 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-nullptr-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 = (s != nullptr ? strlen(s) : 0); 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