jdwp_expand_buf.cc revision 2cebb24bfc3247d3e9be138a3350106737455918
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
30namespace art {
31
32namespace JDWP {
33
34/*
35 * Data structure used to track buffer use.
36 */
37struct 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 */
48ExpandBuf* 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 */
59void 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 */
71uint8_t* expandBufGetBuffer(ExpandBuf* pBuf) {
72  return pBuf->storage;
73}
74
75/*
76 * Get the amount of data currently in the buffer.
77 */
78size_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 */
86static 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 */
106uint8_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 */
120void 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 */
129void 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 */
138void 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 */
147void 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
153static 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 */
166void 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
173void 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
179void 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