Initial implementation for adding StackTraceElement support.
Line # information added.
Change-Id: I5a68383e74a19fa28d82a33bb1db649ef570f3b0
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 14c62f1..b575bcf 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -534,4 +534,158 @@
return static_cast<ValueType>(type);
}
+String* DexFile::dexArtStringById(uint32_t idx) const {
+ return String::AllocFromModifiedUtf8(dexStringById(idx));
+}
+
+int32_t DexFile::GetLineNumFromPC(const art::Method* method, uint32_t rel_pc) const {
+ const CodeItem* code_item = GetCodeItem(method->code_off_);
+ DCHECK(code_item != NULL);
+
+ // A method with no line number info should return -1
+ LineNumFromPcContext context(rel_pc, -1);
+ dexDecodeDebugInfo(code_item, method, LineNumForPcCb, NULL, &context);
+ return context.line_num_;
+}
+
+void DexFile::dexDecodeDebugInfo0(const CodeItem* code_item, const art::Method* method,
+ DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb,
+ void* cnxt, const byte* stream, LocalInfo* local_in_reg) const {
+ uint32_t line = DecodeUnsignedLeb128(&stream);
+ uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
+ uint16_t arg_reg = code_item->registers_size_ - code_item->ins_size_;
+ uint32_t address = 0;
+
+ if (!method->IsStatic()) {
+ local_in_reg[arg_reg].name_ = String::AllocFromModifiedUtf8("this");
+ local_in_reg[arg_reg].descriptor_ = method->GetDeclaringClass()->GetDescriptor();
+ local_in_reg[arg_reg].signature_ = NULL;
+ local_in_reg[arg_reg].start_address_ = 0;
+ local_in_reg[arg_reg].is_live_ = true;
+ arg_reg++;
+ }
+
+ ParameterIterator *it = GetParameterIterator(GetProtoId(method->proto_idx_));
+ for (uint32_t i = 0; i < parameters_size && it->HasNext(); ++i, it->Next()) {
+ if (arg_reg >= code_item->registers_size_) {
+ LOG(FATAL) << "invalid stream";
+ return;
+ }
+
+ String* descriptor = String::AllocFromModifiedUtf8(it->GetDescriptor());
+ String* name = dexArtStringById(DecodeUnsignedLeb128P1(&stream));
+
+ local_in_reg[arg_reg].name_ = name;
+ local_in_reg[arg_reg].descriptor_ = descriptor;
+ local_in_reg[arg_reg].signature_ = NULL;
+ local_in_reg[arg_reg].start_address_ = address;
+ local_in_reg[arg_reg].is_live_ = true;
+ switch (descriptor->CharAt(0)) {
+ case 'D':
+ case 'J':
+ arg_reg += 2;
+ break;
+ default:
+ arg_reg += 1;
+ break;
+ }
+ }
+
+ if (it->HasNext()) {
+ LOG(FATAL) << "invalid stream";
+ return;
+ }
+
+ for (;;) {
+ uint8_t opcode = *stream++;
+ uint8_t adjopcode = opcode - DBG_FIRST_SPECIAL;
+ uint16_t reg;
+
+
+ switch (opcode) {
+ case DBG_END_SEQUENCE:
+ return;
+
+ case DBG_ADVANCE_PC:
+ address += DecodeUnsignedLeb128(&stream);
+ break;
+
+ case DBG_ADVANCE_LINE:
+ line += DecodeUnsignedLeb128(&stream);
+ break;
+
+ case DBG_START_LOCAL:
+ case DBG_START_LOCAL_EXTENDED:
+ reg = DecodeUnsignedLeb128(&stream);
+ if (reg > code_item->registers_size_) {
+ LOG(FATAL) << "invalid stream";
+ return;
+ }
+
+ // Emit what was previously there, if anything
+ InvokeLocalCbIfLive(cnxt, reg, address, local_in_reg, local_cb);
+
+ local_in_reg[reg].name_ = dexArtStringById(DecodeUnsignedLeb128P1(&stream));
+ local_in_reg[reg].descriptor_ = dexArtStringByTypeIdx(DecodeUnsignedLeb128P1(&stream));
+ if (opcode == DBG_START_LOCAL_EXTENDED) {
+ local_in_reg[reg].signature_ = dexArtStringById(DecodeUnsignedLeb128P1(&stream));
+ } else {
+ local_in_reg[reg].signature_ = NULL;
+ }
+ local_in_reg[reg].start_address_ = address;
+ local_in_reg[reg].is_live_ = true;
+ break;
+
+ case DBG_END_LOCAL:
+ reg = DecodeUnsignedLeb128(&stream);
+ if (reg > code_item->registers_size_) {
+ LOG(FATAL) << "invalid stream";
+ return;
+ }
+
+ InvokeLocalCbIfLive(cnxt, reg, address, local_in_reg, local_cb);
+ local_in_reg[reg].is_live_ = false;
+ break;
+
+ case DBG_RESTART_LOCAL:
+ reg = DecodeUnsignedLeb128(&stream);
+ if (reg > code_item->registers_size_) {
+ LOG(FATAL) << "invalid stream";
+ return;
+ }
+
+ if (local_in_reg[reg].name_ == NULL
+ || local_in_reg[reg].descriptor_ == NULL) {
+ LOG(FATAL) << "invalid stream";
+ return;
+ }
+
+ // If the register is live, the "restart" is superfluous,
+ // and we don't want to mess with the existing start address.
+ if (!local_in_reg[reg].is_live_) {
+ local_in_reg[reg].start_address_ = address;
+ local_in_reg[reg].is_live_ = true;
+ }
+ break;
+
+ case DBG_SET_PROLOGUE_END:
+ case DBG_SET_EPILOGUE_BEGIN:
+ case DBG_SET_FILE:
+ break;
+
+ default:
+ address += adjopcode / DBG_LINE_RANGE;
+ line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
+
+ if (posCb != NULL) {
+ if (posCb(cnxt, address, line)) {
+ // early exit
+ return;
+ }
+ }
+ break;
+ }
+ }
+}
+
} // namespace art