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 "base/logging.h" 27 #include "jdwp/jdwp.h" 28 #include "jdwp/jdwp_bits.h" 29 30 namespace art { 31 32 namespace JDWP { 33 34 /* 35 * Data structure used to track buffer use. 36 */ 37 struct ExpandBuf { 38 uint8_t* storage; 39 int curLen; 40 int maxLen; 41 }; 42 43 #define kInitialStorage 64 44 45 /* 46 * Allocate a JdwpBuf and some initial storage. 47 */ 48 ExpandBuf* expandBufAlloc() { 49 ExpandBuf* newBuf = new ExpandBuf; 50 newBuf->storage = reinterpret_cast<uint8_t*>(malloc(kInitialStorage)); 51 newBuf->curLen = 0; 52 newBuf->maxLen = kInitialStorage; 53 return newBuf; 54 } 55 56 /* 57 * Free a JdwpBuf and associated storage. 58 */ 59 void expandBufFree(ExpandBuf* pBuf) { 60 if (pBuf == NULL) { 61 return; 62 } 63 64 free(pBuf->storage); 65 delete pBuf; 66 } 67 68 /* 69 * Get a pointer to the start of the buffer. 70 */ 71 uint8_t* expandBufGetBuffer(ExpandBuf* pBuf) { 72 return pBuf->storage; 73 } 74 75 /* 76 * Get the amount of data currently in the buffer. 77 */ 78 size_t expandBufGetLength(ExpandBuf* pBuf) { 79 return pBuf->curLen; 80 } 81 82 /* 83 * Ensure that the buffer has enough space to hold incoming data. If it 84 * doesn't, resize the buffer. 85 */ 86 static void ensureSpace(ExpandBuf* pBuf, int newCount) { 87 if (pBuf->curLen + newCount <= pBuf->maxLen) { 88 return; 89 } 90 91 while (pBuf->curLen + newCount > pBuf->maxLen) { 92 pBuf->maxLen *= 2; 93 } 94 95 uint8_t* newPtr = reinterpret_cast<uint8_t*>(realloc(pBuf->storage, pBuf->maxLen)); 96 if (newPtr == NULL) { 97 LOG(FATAL) << "realloc(" << pBuf->maxLen << ") failed"; 98 } 99 100 pBuf->storage = newPtr; 101 } 102 103 /* 104 * Allocate some space in the buffer. 105 */ 106 uint8_t* expandBufAddSpace(ExpandBuf* pBuf, int gapSize) { 107 uint8_t* gapStart; 108 109 ensureSpace(pBuf, gapSize); 110 gapStart = pBuf->storage + pBuf->curLen; 111 /* do we want to garbage-fill the gap for debugging? */ 112 pBuf->curLen += gapSize; 113 114 return gapStart; 115 } 116 117 /* 118 * Append a byte. 119 */ 120 void expandBufAdd1(ExpandBuf* pBuf, uint8_t val) { 121 ensureSpace(pBuf, sizeof(val)); 122 *(pBuf->storage + pBuf->curLen) = val; 123 pBuf->curLen++; 124 } 125 126 /* 127 * Append two big-endian bytes. 128 */ 129 void expandBufAdd2BE(ExpandBuf* pBuf, uint16_t val) { 130 ensureSpace(pBuf, sizeof(val)); 131 Set2BE(pBuf->storage + pBuf->curLen, val); 132 pBuf->curLen += sizeof(val); 133 } 134 135 /* 136 * Append four big-endian bytes. 137 */ 138 void expandBufAdd4BE(ExpandBuf* pBuf, uint32_t val) { 139 ensureSpace(pBuf, sizeof(val)); 140 Set4BE(pBuf->storage + pBuf->curLen, val); 141 pBuf->curLen += sizeof(val); 142 } 143 144 /* 145 * Append eight big-endian bytes. 146 */ 147 void expandBufAdd8BE(ExpandBuf* pBuf, uint64_t val) { 148 ensureSpace(pBuf, sizeof(val)); 149 Set8BE(pBuf->storage + pBuf->curLen, val); 150 pBuf->curLen += sizeof(val); 151 } 152 153 static void SetUtf8String(uint8_t* buf, const char* str, size_t strLen) { 154 Set4BE(buf, strLen); 155 memcpy(buf + sizeof(uint32_t), str, strLen); 156 } 157 158 /* 159 * Add a UTF8 string as a 4-byte length followed by a non-NULL-terminated 160 * string. 161 * 162 * Because these strings are coming out of the VM, it's safe to assume that 163 * they can be null-terminated (either they don't have null bytes or they 164 * have stored null bytes in a multi-byte encoding). 165 */ 166 void expandBufAddUtf8String(ExpandBuf* pBuf, const char* s) { 167 int strLen = strlen(s); 168 ensureSpace(pBuf, sizeof(uint32_t) + strLen); 169 SetUtf8String(pBuf->storage + pBuf->curLen, s, strLen); 170 pBuf->curLen += sizeof(uint32_t) + strLen; 171 } 172 173 void expandBufAddUtf8String(ExpandBuf* pBuf, const std::string& s) { 174 ensureSpace(pBuf, sizeof(uint32_t) + s.size()); 175 SetUtf8String(pBuf->storage + pBuf->curLen, s.data(), s.size()); 176 pBuf->curLen += sizeof(uint32_t) + s.size(); 177 } 178 179 void expandBufAddLocation(ExpandBuf* buf, const JdwpLocation& location) { 180 expandBufAdd1(buf, location.type_tag); 181 expandBufAddObjectId(buf, location.class_id); 182 expandBufAddMethodId(buf, location.method_id); 183 expandBufAdd8BE(buf, location.dex_pc); 184 } 185 186 } // namespace JDWP 187 188 } // namespace art 189