1872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
2872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Copyright (C) 2008 The Android Open Source Project
3872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes *
4872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
5872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * you may not use this file except in compliance with the License.
6872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * You may obtain a copy of the License at
7872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes *
8872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
9872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes *
10872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Unless required by applicable law or agreed to in writing, software
11872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
12872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * See the License for the specific language governing permissions and
14872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * limitations under the License.
15872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
16872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
17872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Implementation of an expandable byte buffer.  Designed for serializing
18872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * primitive values, e.g. JDWP replies.
19872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
20872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
21872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes#include "jdwp/jdwp_expand_buf.h"
22872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
23872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes#include <stdlib.h>
24872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes#include <string.h>
25872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
2607ed66b5ae659c452cbe1ab20c3dbf1d6f546461Elliott Hughes#include "base/logging.h"
2707ed66b5ae659c452cbe1ab20c3dbf1d6f546461Elliott Hughes#include "jdwp/jdwp.h"
2807ed66b5ae659c452cbe1ab20c3dbf1d6f546461Elliott Hughes#include "jdwp/jdwp_bits.h"
2907ed66b5ae659c452cbe1ab20c3dbf1d6f546461Elliott Hughes
30872d4ec7225444d9400d30f9027247deb91012fdElliott Hughesnamespace art {
31872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
32872d4ec7225444d9400d30f9027247deb91012fdElliott Hughesnamespace JDWP {
33872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
34872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
35872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Data structure used to track buffer use.
36872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
37872d4ec7225444d9400d30f9027247deb91012fdElliott Hughesstruct ExpandBuf {
38872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  uint8_t*     storage;
39872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  int     curLen;
40872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  int     maxLen;
41872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes};
42872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
43872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes#define kInitialStorage 64
44872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
45872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
46872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Allocate a JdwpBuf and some initial storage.
47872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
48872d4ec7225444d9400d30f9027247deb91012fdElliott HughesExpandBuf* expandBufAlloc() {
49a21039c3ae2b20e44ceb2735251c04d0aac89afdElliott Hughes  ExpandBuf* newBuf = new ExpandBuf;
50a21039c3ae2b20e44ceb2735251c04d0aac89afdElliott Hughes  newBuf->storage = reinterpret_cast<uint8_t*>(malloc(kInitialStorage));
51872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  newBuf->curLen = 0;
52872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  newBuf->maxLen = kInitialStorage;
53872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  return newBuf;
54872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes}
55872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
56872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
57872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Free a JdwpBuf and associated storage.
58872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
59872d4ec7225444d9400d30f9027247deb91012fdElliott Hughesvoid expandBufFree(ExpandBuf* pBuf) {
60872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  if (pBuf == NULL) {
61872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes    return;
62872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  }
63872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
64872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  free(pBuf->storage);
65a21039c3ae2b20e44ceb2735251c04d0aac89afdElliott Hughes  delete pBuf;
66872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes}
67872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
68872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
69872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Get a pointer to the start of the buffer.
70872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
71872d4ec7225444d9400d30f9027247deb91012fdElliott Hughesuint8_t* expandBufGetBuffer(ExpandBuf* pBuf) {
72872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  return pBuf->storage;
73872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes}
74872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
75872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
76872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Get the amount of data currently in the buffer.
77872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
78872d4ec7225444d9400d30f9027247deb91012fdElliott Hughessize_t expandBufGetLength(ExpandBuf* pBuf) {
79872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  return pBuf->curLen;
80872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes}
81872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
82872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
83872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Ensure that the buffer has enough space to hold incoming data.  If it
84872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * doesn't, resize the buffer.
85872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
86872d4ec7225444d9400d30f9027247deb91012fdElliott Hughesstatic void ensureSpace(ExpandBuf* pBuf, int newCount) {
87872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  if (pBuf->curLen + newCount <= pBuf->maxLen) {
88872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes    return;
89872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  }
90872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
91872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  while (pBuf->curLen + newCount > pBuf->maxLen) {
92872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes    pBuf->maxLen *= 2;
93872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  }
94872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
95a21039c3ae2b20e44ceb2735251c04d0aac89afdElliott Hughes  uint8_t* newPtr = reinterpret_cast<uint8_t*>(realloc(pBuf->storage, pBuf->maxLen));
96872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  if (newPtr == NULL) {
976c1c69eea21cce39dd043d89368a684d250c9abeElliott Hughes    LOG(FATAL) << "realloc(" << pBuf->maxLen << ") failed";
98872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  }
99872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
100872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  pBuf->storage = newPtr;
101872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes}
102872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
103872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
104872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Allocate some space in the buffer.
105872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
106872d4ec7225444d9400d30f9027247deb91012fdElliott Hughesuint8_t* expandBufAddSpace(ExpandBuf* pBuf, int gapSize) {
107872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  uint8_t* gapStart;
108872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
109872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  ensureSpace(pBuf, gapSize);
110872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  gapStart = pBuf->storage + pBuf->curLen;
111872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  /* do we want to garbage-fill the gap for debugging? */
112872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  pBuf->curLen += gapSize;
113872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
114872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  return gapStart;
115872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes}
116872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
117872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
118872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Append a byte.
119872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
120872d4ec7225444d9400d30f9027247deb91012fdElliott Hughesvoid expandBufAdd1(ExpandBuf* pBuf, uint8_t val) {
121872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  ensureSpace(pBuf, sizeof(val));
122872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  *(pBuf->storage + pBuf->curLen) = val;
123872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  pBuf->curLen++;
124872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes}
125872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
126872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
127872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Append two big-endian bytes.
128872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
129872d4ec7225444d9400d30f9027247deb91012fdElliott Hughesvoid expandBufAdd2BE(ExpandBuf* pBuf, uint16_t val) {
130872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  ensureSpace(pBuf, sizeof(val));
131f7c3b6625d710a8700325eea447f65e9f963b7f2Elliott Hughes  Set2BE(pBuf->storage + pBuf->curLen, val);
132872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  pBuf->curLen += sizeof(val);
133872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes}
134872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
135872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
136872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Append four big-endian bytes.
137872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
138872d4ec7225444d9400d30f9027247deb91012fdElliott Hughesvoid expandBufAdd4BE(ExpandBuf* pBuf, uint32_t val) {
139872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  ensureSpace(pBuf, sizeof(val));
140f7c3b6625d710a8700325eea447f65e9f963b7f2Elliott Hughes  Set4BE(pBuf->storage + pBuf->curLen, val);
141872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  pBuf->curLen += sizeof(val);
142872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes}
143872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
144872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
145872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Append eight big-endian bytes.
146872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
147872d4ec7225444d9400d30f9027247deb91012fdElliott Hughesvoid expandBufAdd8BE(ExpandBuf* pBuf, uint64_t val) {
148872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  ensureSpace(pBuf, sizeof(val));
149f7c3b6625d710a8700325eea447f65e9f963b7f2Elliott Hughes  Set8BE(pBuf->storage + pBuf->curLen, val);
150872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  pBuf->curLen += sizeof(val);
151872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes}
152872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
153a215526d5c789cbef0f81a1f9aba22541a841ccaElliott Hughesstatic void SetUtf8String(uint8_t* buf, const char* str, size_t strLen) {
15421f32d704a21bcd67d7b87b149b6314ff92946cbElliott Hughes  Set4BE(buf, strLen);
15521f32d704a21bcd67d7b87b149b6314ff92946cbElliott Hughes  memcpy(buf + sizeof(uint32_t), str, strLen);
15621f32d704a21bcd67d7b87b149b6314ff92946cbElliott Hughes}
15721f32d704a21bcd67d7b87b149b6314ff92946cbElliott Hughes
158872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes/*
159872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Add a UTF8 string as a 4-byte length followed by a non-NULL-terminated
160872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * string.
161872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes *
162872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * Because these strings are coming out of the VM, it's safe to assume that
163872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * they can be null-terminated (either they don't have null bytes or they
164872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes * have stored null bytes in a multi-byte encoding).
165872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes */
1664740cdff25875c530649a670b15e8ac52bfd7252Elliott Hughesvoid expandBufAddUtf8String(ExpandBuf* pBuf, const char* s) {
1674740cdff25875c530649a670b15e8ac52bfd7252Elliott Hughes  int strLen = strlen(s);
168872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  ensureSpace(pBuf, sizeof(uint32_t) + strLen);
1694740cdff25875c530649a670b15e8ac52bfd7252Elliott Hughes  SetUtf8String(pBuf->storage + pBuf->curLen, s, strLen);
170872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes  pBuf->curLen += sizeof(uint32_t) + strLen;
171872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes}
172872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
1734740cdff25875c530649a670b15e8ac52bfd7252Elliott Hughesvoid expandBufAddUtf8String(ExpandBuf* pBuf, const std::string& s) {
1744740cdff25875c530649a670b15e8ac52bfd7252Elliott Hughes  ensureSpace(pBuf, sizeof(uint32_t) + s.size());
1754740cdff25875c530649a670b15e8ac52bfd7252Elliott Hughes  SetUtf8String(pBuf->storage + pBuf->curLen, s.data(), s.size());
1764740cdff25875c530649a670b15e8ac52bfd7252Elliott Hughes  pBuf->curLen += sizeof(uint32_t) + s.size();
1774740cdff25875c530649a670b15e8ac52bfd7252Elliott Hughes}
1784740cdff25875c530649a670b15e8ac52bfd7252Elliott Hughes
1796e9d22c78c1016e70f8c2a9e6bc66c94ec36f728Elliott Hughesvoid expandBufAddLocation(ExpandBuf* buf, const JdwpLocation& location) {
1806e9d22c78c1016e70f8c2a9e6bc66c94ec36f728Elliott Hughes  expandBufAdd1(buf, location.type_tag);
1816e9d22c78c1016e70f8c2a9e6bc66c94ec36f728Elliott Hughes  expandBufAddObjectId(buf, location.class_id);
1826e9d22c78c1016e70f8c2a9e6bc66c94ec36f728Elliott Hughes  expandBufAddMethodId(buf, location.method_id);
1836e9d22c78c1016e70f8c2a9e6bc66c94ec36f728Elliott Hughes  expandBufAdd8BE(buf, location.dex_pc);
1846e9d22c78c1016e70f8c2a9e6bc66c94ec36f728Elliott Hughes}
1856e9d22c78c1016e70f8c2a9e6bc66c94ec36f728Elliott Hughes
186872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes}  // namespace JDWP
187872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes
188872d4ec7225444d9400d30f9027247deb91012fdElliott Hughes}  // namespace art
189