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
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 {
diff --git a/src/leb128.h b/src/leb128.h
index 51df6c9..bc5dd1a 100644
--- a/src/leb128.h
+++ b/src/leb128.h
@@ -35,6 +35,14 @@
   return (uint32_t)result;
 }
 
+// Reads an unsigned LEB128 + 1 value. updating the given pointer to point
+// just past the end of the read value. This function tolerates
+// non-zero high-order bits in the fifth encoded byte.
+// It is possible for this function to return -1.
+static inline int32_t DecodeUnsignedLeb128P1(const byte** data) {
+  return DecodeUnsignedLeb128(data) - 1;
+}
+
 // Reads a signed LEB128 value, updating the given pointer to point
 // just past the end of the read value. This function tolerates
 // non-zero high-order bits in the fifth encoded byte.
diff --git a/src/object.h b/src/object.h
index 0bbb4f4..c8ec9cb 100644
--- a/src/object.h
+++ b/src/object.h
@@ -5,7 +5,6 @@
 
 #include "constants.h"
 #include "casts.h"
-#include "dex_file.h"
 #include "globals.h"
 #include "heap.h"
 #include "logging.h"