/* * Reads a signed LEB128 value, updating the given pointer to point * just past the end of the read value and also indicating whether the * value was syntactically valid. The only syntactically *invalid* * values are ones that are five bytes long where the final byte has * any but the low-order four bits set. Additionally, if the limit is * passed as non-NULL and bytes would need to be read past the limit, * then the read is considered invalid. */ int readAndVerifySignedLeb128(const u1** pStream, const u1* limit, bool* okay) { const u1* ptr = *pStream; int result = readSignedLeb128(pStream); if (((limit != NULL) && (*pStream > limit)) || (((*pStream - ptr) == 5) && (ptr[4] > 0x0f))) { *okay = false; } return result; }
/* Initialize a DexCatchIterator with a direct pointer to encoded handlers. */ DEX_INLINE void dexCatchIteratorInitToPointer(DexCatchIterator* pIterator, const u1* pEncodedData) { s4 count = readSignedLeb128(&pEncodedData); if (count <= 0) { pIterator->catchesAll = true; count = -count; } else { pIterator->catchesAll = false; } pIterator->pEncodedData = pEncodedData; pIterator->countRemaining = count; }
// TODO optimize localCb == NULL case void dexDecodeDebugInfo( const DexFile* pDexFile, const DexCode* pCode, const char* classDescriptor, u4 protoIdx, u4 accessFlags, DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb, void* cnxt) { const u1 *stream = dexGetDebugInfoStream(pDexFile, pCode); u4 line; u4 parametersSize; u4 address = 0; LocalInfo localInReg[pCode->registersSize]; u4 insnsSize = pCode->insnsSize; DexProto proto = { pDexFile, protoIdx }; memset(localInReg, 0, sizeof(LocalInfo) * pCode->registersSize); if (stream == NULL) { goto end; } line = readUnsignedLeb128(&stream); parametersSize = readUnsignedLeb128(&stream); u2 argReg = pCode->registersSize - pCode->insSize; if ((accessFlags & ACC_STATIC) == 0) { /* * The code is an instance method, which means that there is * an initial this parameter. Also, the proto list should * contain exactly one fewer argument word than the insSize * indicates. */ assert(pCode->insSize == (dexProtoComputeArgsSize(&proto) + 1)); localInReg[argReg].name = "this"; localInReg[argReg].descriptor = classDescriptor; localInReg[argReg].startAddress = 0; localInReg[argReg].live = true; argReg++; } else { assert(pCode->insSize == dexProtoComputeArgsSize(&proto)); } DexParameterIterator iterator; dexParameterIteratorInit(&iterator, &proto); while (parametersSize-- != 0) { const char* descriptor = dexParameterIteratorNextDescriptor(&iterator); const char *name; int reg; if ((argReg >= pCode->registersSize) || (descriptor == NULL)) { goto invalid_stream; } name = readStringIdx(pDexFile, &stream); reg = argReg; switch (descriptor[0]) { case 'D': case 'J': argReg += 2; break; default: argReg += 1; break; } if (name != NULL) { localInReg[reg].name = name; localInReg[reg].descriptor = descriptor; localInReg[reg].signature = NULL; localInReg[reg].startAddress = address; localInReg[reg].live = true; } } for (;;) { u1 opcode = *stream++; u2 reg; switch (opcode) { case DBG_END_SEQUENCE: goto end; case DBG_ADVANCE_PC: address += readUnsignedLeb128(&stream); break; case DBG_ADVANCE_LINE: line += readSignedLeb128(&stream); break; case DBG_START_LOCAL: case DBG_START_LOCAL_EXTENDED: reg = readUnsignedLeb128(&stream); if (reg > pCode->registersSize) goto invalid_stream; // Emit what was previously there, if anything emitLocalCbIfLive (cnxt, reg, address, localInReg, localCb); localInReg[reg].name = readStringIdx(pDexFile, &stream); localInReg[reg].descriptor = readTypeIdx(pDexFile, &stream); if (opcode == DBG_START_LOCAL_EXTENDED) { localInReg[reg].signature = readStringIdx(pDexFile, &stream); } else { localInReg[reg].signature = NULL; } localInReg[reg].startAddress = address; localInReg[reg].live = true; break; case DBG_END_LOCAL: reg = readUnsignedLeb128(&stream); if (reg > pCode->registersSize) goto invalid_stream; emitLocalCbIfLive (cnxt, reg, address, localInReg, localCb); localInReg[reg].live = false; break; case DBG_RESTART_LOCAL: reg = readUnsignedLeb128(&stream); if (reg > pCode->registersSize) goto invalid_stream; if (localInReg[reg].name == NULL || localInReg[reg].descriptor == NULL) { goto invalid_stream; } /* * If the register is live, the "restart" is superfluous, * and we don't want to mess with the existing start address. */ if (!localInReg[reg].live) { localInReg[reg].startAddress = address; localInReg[reg].live = true; } break; case DBG_SET_PROLOGUE_END: case DBG_SET_EPILOGUE_BEGIN: case DBG_SET_FILE: break; default: { int adjopcode = opcode - DBG_FIRST_SPECIAL; address += adjopcode / DBG_LINE_RANGE; line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE); if (posCb != NULL) { int done; done = posCb(cnxt, address, line); if (done) { // early exit goto end; } } break; } } } end: { int reg; for (reg = 0; reg < pCode->registersSize; reg++) { emitLocalCbIfLive (cnxt, reg, insnsSize, localInReg, localCb); } } return; invalid_stream: IF_LOGE() { char* methodDescriptor = dexProtoCopyMethodDescriptor(&proto); LOGE("Invalid debug info stream. class %s; proto %s", classDescriptor, methodDescriptor); free(methodDescriptor); } }