diff options
-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; |