Home | History | Annotate | Download | only in libdex
      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