diff options
author | 2015-12-10 13:15:00 +0000 | |
---|---|---|
committer | 2015-12-15 15:11:50 +0000 | |
commit | b06e28e5b9fbabe3e69b18f31bf353eaff5d0c1f (patch) | |
tree | 18ff419c6a3b80ecff3125f13b72a8851e848ab0 | |
parent | f71b3ade9c99ce2fec2f5049ce9c5968721e1b81 (diff) |
Refactor DexFile::DecodeDebugInfo.
Split the method into two - one for locals and one for positions.
All uses of the method request only one of the two and it makes the
code slightly cleaner. The position variant requires fewer parameters.
Expose additional line table information which was previously ignored
by the decode method (prologue, epilogue, source file).
Change-Id: Idf8ba98fa58ea0d2103932b5cc0af81365885107
-rw-r--r-- | compiler/elf_writer_debug.cc | 170 | ||||
-rw-r--r-- | dexdump/dexdump.cc | 17 | ||||
-rw-r--r-- | dexlist/dexlist.cc | 10 | ||||
-rw-r--r-- | runtime/debugger.cc | 43 | ||||
-rw-r--r-- | runtime/dex_file.cc | 280 | ||||
-rw-r--r-- | runtime/dex_file.h | 89 | ||||
-rw-r--r-- | runtime/jdwp/jdwp_expand_buf.cc | 2 |
7 files changed, 320 insertions, 291 deletions
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc index c5c0f1308b..01533eb1fd 100644 --- a/compiler/elf_writer_debug.cc +++ b/compiler/elf_writer_debug.cc @@ -301,40 +301,30 @@ namespace { uint32_t high_pc_ = 0; }; - struct LocalVariable { - uint16_t vreg; - uint32_t dex_pc_low; - uint32_t dex_pc_high; - const char* name; - const char* type; - const char* sig; - }; + typedef std::vector<DexFile::LocalInfo> LocalInfos; - struct DebugInfoCallback { - static void NewLocal(void* ctx, - uint16_t vreg, - uint32_t start, - uint32_t end, - const char* name, - const char* type, - const char* sig) { - auto* context = static_cast<DebugInfoCallback*>(ctx); - if (name != nullptr && type != nullptr) { - context->local_variables_.push_back({vreg, start, end, name, type, sig}); - } - } - std::vector<LocalVariable> local_variables_; - }; + void LocalInfoCallback(void* ctx, const DexFile::LocalInfo& entry) { + static_cast<LocalInfos*>(ctx)->push_back(entry); + } + + typedef std::vector<DexFile::PositionInfo> PositionInfos; + + bool PositionInfoCallback(void* ctx, const DexFile::PositionInfo& entry) { + static_cast<PositionInfos*>(ctx)->push_back(entry); + return false; + } std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) { std::vector<const char*> names; - const uint8_t* stream = mi->dex_file_->GetDebugInfoStream(mi->code_item_); - if (stream != nullptr) { - DecodeUnsignedLeb128(&stream); // line. - uint32_t parameters_size = DecodeUnsignedLeb128(&stream); - for (uint32_t i = 0; i < parameters_size; ++i) { - uint32_t id = DecodeUnsignedLeb128P1(&stream); - names.push_back(mi->dex_file_->StringDataByIdx(id)); + if (mi->code_item_ != nullptr) { + const uint8_t* stream = mi->dex_file_->GetDebugInfoStream(mi->code_item_); + if (stream != nullptr) { + DecodeUnsignedLeb128(&stream); // line. + uint32_t parameters_size = DecodeUnsignedLeb128(&stream); + for (uint32_t i = 0; i < parameters_size; ++i) { + uint32_t id = DecodeUnsignedLeb128P1(&stream); + names.push_back(mi->dex_file_->StringDataByIdx(id)); + } } } return names; @@ -453,6 +443,7 @@ class DebugInfoWriter { const char* last_dex_class_desc = nullptr; for (auto mi : compilation_unit.methods_) { const DexFile* dex = mi->dex_file_; + const DexFile::CodeItem* dex_code = mi->code_item_; const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index_); const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method); const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto); @@ -472,19 +463,6 @@ class DebugInfoWriter { last_dex_class_desc = dex_class_desc; } - // Collect information about local variables and parameters. - DebugInfoCallback debug_info_callback; - std::vector<const char*> param_names; - if (mi->code_item_ != nullptr) { - dex->DecodeDebugInfo(mi->code_item_, - is_static, - mi->dex_method_index_, - nullptr, - DebugInfoCallback::NewLocal, - &debug_info_callback); - param_names = GetParamNames(mi); - } - int start_depth = info_.Depth(); info_.StartTag(DW_TAG_subprogram); WriteName(dex->GetMethodName(dex_method)); @@ -493,50 +471,70 @@ class DebugInfoWriter { uint8_t frame_base[] = { DW_OP_call_frame_cfa }; info_.WriteExprLoc(DW_AT_frame_base, &frame_base, sizeof(frame_base)); WriteLazyType(dex->GetReturnTypeDescriptor(dex_proto)); - uint32_t vreg = mi->code_item_ == nullptr ? 0 : - mi->code_item_->registers_size_ - mi->code_item_->ins_size_; + + // Write parameters. DecodeDebugLocalInfo returns them as well, but it does not + // guarantee order or uniqueness so it is safer to iterate over them manually. + // DecodeDebugLocalInfo might not also be available if there is no debug info. + std::vector<const char*> param_names = GetParamNames(mi); + uint32_t arg_reg = 0; if (!is_static) { info_.StartTag(DW_TAG_formal_parameter); WriteName("this"); info_.WriteFlag(DW_AT_artificial, true); WriteLazyType(dex_class_desc); - const bool is64bitValue = false; - WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc_); - vreg++; + if (dex_code != nullptr) { + // Write the stack location of the parameter. + const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg; + const bool is64bitValue = false; + WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc_); + } + arg_reg++; info_.EndTag(); } if (dex_params != nullptr) { for (uint32_t i = 0; i < dex_params->Size(); ++i) { info_.StartTag(DW_TAG_formal_parameter); // Parameter names may not be always available. - if (i < param_names.size() && param_names[i] != nullptr) { + if (i < param_names.size()) { WriteName(param_names[i]); } // Write the type. const char* type_desc = dex->StringByTypeIdx(dex_params->GetTypeItem(i).type_idx_); WriteLazyType(type_desc); - // Write the stack location of the parameter. const bool is64bitValue = type_desc[0] == 'D' || type_desc[0] == 'J'; - WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc_); - vreg += is64bitValue ? 2 : 1; + if (dex_code != nullptr) { + // Write the stack location of the parameter. + const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg; + WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc_); + } + arg_reg += is64bitValue ? 2 : 1; info_.EndTag(); } - if (mi->code_item_ != nullptr) { - CHECK_EQ(vreg, mi->code_item_->registers_size_); + if (dex_code != nullptr) { + DCHECK_EQ(arg_reg, dex_code->ins_size_); } } - for (const LocalVariable& var : debug_info_callback.local_variables_) { - const uint32_t first_arg = mi->code_item_->registers_size_ - mi->code_item_->ins_size_; - if (var.vreg < first_arg) { - info_.StartTag(DW_TAG_variable); - WriteName(var.name); - WriteLazyType(var.type); - bool is64bitValue = var.type[0] == 'D' || var.type[0] == 'J'; - WriteRegLocation(mi, var.vreg, is64bitValue, compilation_unit.low_pc_, - var.dex_pc_low, var.dex_pc_high); - info_.EndTag(); + + // Write local variables. + LocalInfos local_infos; + if (dex->DecodeDebugLocalInfo(dex_code, + is_static, + mi->dex_method_index_, + LocalInfoCallback, + &local_infos)) { + for (const DexFile::LocalInfo& var : local_infos) { + if (var.reg_ < dex_code->registers_size_ - dex_code->ins_size_) { + info_.StartTag(DW_TAG_variable); + WriteName(var.name_); + WriteLazyType(var.descriptor_); + bool is64bitValue = var.descriptor_[0] == 'D' || var.descriptor_[0] == 'J'; + WriteRegLocation(mi, var.reg_, is64bitValue, compilation_unit.low_pc_, + var.start_address_, var.end_address_); + info_.EndTag(); + } } } + info_.EndTag(); CHECK_EQ(info_.Depth(), start_depth); // Balanced start/end. } @@ -707,8 +705,7 @@ class DebugInfoWriter { // to be enclosed in the right set of namespaces. Therefore we // just define all types lazily at the end of compilation unit. void WriteLazyType(const char* type_descriptor) { - DCHECK(type_descriptor != nullptr); - if (type_descriptor[0] != 'V') { + if (type_descriptor != nullptr && type_descriptor[0] != 'V') { lazy_types_.emplace(type_descriptor, info_.size()); info_.WriteRef4(DW_AT_type, 0); } @@ -723,7 +720,9 @@ class DebugInfoWriter { private: void WriteName(const char* name) { - info_.WriteStrp(DW_AT_name, owner_->WriteString(name)); + if (name != nullptr) { + info_.WriteStrp(DW_AT_name, owner_->WriteString(name)); + } } // Helper which writes DWARF expression referencing a register. @@ -975,29 +974,15 @@ class DebugLineWriter { continue; } - // Create mapping table from dex to source line. - struct DebugInfoCallbacks { - static bool NewPosition(void* ctx, uint32_t address, uint32_t line) { - auto* context = static_cast<DebugInfoCallbacks*>(ctx); - context->dex2line_.push_back({address, static_cast<int32_t>(line)}); - return false; - } - DefaultSrcMap dex2line_; - } debug_info_callbacks; - Elf_Addr method_address = text_address + mi->low_pc_; + PositionInfos position_infos; const DexFile* dex = mi->dex_file_; - if (mi->code_item_ != nullptr) { - dex->DecodeDebugInfo(mi->code_item_, - (mi->access_flags_ & kAccStatic) != 0, - mi->dex_method_index_, - DebugInfoCallbacks::NewPosition, - nullptr, - &debug_info_callbacks); + if (!dex->DecodeDebugPositionInfo(mi->code_item_, PositionInfoCallback, &position_infos)) { + continue; } - if (debug_info_callbacks.dex2line_.empty()) { + if (position_infos.empty()) { continue; } @@ -1052,20 +1037,23 @@ class DebugLineWriter { opcodes.SetFile(file_index); // Generate mapping opcodes from PC to Java lines. - const DefaultSrcMap& dex2line_map = debug_info_callbacks.dex2line_; - if (file_index != 0 && !dex2line_map.empty()) { + if (file_index != 0) { bool first = true; for (SrcMapElem pc2dex : src_mapping_table) { uint32_t pc = pc2dex.from_; int dex_pc = pc2dex.to_; - auto dex2line = dex2line_map.Find(static_cast<uint32_t>(dex_pc)); - if (dex2line.first) { - int line = dex2line.second; + // Find mapping with address with is greater than our dex pc; then go back one step. + auto ub = std::upper_bound(position_infos.begin(), position_infos.end(), dex_pc, + [](uint32_t address, const DexFile::PositionInfo& entry) { + return address < entry.address_; + }); + if (ub != position_infos.begin()) { + int line = (--ub)->line_; if (first) { first = false; if (pc > 0) { // Assume that any preceding code is prologue. - int first_line = dex2line_map.front().to_; + int first_line = position_infos.front().line_; // Prologue is not a sensible place for a breakpoint. opcodes.NegateStmt(); opcodes.AddRow(method_address, first_line); diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc index 52e6c023fe..81fb33cab2 100644 --- a/dexdump/dexdump.cc +++ b/dexdump/dexdump.cc @@ -472,18 +472,19 @@ static void dumpCatches(const DexFile* pDexFile, const DexFile::CodeItem* pCode) /* * Callback for dumping each positions table entry. */ -static bool dumpPositionsCb(void* /*context*/, u4 address, u4 lineNum) { - fprintf(gOutFile, " 0x%04x line=%d\n", address, lineNum); +static bool dumpPositionsCb(void* /*context*/, const DexFile::PositionInfo& entry) { + fprintf(gOutFile, " 0x%04x line=%d\n", entry.address_, entry.line_); return false; } /* * Callback for dumping locals table entry. */ -static void dumpLocalsCb(void* /*context*/, u2 slot, u4 startAddress, u4 endAddress, - const char* name, const char* descriptor, const char* signature) { +static void dumpLocalsCb(void* /*context*/, const DexFile::LocalInfo& entry) { + const char* signature = entry.signature_ != nullptr ? entry.signature_ : ""; fprintf(gOutFile, " 0x%04x - 0x%04x reg=%d %s %s %s\n", - startAddress, endAddress, slot, name, descriptor, signature); + entry.start_address_, entry.end_address_, entry.reg_, + entry.name_, entry.descriptor_, signature); } /* @@ -901,11 +902,9 @@ static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags, // Positions and locals table in the debug info. bool is_static = (flags & kAccStatic) != 0; fprintf(gOutFile, " positions : \n"); - pDexFile->DecodeDebugInfo( - pCode, is_static, idx, dumpPositionsCb, nullptr, nullptr); + pDexFile->DecodeDebugPositionInfo(pCode, dumpPositionsCb, nullptr); fprintf(gOutFile, " locals : \n"); - pDexFile->DecodeDebugInfo( - pCode, is_static, idx, nullptr, dumpLocalsCb, nullptr); + pDexFile->DecodeDebugLocalInfo(pCode, is_static, idx, dumpLocalsCb, nullptr); } /* diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc index 1d0f75ea92..d20c16919a 100644 --- a/dexlist/dexlist.cc +++ b/dexlist/dexlist.cc @@ -80,10 +80,10 @@ static char* descriptorToDot(const char* str) { * first line in the method, which *should* correspond to the first * entry from the table. (Could also use "min" here.) */ -static bool positionsCb(void* context, u4 /*address*/, u4 lineNum) { +static bool positionsCb(void* context, const DexFile::PositionInfo& entry) { int* pFirstLine = reinterpret_cast<int *>(context); if (*pFirstLine == -1) { - *pFirstLine = lineNum; + *pFirstLine = entry.line_; } return 0; } @@ -92,7 +92,7 @@ static bool positionsCb(void* context, u4 /*address*/, u4 lineNum) { * Dumps a method. */ static void dumpMethod(const DexFile* pDexFile, - const char* fileName, u4 idx, u4 flags, + const char* fileName, u4 idx, u4 flags ATTRIBUTE_UNUSED, const DexFile::CodeItem* pCode, u4 codeOffset) { // Abstract and native methods don't get listed. if (pCode == nullptr || codeOffset == 0) { @@ -121,9 +121,7 @@ static void dumpMethod(const DexFile* pDexFile, // Find the first line. int firstLine = -1; - bool is_static = (flags & kAccStatic) != 0; - pDexFile->DecodeDebugInfo( - pCode, is_static, idx, positionsCb, nullptr, &firstLine); + pDexFile->DecodeDebugPositionInfo(pCode, positionsCb, &firstLine); // Method signature. const Signature signature = pDexFile->GetMethodSignature(pMethodId); diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 51f57c3cf7..62c9d25574 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -1536,10 +1536,10 @@ void Dbg::OutputLineTable(JDWP::RefTypeId, JDWP::MethodId method_id, JDWP::Expan int numItems; JDWP::ExpandBuf* pReply; - static bool Callback(void* context, uint32_t address, uint32_t line_number) { + static bool Callback(void* context, const DexFile::PositionInfo& entry) { DebugCallbackContext* pContext = reinterpret_cast<DebugCallbackContext*>(context); - expandBufAdd8BE(pContext->pReply, address); - expandBufAdd4BE(pContext->pReply, line_number); + expandBufAdd8BE(pContext->pReply, entry.address_); + expandBufAdd4BE(pContext->pReply, entry.line_); pContext->numItems++; return false; } @@ -1569,8 +1569,7 @@ void Dbg::OutputLineTable(JDWP::RefTypeId, JDWP::MethodId method_id, JDWP::Expan context.pReply = pReply; if (code_item != nullptr) { - m->GetDexFile()->DecodeDebugInfo(code_item, m->IsStatic(), m->GetDexMethodIndex(), - DebugCallbackContext::Callback, nullptr, &context); + m->GetDexFile()->DecodeDebugPositionInfo(code_item, DebugCallbackContext::Callback, &context); } JDWP::Set4BE(expandBufGetBuffer(pReply) + numLinesOffset, context.numItems); @@ -1584,25 +1583,26 @@ void Dbg::OutputVariableTable(JDWP::RefTypeId, JDWP::MethodId method_id, bool wi size_t variable_count; bool with_generic; - static void Callback(void* context, uint16_t slot, uint32_t startAddress, uint32_t endAddress, - const char* name, const char* descriptor, const char* signature) + static void Callback(void* context, const DexFile::LocalInfo& entry) SHARED_REQUIRES(Locks::mutator_lock_) { DebugCallbackContext* pContext = reinterpret_cast<DebugCallbackContext*>(context); + uint16_t slot = entry.reg_; VLOG(jdwp) << StringPrintf(" %2zd: %d(%d) '%s' '%s' '%s' actual slot=%d mangled slot=%d", - pContext->variable_count, startAddress, endAddress - startAddress, - name, descriptor, signature, slot, + pContext->variable_count, entry.start_address_, + entry.end_address_ - entry.start_address_, + entry.name_, entry.descriptor_, entry.signature_, slot, MangleSlot(slot, pContext->method)); slot = MangleSlot(slot, pContext->method); - expandBufAdd8BE(pContext->pReply, startAddress); - expandBufAddUtf8String(pContext->pReply, name); - expandBufAddUtf8String(pContext->pReply, descriptor); + expandBufAdd8BE(pContext->pReply, entry.start_address_); + expandBufAddUtf8String(pContext->pReply, entry.name_); + expandBufAddUtf8String(pContext->pReply, entry.descriptor_); if (pContext->with_generic) { - expandBufAddUtf8String(pContext->pReply, signature); + expandBufAddUtf8String(pContext->pReply, entry.signature_); } - expandBufAdd4BE(pContext->pReply, endAddress - startAddress); + expandBufAdd4BE(pContext->pReply, entry.end_address_- entry.start_address_); expandBufAdd4BE(pContext->pReply, slot); ++pContext->variable_count; @@ -1627,8 +1627,8 @@ void Dbg::OutputVariableTable(JDWP::RefTypeId, JDWP::MethodId method_id, bool wi const DexFile::CodeItem* code_item = m->GetCodeItem(); if (code_item != nullptr) { - m->GetDexFile()->DecodeDebugInfo( - code_item, m->IsStatic(), m->GetDexMethodIndex(), nullptr, DebugCallbackContext::Callback, + m->GetDexFile()->DecodeDebugLocalInfo( + code_item, m->IsStatic(), m->GetDexMethodIndex(), DebugCallbackContext::Callback, &context); } @@ -3716,19 +3716,19 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId thread_id, JDWP::JdwpStepSize code_item_(code_item), last_pc_valid(false), last_pc(0) { } - static bool Callback(void* raw_context, uint32_t address, uint32_t line_number_cb) { + static bool Callback(void* raw_context, const DexFile::PositionInfo& entry) { DebugCallbackContext* context = reinterpret_cast<DebugCallbackContext*>(raw_context); - if (static_cast<int32_t>(line_number_cb) == context->line_number_) { + if (static_cast<int32_t>(entry.line_) == context->line_number_) { if (!context->last_pc_valid) { // Everything from this address until the next line change is ours. - context->last_pc = address; + context->last_pc = entry.address_; context->last_pc_valid = true; } // Otherwise, if we're already in a valid range for this line, // just keep going (shouldn't really happen)... } else if (context->last_pc_valid) { // and the line number is new // Add everything from the last entry up until here to the set - for (uint32_t dex_pc = context->last_pc; dex_pc < address; ++dex_pc) { + for (uint32_t dex_pc = context->last_pc; dex_pc < entry.address_; ++dex_pc) { context->single_step_control_->AddDexPc(dex_pc); } context->last_pc_valid = false; @@ -3769,8 +3769,7 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId thread_id, JDWP::JdwpStepSize if (m != nullptr && !m->IsNative()) { const DexFile::CodeItem* const code_item = m->GetCodeItem(); DebugCallbackContext context(single_step_control, line_number, code_item); - m->GetDexFile()->DecodeDebugInfo(code_item, m->IsStatic(), m->GetDexMethodIndex(), - DebugCallbackContext::Callback, nullptr, &context); + m->GetDexFile()->DecodeDebugPositionInfo(code_item, DebugCallbackContext::Callback, &context); } // Activate single-step in the thread. diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index 30d921afe6..e62aa04d00 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -767,8 +767,7 @@ int32_t DexFile::GetLineNumFromPC(ArtMethod* method, uint32_t rel_pc) const { // A method with no line number info should return -1 LineNumFromPcContext context(rel_pc, -1); - DecodeDebugInfo(code_item, method->IsStatic(), method->GetDexMethodIndex(), LineNumForPcCb, - nullptr, &context); + DecodeDebugPositionInfo(code_item, LineNumForPcCb, &context); return context.line_num_; } @@ -805,45 +804,48 @@ int32_t DexFile::FindCatchHandlerOffset(const CodeItem &code_item, uint32_t addr } } -void DexFile::DecodeDebugInfo0(const CodeItem* code_item, bool is_static, uint32_t method_idx, - DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb, - void* context, const uint8_t* 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; - bool need_locals = (local_cb != nullptr); +bool DexFile::DecodeDebugLocalInfo(const CodeItem* code_item, bool is_static, uint32_t method_idx, + DexDebugNewLocalCb local_cb, void* context) const { + DCHECK(local_cb != nullptr); + if (code_item == nullptr) { + return false; + } + const uint8_t* stream = GetDebugInfoStream(code_item); + if (stream == nullptr) { + return false; + } + std::vector<LocalInfo> local_in_reg(code_item->registers_size_); + uint16_t arg_reg = code_item->registers_size_ - code_item->ins_size_; if (!is_static) { - if (need_locals) { - const char* descriptor = GetMethodDeclaringClassDescriptor(GetMethodId(method_idx)); - local_in_reg[arg_reg].name_ = "this"; - local_in_reg[arg_reg].descriptor_ = descriptor; - local_in_reg[arg_reg].signature_ = nullptr; - local_in_reg[arg_reg].start_address_ = 0; - local_in_reg[arg_reg].is_live_ = true; - } + const char* descriptor = GetMethodDeclaringClassDescriptor(GetMethodId(method_idx)); + local_in_reg[arg_reg].name_ = "this"; + local_in_reg[arg_reg].descriptor_ = descriptor; + local_in_reg[arg_reg].signature_ = nullptr; + local_in_reg[arg_reg].start_address_ = 0; + local_in_reg[arg_reg].reg_ = arg_reg; + local_in_reg[arg_reg].is_live_ = true; arg_reg++; } DexFileParameterIterator it(*this, GetMethodPrototype(GetMethodId(method_idx))); - for (uint32_t i = 0; i < parameters_size && it.HasNext(); ++i, it.Next()) { + DecodeUnsignedLeb128(&stream); // Line. + uint32_t parameters_size = DecodeUnsignedLeb128(&stream); + uint32_t i; + for (i = 0; i < parameters_size && it.HasNext(); ++i, it.Next()) { if (arg_reg >= code_item->registers_size_) { LOG(ERROR) << "invalid stream - arg reg >= reg size (" << arg_reg << " >= " << code_item->registers_size_ << ") in " << GetLocation(); - return; + return false; } - uint32_t id = DecodeUnsignedLeb128P1(&stream); + uint32_t name_idx = DecodeUnsignedLeb128P1(&stream); const char* descriptor = it.GetDescriptor(); - if (need_locals && id != kDexNoIndex) { - const char* name = StringDataByIdx(id); - local_in_reg[arg_reg].name_ = name; - local_in_reg[arg_reg].descriptor_ = descriptor; - local_in_reg[arg_reg].signature_ = nullptr; - local_in_reg[arg_reg].start_address_ = address; - local_in_reg[arg_reg].is_live_ = true; - } + local_in_reg[arg_reg].name_ = StringDataByIdx(name_idx); + local_in_reg[arg_reg].descriptor_ = descriptor; + local_in_reg[arg_reg].signature_ = nullptr; + local_in_reg[arg_reg].start_address_ = 0; + local_in_reg[arg_reg].reg_ = arg_reg; + local_in_reg[arg_reg].is_live_ = true; switch (*descriptor) { case 'D': case 'J': @@ -854,152 +856,188 @@ void DexFile::DecodeDebugInfo0(const CodeItem* code_item, bool is_static, uint32 break; } } - - if (it.HasNext()) { + if (i != parameters_size || it.HasNext()) { LOG(ERROR) << "invalid stream - problem with parameter iterator in " << GetLocation() << " for method " << PrettyMethod(method_idx, *this); - return; + return false; } + uint32_t address = 0; for (;;) { uint8_t opcode = *stream++; - uint16_t reg; - uint32_t name_idx; - uint32_t descriptor_idx; - uint32_t signature_idx = 0; - switch (opcode) { case DBG_END_SEQUENCE: - return; - + // Emit all variables which are still alive at the end of the method. + for (uint16_t reg = 0; reg < code_item->registers_size_; reg++) { + if (local_in_reg[reg].is_live_) { + local_in_reg[reg].end_address_ = code_item->insns_size_in_code_units_; + local_cb(context, local_in_reg[reg]); + } + } + return true; case DBG_ADVANCE_PC: address += DecodeUnsignedLeb128(&stream); break; - case DBG_ADVANCE_LINE: - line += DecodeSignedLeb128(&stream); + DecodeSignedLeb128(&stream); // Line. break; - case DBG_START_LOCAL: - case DBG_START_LOCAL_EXTENDED: - reg = DecodeUnsignedLeb128(&stream); - if (reg > code_item->registers_size_) { - LOG(ERROR) << "invalid stream - reg > reg size (" << reg << " > " + case DBG_START_LOCAL_EXTENDED: { + uint16_t reg = DecodeUnsignedLeb128(&stream); + if (reg >= code_item->registers_size_) { + LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= " << code_item->registers_size_ << ") in " << GetLocation(); - return; + return false; } - name_idx = DecodeUnsignedLeb128P1(&stream); - descriptor_idx = DecodeUnsignedLeb128P1(&stream); + uint32_t name_idx = DecodeUnsignedLeb128P1(&stream); + uint32_t descriptor_idx = DecodeUnsignedLeb128P1(&stream); + uint32_t signature_idx = kDexNoIndex; if (opcode == DBG_START_LOCAL_EXTENDED) { signature_idx = DecodeUnsignedLeb128P1(&stream); } // Emit what was previously there, if anything - if (need_locals) { - InvokeLocalCbIfLive(context, reg, address, local_in_reg, local_cb); - - local_in_reg[reg].name_ = StringDataByIdx(name_idx); - local_in_reg[reg].descriptor_ = StringByTypeIdx(descriptor_idx); - local_in_reg[reg].signature_ = - (opcode == DBG_START_LOCAL_EXTENDED) ? StringDataByIdx(signature_idx) - : nullptr; - local_in_reg[reg].start_address_ = address; - local_in_reg[reg].is_live_ = true; + if (local_in_reg[reg].is_live_) { + local_in_reg[reg].end_address_ = address; + local_cb(context, local_in_reg[reg]); } - break; - case DBG_END_LOCAL: - reg = DecodeUnsignedLeb128(&stream); - if (reg > code_item->registers_size_) { - LOG(ERROR) << "invalid stream - reg > reg size (" << reg << " > " + local_in_reg[reg].name_ = StringDataByIdx(name_idx); + local_in_reg[reg].descriptor_ = StringByTypeIdx(descriptor_idx); + local_in_reg[reg].signature_ = StringDataByIdx(signature_idx); + local_in_reg[reg].start_address_ = address; + local_in_reg[reg].reg_ = reg; + local_in_reg[reg].is_live_ = true; + break; + } + case DBG_END_LOCAL: { + uint16_t reg = DecodeUnsignedLeb128(&stream); + if (reg >= code_item->registers_size_) { + LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= " << code_item->registers_size_ << ") in " << GetLocation(); - return; + return false; } - - if (need_locals) { - InvokeLocalCbIfLive(context, reg, address, local_in_reg, local_cb); - local_in_reg[reg].is_live_ = false; + if (!local_in_reg[reg].is_live_) { + LOG(ERROR) << "invalid stream - end without start in " << GetLocation(); + return false; } + local_in_reg[reg].end_address_ = address; + local_cb(context, local_in_reg[reg]); + local_in_reg[reg].is_live_ = false; break; - - case DBG_RESTART_LOCAL: - reg = DecodeUnsignedLeb128(&stream); - if (reg > code_item->registers_size_) { - LOG(ERROR) << "invalid stream - reg > reg size (" << reg << " > " + } + case DBG_RESTART_LOCAL: { + uint16_t reg = DecodeUnsignedLeb128(&stream); + if (reg >= code_item->registers_size_) { + LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= " << code_item->registers_size_ << ") in " << GetLocation(); - return; + return false; } - - if (need_locals) { - if (local_in_reg[reg].name_ == nullptr || local_in_reg[reg].descriptor_ == nullptr) { - LOG(ERROR) << "invalid stream - no name or descriptor in " << GetLocation(); - 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; - } + // 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: + break; case DBG_SET_FILE: + DecodeUnsignedLeb128P1(&stream); // name. break; - - default: { - int adjopcode = opcode - DBG_FIRST_SPECIAL; - - address += adjopcode / DBG_LINE_RANGE; - line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE); - - if (position_cb != nullptr) { - if (position_cb(context, address, line)) { - // early exit - return; - } - } + default: + address += (opcode - DBG_FIRST_SPECIAL) / DBG_LINE_RANGE; break; - } } } } -void DexFile::DecodeDebugInfo(const CodeItem* code_item, bool is_static, uint32_t method_idx, - DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb, - void* context) const { - DCHECK(code_item != nullptr); +bool DexFile::DecodeDebugPositionInfo(const CodeItem* code_item, DexDebugNewPositionCb position_cb, + void* context) const { + DCHECK(position_cb != nullptr); + if (code_item == nullptr) { + return false; + } const uint8_t* stream = GetDebugInfoStream(code_item); - std::unique_ptr<LocalInfo[]> local_in_reg(local_cb != nullptr ? - new LocalInfo[code_item->registers_size_] : - nullptr); - if (stream != nullptr) { - DecodeDebugInfo0(code_item, is_static, method_idx, position_cb, local_cb, context, stream, - &local_in_reg[0]); + if (stream == nullptr) { + return false; + } + + PositionInfo entry = PositionInfo(); + entry.line_ = DecodeUnsignedLeb128(&stream); + uint32_t parameters_size = DecodeUnsignedLeb128(&stream); + for (uint32_t i = 0; i < parameters_size; ++i) { + DecodeUnsignedLeb128P1(&stream); // Parameter name. } - for (int reg = 0; reg < code_item->registers_size_; reg++) { - InvokeLocalCbIfLive(context, reg, code_item->insns_size_in_code_units_, &local_in_reg[0], - local_cb); + + for (;;) { + uint8_t opcode = *stream++; + switch (opcode) { + case DBG_END_SEQUENCE: + return true; // end of stream. + case DBG_ADVANCE_PC: + entry.address_ += DecodeUnsignedLeb128(&stream); + break; + case DBG_ADVANCE_LINE: + entry.line_ += DecodeSignedLeb128(&stream); + break; + case DBG_START_LOCAL: + DecodeUnsignedLeb128(&stream); // reg. + DecodeUnsignedLeb128P1(&stream); // name. + DecodeUnsignedLeb128P1(&stream); // descriptor. + break; + case DBG_START_LOCAL_EXTENDED: + DecodeUnsignedLeb128(&stream); // reg. + DecodeUnsignedLeb128P1(&stream); // name. + DecodeUnsignedLeb128P1(&stream); // descriptor. + DecodeUnsignedLeb128P1(&stream); // signature. + break; + case DBG_END_LOCAL: + case DBG_RESTART_LOCAL: + DecodeUnsignedLeb128(&stream); // reg. + break; + case DBG_SET_PROLOGUE_END: + entry.prologue_end_ = true; + break; + case DBG_SET_EPILOGUE_BEGIN: + entry.epilogue_begin_ = true; + break; + case DBG_SET_FILE: { + uint32_t name_idx = DecodeUnsignedLeb128P1(&stream); + entry.source_file_ = StringDataByIdx(name_idx); + break; + } + default: { + int adjopcode = opcode - DBG_FIRST_SPECIAL; + entry.address_ += adjopcode / DBG_LINE_RANGE; + entry.line_ += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE); + if (position_cb(context, entry)) { + return true; // early exit. + } + entry.prologue_end_ = false; + entry.epilogue_begin_ = false; + break; + } + } } } -bool DexFile::LineNumForPcCb(void* raw_context, uint32_t address, uint32_t line_num) { +bool DexFile::LineNumForPcCb(void* raw_context, const PositionInfo& entry) { LineNumFromPcContext* context = reinterpret_cast<LineNumFromPcContext*>(raw_context); // 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_) { + if (entry.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_; + context->line_num_ = entry.line_; + return entry.address_ == context->address_; } } diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 1e44f509f1..a9f1e8da05 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -819,20 +819,50 @@ class DexFile { } } + struct PositionInfo { + PositionInfo() + : address_(0), + line_(0), + source_file_(nullptr), + prologue_end_(false), + epilogue_begin_(false) { + } + + uint32_t address_; // In 16-bit code units. + uint32_t line_; // Source code line number starting at 1. + const char* source_file_; // nullptr if the file from ClassDef still applies. + bool prologue_end_; + bool epilogue_begin_; + }; + // Callback for "new position table entry". // Returning true causes the decoder to stop early. - typedef bool (*DexDebugNewPositionCb)(void* context, uint32_t address, uint32_t line_num); + typedef bool (*DexDebugNewPositionCb)(void* context, const PositionInfo& entry); + + struct LocalInfo { + LocalInfo() + : name_(nullptr), + descriptor_(nullptr), + signature_(nullptr), + start_address_(0), + end_address_(0), + reg_(0), + is_live_(false) { + } - // Callback for "new locals table entry". "signature" is an empty string - // if no signature is available for an entry. - typedef void (*DexDebugNewLocalCb)(void* context, uint16_t reg, - uint32_t start_address, - uint32_t end_address, - const char* name, - const char* descriptor, - const char* signature); + const char* name_; // E.g., list. It can be nullptr if unknown. + const char* descriptor_; // E.g., Ljava/util/LinkedList; + const char* signature_; // E.g., java.util.LinkedList<java.lang.Integer> + uint32_t start_address_; // PC location where the local is first defined. + uint32_t end_address_; // PC location where the local is no longer defined. + uint16_t reg_; // Dex register which stores the values. + bool is_live_; // Is the local defined and live. + }; + + // Callback for "new locals table entry". + typedef void (*DexDebugNewLocalCb)(void* context, const LocalInfo& entry); - static bool LineNumForPcCb(void* context, uint32_t address, uint32_t line_num); + static bool LineNumForPcCb(void* context, const PositionInfo& entry); const AnnotationsDirectoryItem* GetAnnotationsDirectory(const ClassDef& class_def) const { if (class_def.annotations_off_ == 0) { @@ -1044,21 +1074,6 @@ class DexFile { DBG_LINE_RANGE = 15, }; - struct LocalInfo { - LocalInfo() - : name_(nullptr), descriptor_(nullptr), signature_(nullptr), start_address_(0), - is_live_(false) {} - - const char* name_; // E.g., list - const char* descriptor_; // E.g., Ljava/util/LinkedList; - const char* signature_; // E.g., java.util.LinkedList<java.lang.Integer> - uint16_t start_address_; // PC location where the local is first defined. - bool is_live_; // Is the local defined and live. - - private: - DISALLOW_COPY_AND_ASSIGN(LocalInfo); - }; - struct LineNumFromPcContext { LineNumFromPcContext(uint32_t address, uint32_t line_num) : address_(address), line_num_(line_num) {} @@ -1068,15 +1083,6 @@ class DexFile { DISALLOW_COPY_AND_ASSIGN(LineNumFromPcContext); }; - void InvokeLocalCbIfLive(void* context, int reg, uint32_t end_address, - LocalInfo* local_in_reg, DexDebugNewLocalCb local_cb) const { - if (local_cb != nullptr && local_in_reg[reg].is_live_) { - local_cb(context, reg, local_in_reg[reg].start_address_, end_address, - local_in_reg[reg].name_, local_in_reg[reg].descriptor_, - local_in_reg[reg].signature_ != nullptr ? 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. // @@ -1088,9 +1094,13 @@ class DexFile { int32_t GetLineNumFromPC(ArtMethod* method, uint32_t rel_pc) const SHARED_REQUIRES(Locks::mutator_lock_); - void DecodeDebugInfo(const CodeItem* code_item, bool is_static, uint32_t method_idx, - DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb, - void* context) const; + // Returns false if there is no debugging information or if it can not be decoded. + bool DecodeDebugLocalInfo(const CodeItem* code_item, bool is_static, uint32_t method_idx, + DexDebugNewLocalCb local_cb, void* context) const; + + // Returns false if there is no debugging information or if it can not be decoded. + bool DecodeDebugPositionInfo(const CodeItem* code_item, DexDebugNewPositionCb position_cb, + void* context) const; const char* GetSourceFile(const ClassDef& class_def) const { if (class_def.source_file_idx_ == 0xffffffff) { @@ -1200,10 +1210,6 @@ class DexFile { // Returns true if the header magic and version numbers are of the expected values. bool CheckMagicAndVersion(std::string* error_msg) const; - void DecodeDebugInfo0(const CodeItem* code_item, bool is_static, uint32_t method_idx, - DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb, - void* context, const uint8_t* stream, LocalInfo* local_in_reg) const; - // Check whether a location denotes a multidex dex file. This is a very simple check: returns // whether the string contains the separator character. static bool IsMultiDexLocation(const char* location); @@ -1275,6 +1281,7 @@ class DexFileParameterIterator { } } bool HasNext() const { return pos_ < size_; } + size_t Size() const { return size_; } void Next() { ++pos_; } uint16_t GetTypeIdx() { return type_list_->GetTypeItem(pos_).type_idx_; diff --git a/runtime/jdwp/jdwp_expand_buf.cc b/runtime/jdwp/jdwp_expand_buf.cc index e492d7eb26..961dd369c8 100644 --- a/runtime/jdwp/jdwp_expand_buf.cc +++ b/runtime/jdwp/jdwp_expand_buf.cc @@ -164,7 +164,7 @@ static void SetUtf8String(uint8_t* buf, const char* str, size_t strLen) { * have stored null bytes in a multi-byte encoding). */ void expandBufAddUtf8String(ExpandBuf* pBuf, const char* s) { - int strLen = strlen(s); + int strLen = (s != nullptr ? strlen(s) : 0); ensureSpace(pBuf, sizeof(uint32_t) + strLen); SetUtf8String(pBuf->storage + pBuf->curLen, s, strLen); pBuf->curLen += sizeof(uint32_t) + strLen; |