1 /* 2 * Copyright (C) 2011 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 /* 18 * Handling of method debug info in a .dex file. 19 */ 20 21 #include "DexDebugInfo.h" 22 #include "DexProto.h" 23 #include "Leb128.h" 24 25 #include <stdlib.h> 26 #include <string.h> 27 28 /* 29 * Decode the arguments in a method signature, which looks something 30 * like "(ID[Ljava/lang/String;)V". 31 * 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. 35 */ 36 static char decodeSignature(const char** pSig) 37 { 38 const char* sig = *pSig; 39 40 if (*sig == '(') 41 sig++; 42 43 if (*sig == 'L') { 44 /* object ref */ 45 while (*++sig != ';') 46 ; 47 *pSig = sig+1; 48 return 'L'; 49 } 50 if (*sig == '[') { 51 /* array; advance past array type */ 52 while (*++sig == '[') 53 ; 54 if (*sig == 'L') { 55 while (*++sig != ';') 56 ; 57 } 58 *pSig = sig+1; 59 return '['; 60 } 61 if (*sig == '\0') 62 return *sig; /* don't advance further */ 63 64 *pSig = sig+1; 65 return *sig; 66 } 67 68 /* 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. 72 */ 73 static int typeLength(const char *type) { 74 // Assumes any leading '(' has already been gobbled 75 const char *end = type; 76 decodeSignature(&end); 77 return end - type; 78 } 79 80 /* 81 * Reads a string index as encoded for the debug info format, 82 * returning a string pointer or NULL as appropriate. 83 */ 84 static const char* readStringIdx(const DexFile* pDexFile, 85 const u1** pStream) { 86 u4 stringIdx = readUnsignedLeb128(pStream); 87 88 // Remember, encoded string indicies have 1 added to them. 89 if (stringIdx == 0) { 90 return NULL; 91 } else { 92 return dexStringById(pDexFile, stringIdx - 1); 93 } 94 } 95 96 /* 97 * Reads a type index as encoded for the debug info format, returning 98 * a string pointer for its descriptor or NULL as appropriate. 99 */ 100 static const char* readTypeIdx(const DexFile* pDexFile, 101 const u1** pStream) { 102 u4 typeIdx = readUnsignedLeb128(pStream); 103 104 // Remember, encoded type indicies have 1 added to them. 105 if (typeIdx == 0) { 106 return NULL; 107 } else { 108 return dexStringByTypeIdx(pDexFile, typeIdx - 1); 109 } 110 } 111 112 struct LocalInfo { 113 const char *name; 114 const char *descriptor; 115 const char *signature; 116 u2 startAddress; 117 bool live; 118 }; 119 120 static void emitLocalCbIfLive(void *cnxt, int reg, u4 endAddress, 121 LocalInfo *localInReg, DexDebugNewLocalCb localCb) 122 { 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 ); 129 } 130 } 131 132 static void invalidStream(const char* classDescriptor, const DexProto* proto) { 133 IF_ALOGE() { 134 char* methodDescriptor = dexProtoCopyMethodDescriptor(proto); 135 ALOGE("Invalid debug info stream. class %s; proto %s", 136 classDescriptor, methodDescriptor); 137 free(methodDescriptor); 138 } 139 } 140 141 static void dexDecodeDebugInfo0( 142 const DexFile* pDexFile, 143 const DexCode* pCode, 144 const char* classDescriptor, 145 u4 protoIdx, 146 u4 accessFlags, 147 DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb, 148 void* cnxt, 149 const u1* stream, 150 LocalInfo* localInReg) 151 { 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; 157 u4 address = 0; 158 159 if ((accessFlags & ACC_STATIC) == 0) { 160 /* 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 164 * indicates. 165 */ 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; 171 argReg++; 172 } else { 173 assert(pCode->insSize == dexProtoComputeArgsSize(&proto)); 174 } 175 176 DexParameterIterator iterator; 177 dexParameterIteratorInit(&iterator, &proto); 178 179 while (parametersSize-- != 0) { 180 const char* descriptor = dexParameterIteratorNextDescriptor(&iterator); 181 const char *name; 182 int reg; 183 184 if ((argReg >= pCode->registersSize) || (descriptor == NULL)) { 185 invalidStream(classDescriptor, &proto); 186 return; 187 } 188 189 name = readStringIdx(pDexFile, &stream); 190 reg = argReg; 191 192 switch (descriptor[0]) { 193 case 'D': 194 case 'J': 195 argReg += 2; 196 break; 197 default: 198 argReg += 1; 199 break; 200 } 201 202 if (name != NULL) { 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; 208 } 209 } 210 211 for (;;) { 212 u1 opcode = *stream++; 213 u2 reg; 214 215 switch (opcode) { 216 case DBG_END_SEQUENCE: 217 return; 218 219 case DBG_ADVANCE_PC: 220 address += readUnsignedLeb128(&stream); 221 break; 222 223 case DBG_ADVANCE_LINE: 224 line += readSignedLeb128(&stream); 225 break; 226 227 case DBG_START_LOCAL: 228 case DBG_START_LOCAL_EXTENDED: 229 reg = readUnsignedLeb128(&stream); 230 if (reg > pCode->registersSize) { 231 invalidStream(classDescriptor, &proto); 232 return; 233 } 234 235 // Emit what was previously there, if anything 236 emitLocalCbIfLive(cnxt, reg, address, 237 localInReg, localCb); 238 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); 244 } else { 245 localInReg[reg].signature = NULL; 246 } 247 localInReg[reg].startAddress = address; 248 localInReg[reg].live = true; 249 break; 250 251 case DBG_END_LOCAL: 252 reg = readUnsignedLeb128(&stream); 253 if (reg > pCode->registersSize) { 254 invalidStream(classDescriptor, &proto); 255 return; 256 } 257 258 emitLocalCbIfLive (cnxt, reg, address, localInReg, localCb); 259 localInReg[reg].live = false; 260 break; 261 262 case DBG_RESTART_LOCAL: 263 reg = readUnsignedLeb128(&stream); 264 if (reg > pCode->registersSize) { 265 invalidStream(classDescriptor, &proto); 266 return; 267 } 268 269 if (localInReg[reg].name == NULL 270 || localInReg[reg].descriptor == NULL) { 271 invalidStream(classDescriptor, &proto); 272 return; 273 } 274 275 /* 276 * If the register is live, the "restart" is superfluous, 277 * and we don't want to mess with the existing start address. 278 */ 279 if (!localInReg[reg].live) { 280 localInReg[reg].startAddress = address; 281 localInReg[reg].live = true; 282 } 283 break; 284 285 case DBG_SET_PROLOGUE_END: 286 case DBG_SET_EPILOGUE_BEGIN: 287 case DBG_SET_FILE: 288 break; 289 290 default: { 291 int adjopcode = opcode - DBG_FIRST_SPECIAL; 292 293 address += adjopcode / DBG_LINE_RANGE; 294 line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE); 295 296 if (posCb != NULL) { 297 int done; 298 done = posCb(cnxt, address, line); 299 300 if (done) { 301 // early exit 302 return; 303 } 304 } 305 break; 306 } 307 } 308 } 309 } 310 311 // TODO optimize localCb == NULL case 312 void dexDecodeDebugInfo( 313 const DexFile* pDexFile, 314 const DexCode* pCode, 315 const char* classDescriptor, 316 u4 protoIdx, 317 u4 accessFlags, 318 DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb, 319 void* cnxt) 320 { 321 const u1* stream = dexGetDebugInfoStream(pDexFile, pCode); 322 LocalInfo localInReg[pCode->registersSize]; 323 324 memset(localInReg, 0, sizeof(LocalInfo) * pCode->registersSize); 325 326 if (stream != NULL) { 327 dexDecodeDebugInfo0(pDexFile, pCode, classDescriptor, protoIdx, accessFlags, 328 posCb, localCb, cnxt, stream, localInReg); 329 } 330 331 for (int reg = 0; reg < pCode->registersSize; reg++) { 332 emitLocalCbIfLive(cnxt, reg, pCode->insnsSize, localInReg, localCb); 333 } 334 } 335