Initial implementation for adding StackTraceElement support.
Line # information added.
Change-Id: I5a68383e74a19fa28d82a33bb1db649ef570f3b0
diff --git a/src/dex_file.h b/src/dex_file.h
index b3f9bdd..ee5cc45 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -17,6 +17,8 @@
namespace art {
union JValue;
+class String;
+class Method;
// TODO: move all of the macro functionality into the DexCache class.
class DexFile {
@@ -484,6 +486,10 @@
// return the UTF-8 encoded string with the specified string_id index
const char* dexStringById(uint32_t idx, int32_t* unicode_length) const {
+ if (idx == kDexNoIndex) {
+ *unicode_length = 0;
+ return NULL;
+ }
const StringId& string_id = GetStringId(idx);
return GetStringData(string_id, unicode_length);
}
@@ -493,6 +499,8 @@
return dexStringById(idx, &unicode_length);
}
+ String* dexArtStringById(uint32_t idx) const;
+
// Get the descriptor string associated with a given type index.
const char* dexStringByTypeIdx(uint32_t idx, int32_t* unicode_length) const {
const TypeId& type_id = GetTypeId(idx);
@@ -504,6 +512,11 @@
return dexStringById(type_id.descriptor_idx_);
}
+ String* dexArtStringByTypeIdx(uint32_t idx) const {
+ const TypeId& type_id = GetTypeId(idx);
+ return dexArtStringById(type_id.descriptor_idx_);
+ }
+
// TODO: encoded_field is actually a stream of bytes
void dexReadClassDataField(const byte** encoded_field,
DexFile::Field* field,
@@ -605,6 +618,124 @@
return -1;
}
+ // Get the pointer to the start of the debugging data
+ const byte* dexGetDebugInfoStream(const CodeItem* code_item) const {
+ if (code_item->debug_info_off_ == 0) {
+ return NULL;
+ } else {
+ return base_ + code_item->debug_info_off_;
+ }
+ }
+
+ // Callback for "new position table entry".
+ // Returning true causes the decoder to stop early.
+ typedef bool (*DexDebugNewPositionCb)(void *cnxt, uint32_t address, uint32_t line_num);
+
+ // Callback for "new locals table entry". "signature" is an empty string
+ // if no signature is available for an entry.
+ typedef void (*DexDebugNewLocalCb)(void *cnxt, uint16_t reg,
+ uint32_t startAddress,
+ uint32_t endAddress,
+ const String* name,
+ const String* descriptor,
+ const String* signature);
+
+ static bool LineNumForPcCb(void *cnxt, uint32_t address, uint32_t line_num) {
+ LineNumFromPcContext *context = (LineNumFromPcContext *)cnxt;
+
+ // We know that this callback will be called in
+ // ascending address order, so keep going until we find
+ // a match or we've just gone past it.
+ if (address > context->address_) {
+ // The line number from the previous positions callback
+ // wil be the final result.
+ return true;
+ } else {
+ context->line_num_ = line_num;
+ return address == context->address_;
+ }
+ }
+
+
+ // Debug info opcodes and constants
+ enum {
+ DBG_END_SEQUENCE = 0x00,
+ DBG_ADVANCE_PC = 0x01,
+ DBG_ADVANCE_LINE = 0x02,
+ DBG_START_LOCAL = 0x03,
+ DBG_START_LOCAL_EXTENDED = 0x04,
+ DBG_END_LOCAL = 0x05,
+ DBG_RESTART_LOCAL = 0x06,
+ DBG_SET_PROLOGUE_END = 0x07,
+ DBG_SET_EPILOGUE_BEGIN = 0x08,
+ DBG_SET_FILE = 0x09,
+ DBG_FIRST_SPECIAL = 0x0a,
+ DBG_LINE_BASE = -4,
+ DBG_LINE_RANGE = 15,
+ };
+
+ struct LocalInfo {
+ LocalInfo() : name_(NULL), descriptor_(NULL), signature_(NULL), start_address_(0), is_live_(false) {}
+
+ // E.g., list
+ const String* name_;
+
+ // E.g., Ljava/util/LinkedList;
+ const String* descriptor_;
+
+ // E.g., java.util.LinkedList<java.lang.Integer>
+ const String* signature_;
+
+ // PC location where the local is first defined.
+ uint16_t start_address_;
+
+ // Is the local defined and live.
+ bool is_live_;
+ };
+
+ struct LineNumFromPcContext {
+ LineNumFromPcContext(uint32_t address, uint32_t line_num) :
+ address_(address), line_num_(line_num) {}
+ uint32_t address_;
+ uint32_t line_num_;
+ };
+
+ void InvokeLocalCbIfLive(void *cnxt, int reg, uint32_t end_address,
+ LocalInfo *local_in_reg, DexDebugNewLocalCb local_cb) const {
+ if (local_cb != NULL && local_in_reg[reg].is_live_) {
+ local_cb(cnxt, reg, local_in_reg[reg].start_address_, end_address,
+ local_in_reg[reg].name_, local_in_reg[reg].descriptor_,
+ local_in_reg[reg].signature_);
+ }
+ }
+
+ // Determine the source file line number based on the program counter.
+ // "pc" is an offset, in 16-bit units, from the start of the method's code.
+ //
+ // Returns -1 if no match was found (possibly because the source files were
+ // compiled without "-g", so no line number information is present).
+ // Returns -2 for native methods (as expected in exception traces).
+ //
+ // This is used by runtime; therefore use art::Method not art::DexFile::Method.
+ int32_t GetLineNumFromPC(const art::Method* method, uint32_t rel_pc) const;
+
+ void dexDecodeDebugInfo0(const CodeItem* code_item, const art::Method* method,
+ DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb,
+ void* cnxt, const byte* stream, LocalInfo* local_in_reg) const;
+
+ void dexDecodeDebugInfo(const CodeItem* code_item, const art::Method *method,
+ DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb,
+ void* cnxt) const {
+ const byte* stream = dexGetDebugInfoStream(code_item);
+ LocalInfo local_in_reg[code_item->registers_size_];
+
+ if (stream != NULL) {
+ dexDecodeDebugInfo0(code_item, method, posCb, local_cb, cnxt, stream, local_in_reg);
+ }
+ for (int reg = 0; reg < code_item->registers_size_; reg++) {
+ InvokeLocalCbIfLive(cnxt, reg, code_item->insns_size_, local_in_reg, local_cb);
+ }
+ }
// TODO: const reference
uint32_t dexGetIndexForClassDef(const ClassDef* class_def) const {