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  */
expandBufAlloc()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  */
expandBufFree(ExpandBuf * pBuf)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  */
expandBufGetBuffer(ExpandBuf * pBuf)72 uint8_t* expandBufGetBuffer(ExpandBuf* pBuf) {
73   return pBuf->storage;
74 }
75 
76 /*
77  * Get the amount of data currently in the buffer.
78  */
expandBufGetLength(ExpandBuf * pBuf)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  */
ensureSpace(ExpandBuf * pBuf,int newCount)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  */
expandBufAddSpace(ExpandBuf * pBuf,int gapSize)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  */
expandBufAdd1(ExpandBuf * pBuf,uint8_t val)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  */
expandBufAdd2BE(ExpandBuf * pBuf,uint16_t val)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  */
expandBufAdd4BE(ExpandBuf * pBuf,uint32_t val)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  */
expandBufAdd8BE(ExpandBuf * pBuf,uint64_t val)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 
SetUtf8String(uint8_t * buf,const char * str,size_t strLen)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  */
expandBufAddUtf8String(ExpandBuf * pBuf,const char * s)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 
expandBufAddUtf8String(ExpandBuf * pBuf,const std::string & s)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 
expandBufAddLocation(ExpandBuf * buf,const JdwpLocation & location)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