Home | History | Annotate | Download | only in jdwp
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 /*
     17  * Implementation of an expandable byte buffer.  Designed for serializing
     18  * primitive values, e.g. JDWP replies.
     19  */
     20 
     21 #include "jdwp/jdwp_expand_buf.h"
     22 
     23 #include <stdlib.h>
     24 #include <string.h>
     25 
     26 #include <android-base/logging.h>
     27 
     28 #include "jdwp/jdwp.h"
     29 #include "jdwp/jdwp_bits.h"
     30 
     31 namespace art {
     32 
     33 namespace JDWP {
     34 
     35 /*
     36  * Data structure used to track buffer use.
     37  */
     38 struct ExpandBuf {
     39   uint8_t*     storage;
     40   int     curLen;
     41   int     maxLen;
     42 };
     43 
     44 #define kInitialStorage 64
     45 
     46 /*
     47  * Allocate a JdwpBuf and some initial storage.
     48  */
     49 ExpandBuf* expandBufAlloc() {
     50   ExpandBuf* newBuf = new ExpandBuf;
     51   newBuf->storage = reinterpret_cast<uint8_t*>(malloc(kInitialStorage));
     52   newBuf->curLen = 0;
     53   newBuf->maxLen = kInitialStorage;
     54   return newBuf;
     55 }
     56 
     57 /*
     58  * Free a JdwpBuf and associated storage.
     59  */
     60 void expandBufFree(ExpandBuf* pBuf) {
     61   if (pBuf == nullptr) {
     62     return;
     63   }
     64 
     65   free(pBuf->storage);
     66   delete pBuf;
     67 }
     68 
     69 /*
     70  * Get a pointer to the start of the buffer.
     71  */
     72 uint8_t* expandBufGetBuffer(ExpandBuf* pBuf) {
     73   return pBuf->storage;
     74 }
     75 
     76 /*
     77  * Get the amount of data currently in the buffer.
     78  */
     79 size_t expandBufGetLength(ExpandBuf* pBuf) {
     80   return pBuf->curLen;
     81 }
     82 
     83 /*
     84  * Ensure that the buffer has enough space to hold incoming data.  If it
     85  * doesn't, resize the buffer.
     86  */
     87 static void ensureSpace(ExpandBuf* pBuf, int newCount) {
     88   if (pBuf->curLen + newCount <= pBuf->maxLen) {
     89     return;
     90   }
     91 
     92   while (pBuf->curLen + newCount > pBuf->maxLen) {
     93     pBuf->maxLen *= 2;
     94   }
     95 
     96   uint8_t* newPtr = reinterpret_cast<uint8_t*>(realloc(pBuf->storage, pBuf->maxLen));
     97   if (newPtr == nullptr) {
     98     LOG(FATAL) << "realloc(" << pBuf->maxLen << ") failed";
     99   }
    100 
    101   pBuf->storage = newPtr;
    102 }
    103 
    104 /*
    105  * Allocate some space in the buffer.
    106  */
    107 uint8_t* expandBufAddSpace(ExpandBuf* pBuf, int gapSize) {
    108   uint8_t* gapStart;
    109 
    110   ensureSpace(pBuf, gapSize);
    111   gapStart = pBuf->storage + pBuf->curLen;
    112   /* do we want to garbage-fill the gap for debugging? */
    113   pBuf->curLen += gapSize;
    114 
    115   return gapStart;
    116 }
    117 
    118 /*
    119  * Append a byte.
    120  */
    121 void expandBufAdd1(ExpandBuf* pBuf, uint8_t val) {
    122   ensureSpace(pBuf, sizeof(val));
    123   *(pBuf->storage + pBuf->curLen) = val;
    124   pBuf->curLen++;
    125 }
    126 
    127 /*
    128  * Append two big-endian bytes.
    129  */
    130 void expandBufAdd2BE(ExpandBuf* pBuf, uint16_t val) {
    131   ensureSpace(pBuf, sizeof(val));
    132   Set2BE(pBuf->storage + pBuf->curLen, val);
    133   pBuf->curLen += sizeof(val);
    134 }
    135 
    136 /*
    137  * Append four big-endian bytes.
    138  */
    139 void expandBufAdd4BE(ExpandBuf* pBuf, uint32_t val) {
    140   ensureSpace(pBuf, sizeof(val));
    141   Set4BE(pBuf->storage + pBuf->curLen, val);
    142   pBuf->curLen += sizeof(val);
    143 }
    144 
    145 /*
    146  * Append eight big-endian bytes.
    147  */
    148 void expandBufAdd8BE(ExpandBuf* pBuf, uint64_t val) {
    149   ensureSpace(pBuf, sizeof(val));
    150   Set8BE(pBuf->storage + pBuf->curLen, val);
    151   pBuf->curLen += sizeof(val);
    152 }
    153 
    154 static void SetUtf8String(uint8_t* buf, const char* str, size_t strLen) {
    155   Set4BE(buf, strLen);
    156   if (str != nullptr) {
    157     memcpy(buf + sizeof(uint32_t), str, strLen);
    158   }
    159 }
    160 
    161 /*
    162  * Add a UTF8 string as a 4-byte length followed by a non-nullptr-terminated
    163  * string.
    164  *
    165  * Because these strings are coming out of the VM, it's safe to assume that
    166  * they can be null-terminated (either they don't have null bytes or they
    167  * have stored null bytes in a multi-byte encoding).
    168  */
    169 void expandBufAddUtf8String(ExpandBuf* pBuf, const char* s) {
    170   int strLen = (s != nullptr ? strlen(s) : 0);
    171   ensureSpace(pBuf, sizeof(uint32_t) + strLen);
    172   SetUtf8String(pBuf->storage + pBuf->curLen, s, strLen);
    173   pBuf->curLen += sizeof(uint32_t) + strLen;
    174 }
    175 
    176 void expandBufAddUtf8String(ExpandBuf* pBuf, const std::string& s) {
    177   ensureSpace(pBuf, sizeof(uint32_t) + s.size());
    178   SetUtf8String(pBuf->storage + pBuf->curLen, s.data(), s.size());
    179   pBuf->curLen += sizeof(uint32_t) + s.size();
    180 }
    181 
    182 void expandBufAddLocation(ExpandBuf* buf, const JdwpLocation& location) {
    183   expandBufAdd1(buf, location.type_tag);
    184   expandBufAddObjectId(buf, location.class_id);
    185   expandBufAddMethodId(buf, location.method_id);
    186   expandBufAdd8BE(buf, location.dex_pc);
    187 }
    188 
    189 }  // namespace JDWP
    190 
    191 }  // namespace art
    192