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  */
expandBufAlloc()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  */
expandBufFree(ExpandBuf * pBuf)59 void expandBufFree(ExpandBuf* pBuf) {
60   if (pBuf == nullptr) {
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  */
expandBufGetBuffer(ExpandBuf * pBuf)71 uint8_t* expandBufGetBuffer(ExpandBuf* pBuf) {
72   return pBuf->storage;
73 }
74 
75 /*
76  * Get the amount of data currently in the buffer.
77  */
expandBufGetLength(ExpandBuf * pBuf)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  */
ensureSpace(ExpandBuf * pBuf,int newCount)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 == nullptr) {
97     LOG(FATAL) << "realloc(" << pBuf->maxLen << ") failed";
98   }
99 
100   pBuf->storage = newPtr;
101 }
102 
103 /*
104  * Allocate some space in the buffer.
105  */
expandBufAddSpace(ExpandBuf * pBuf,int gapSize)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  */
expandBufAdd1(ExpandBuf * pBuf,uint8_t val)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  */
expandBufAdd2BE(ExpandBuf * pBuf,uint16_t val)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  */
expandBufAdd4BE(ExpandBuf * pBuf,uint32_t val)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  */
expandBufAdd8BE(ExpandBuf * pBuf,uint64_t val)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 
SetUtf8String(uint8_t * buf,const char * str,size_t strLen)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-nullptr-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  */
expandBufAddUtf8String(ExpandBuf * pBuf,const char * s)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 
expandBufAddUtf8String(ExpandBuf * pBuf,const std::string & s)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 
expandBufAddLocation(ExpandBuf * buf,const JdwpLocation & location)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