2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * Handling of method debug info in a .dex file.
21 #include "DexDebugInfo.h"
29 * Decode the arguments in a method signature, which looks something
30 * like "(ID[Ljava/lang/String;)V".
32 * Returns the type signature letter for the next argument, or ')' if
33 * there are no more args. Advances "pSig" to point to the character
34 * after the one returned.
36 static char decodeSignature(const char** pSig)
38 const char* sig = *pSig;
51 /* array; advance past array type */
62 return *sig; /* don't advance further */
69 * returns the length of a type string, given the start of the
70 * type string. Used for the case where the debug info format
71 * references types that are inside a method type signature.
73 static int typeLength(const char *type) {
74 // Assumes any leading '(' has already been gobbled
75 const char *end = type;
76 decodeSignature(&end);
81 * Reads a string index as encoded for the debug info format,
82 * returning a string pointer or NULL as appropriate.
84 static const char* readStringIdx(const DexFile* pDexFile,
86 u4 stringIdx = readUnsignedLeb128(pStream);
88 // Remember, encoded string indicies have 1 added to them.
92 return dexStringById(pDexFile, stringIdx - 1);
97 * Reads a type index as encoded for the debug info format, returning
98 * a string pointer for its descriptor or NULL as appropriate.
100 static const char* readTypeIdx(const DexFile* pDexFile,
101 const u1** pStream) {
102 u4 typeIdx = readUnsignedLeb128(pStream);
104 // Remember, encoded type indicies have 1 added to them.
108 return dexStringByTypeIdx(pDexFile, typeIdx - 1);
114 const char *descriptor;
115 const char *signature;
120 static void emitLocalCbIfLive(void *cnxt, int reg, u4 endAddress,
121 LocalInfo *localInReg, DexDebugNewLocalCb localCb)
123 if (localCb != NULL && localInReg[reg].live) {
124 localCb(cnxt, reg, localInReg[reg].startAddress, endAddress,
125 localInReg[reg].name,
126 localInReg[reg].descriptor,
127 localInReg[reg].signature == NULL
128 ? "" : localInReg[reg].signature );
132 static void invalidStream(const char* classDescriptor, const DexProto* proto) {
134 char* methodDescriptor = dexProtoCopyMethodDescriptor(proto);
135 ALOGE("Invalid debug info stream. class %s; proto %s",
136 classDescriptor, methodDescriptor);
137 free(methodDescriptor);
141 static void dexDecodeDebugInfo0(
142 const DexFile* pDexFile,
143 const DexCode* pCode,
144 const char* classDescriptor,
147 DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb,
150 LocalInfo* localInReg)
152 DexProto proto = { pDexFile, protoIdx };
153 u4 insnsSize = pCode->insnsSize;
154 u4 line = readUnsignedLeb128(&stream);
155 u4 parametersSize = readUnsignedLeb128(&stream);
156 u2 argReg = pCode->registersSize - pCode->insSize;
159 if ((accessFlags & ACC_STATIC) == 0) {
161 * The code is an instance method, which means that there is
162 * an initial this parameter. Also, the proto list should
163 * contain exactly one fewer argument word than the insSize
166 assert(pCode->insSize == (dexProtoComputeArgsSize(&proto) + 1));
167 localInReg[argReg].name = "this";
168 localInReg[argReg].descriptor = classDescriptor;
169 localInReg[argReg].startAddress = 0;
170 localInReg[argReg].live = true;
173 assert(pCode->insSize == dexProtoComputeArgsSize(&proto));
176 DexParameterIterator iterator;
177 dexParameterIteratorInit(&iterator, &proto);
179 while (parametersSize-- != 0) {
180 const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
184 if ((argReg >= pCode->registersSize) || (descriptor == NULL)) {
185 invalidStream(classDescriptor, &proto);
189 name = readStringIdx(pDexFile, &stream);
192 switch (descriptor[0]) {
203 localInReg[reg].name = name;
204 localInReg[reg].descriptor = descriptor;
205 localInReg[reg].signature = NULL;
206 localInReg[reg].startAddress = address;
207 localInReg[reg].live = true;
212 u1 opcode = *stream++;
216 case DBG_END_SEQUENCE:
220 address += readUnsignedLeb128(&stream);
223 case DBG_ADVANCE_LINE:
224 line += readSignedLeb128(&stream);
227 case DBG_START_LOCAL:
228 case DBG_START_LOCAL_EXTENDED:
229 reg = readUnsignedLeb128(&stream);
230 if (reg > pCode->registersSize) {
231 invalidStream(classDescriptor, &proto);
235 // Emit what was previously there, if anything
236 emitLocalCbIfLive(cnxt, reg, address,
237 localInReg, localCb);
239 localInReg[reg].name = readStringIdx(pDexFile, &stream);
240 localInReg[reg].descriptor = readTypeIdx(pDexFile, &stream);
241 if (opcode == DBG_START_LOCAL_EXTENDED) {
242 localInReg[reg].signature
243 = readStringIdx(pDexFile, &stream);
245 localInReg[reg].signature = NULL;
247 localInReg[reg].startAddress = address;
248 localInReg[reg].live = true;
252 reg = readUnsignedLeb128(&stream);
253 if (reg > pCode->registersSize) {
254 invalidStream(classDescriptor, &proto);
258 emitLocalCbIfLive (cnxt, reg, address, localInReg, localCb);
259 localInReg[reg].live = false;
262 case DBG_RESTART_LOCAL:
263 reg = readUnsignedLeb128(&stream);
264 if (reg > pCode->registersSize) {
265 invalidStream(classDescriptor, &proto);
269 if (localInReg[reg].name == NULL
270 || localInReg[reg].descriptor == NULL) {
271 invalidStream(classDescriptor, &proto);
276 * If the register is live, the "restart" is superfluous,
277 * and we don't want to mess with the existing start address.
279 if (!localInReg[reg].live) {
280 localInReg[reg].startAddress = address;
281 localInReg[reg].live = true;
285 case DBG_SET_PROLOGUE_END:
286 case DBG_SET_EPILOGUE_BEGIN:
291 int adjopcode = opcode - DBG_FIRST_SPECIAL;
293 address += adjopcode / DBG_LINE_RANGE;
294 line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
298 done = posCb(cnxt, address, line);
311 // TODO optimize localCb == NULL case
312 void dexDecodeDebugInfo(
313 const DexFile* pDexFile,
314 const DexCode* pCode,
315 const char* classDescriptor,
318 DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb,
321 const u1* stream = dexGetDebugInfoStream(pDexFile, pCode);
322 LocalInfo localInReg[pCode->registersSize];
324 memset(localInReg, 0, sizeof(LocalInfo) * pCode->registersSize);
326 if (stream != NULL) {
327 dexDecodeDebugInfo0(pDexFile, pCode, classDescriptor, protoIdx, accessFlags,
328 posCb, localCb, cnxt, stream, localInReg);
331 for (int reg = 0; reg < pCode->registersSize; reg++) {
332 emitLocalCbIfLive(cnxt, reg, pCode->insnsSize, localInReg, localCb);