diff options
-rw-r--r-- | dexlayout/dex_ir.cc | 24 | ||||
-rw-r--r-- | dexlayout/dex_ir.h | 39 | ||||
-rw-r--r-- | dexlayout/dex_verify.cc | 109 | ||||
-rw-r--r-- | dexlayout/dex_verify.h | 8 | ||||
-rw-r--r-- | dexlayout/dexlayout.cc | 133 | ||||
-rw-r--r-- | dexlayout/dexlayout.h | 8 | ||||
-rw-r--r-- | runtime/dex_file-inl.h | 275 | ||||
-rw-r--r-- | runtime/dex_file.cc | 222 | ||||
-rw-r--r-- | runtime/dex_file.h | 35 |
9 files changed, 420 insertions, 433 deletions
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc index 0c944cee2c..f75eacc2d3 100644 --- a/dexlayout/dex_ir.cc +++ b/dexlayout/dex_ir.cc @@ -39,24 +39,6 @@ static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_ext return value; } -static bool GetPositionsCb(void* context, const DexFile::PositionInfo& entry) { - DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context); - PositionInfoVector& positions = debug_info->GetPositionInfo(); - positions.push_back(std::unique_ptr<PositionInfo>(new PositionInfo(entry.address_, entry.line_))); - return false; -} - -static void GetLocalsCb(void* context, const DexFile::LocalInfo& entry) { - DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context); - LocalInfoVector& locals = debug_info->GetLocalInfo(); - const char* name = entry.name_ != nullptr ? entry.name_ : "(null)"; - const char* descriptor = entry.descriptor_ != nullptr ? entry.descriptor_ : ""; - const char* signature = entry.signature_ != nullptr ? entry.signature_ : ""; - locals.push_back(std::unique_ptr<LocalInfo>( - new LocalInfo(name, descriptor, signature, entry.start_address_, entry.end_address_, - entry.reg_))); -} - static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) { const uint8_t* stream = debug_info_stream; DecodeUnsignedLeb128(&stream); // line_start @@ -694,12 +676,6 @@ MethodItem* Collections::GenerateMethodItem(const DexFile& dex_file, ClassDataIt } debug_info = code_item->DebugInfo(); } - if (debug_info != nullptr) { - bool is_static = (access_flags & kAccStatic) != 0; - dex_file.DecodeDebugLocalInfo( - disk_code_item, is_static, cdii.GetMemberIndex(), GetLocalsCb, debug_info); - dex_file.DecodeDebugPositionInfo(disk_code_item, GetPositionsCb, debug_info); - } return new MethodItem(access_flags, method_id, code_item); } diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h index 5dcc87dd2e..df3484c012 100644 --- a/dexlayout/dex_ir.h +++ b/dexlayout/dex_ir.h @@ -966,39 +966,6 @@ class CodeItem : public Item { DISALLOW_COPY_AND_ASSIGN(CodeItem); }; -struct PositionInfo { - PositionInfo(uint32_t address, uint32_t line) : address_(address), line_(line) { } - - uint32_t address_; - uint32_t line_; -}; - -using PositionInfoVector = std::vector<std::unique_ptr<PositionInfo>>; - -struct LocalInfo { - LocalInfo(const char* name, - const char* descriptor, - const char* signature, - uint32_t start_address, - uint32_t end_address, - uint16_t reg) - : name_(name), - descriptor_(descriptor), - signature_(signature), - start_address_(start_address), - end_address_(end_address), - reg_(reg) { } - - std::string name_; - std::string descriptor_; - std::string signature_; - uint32_t start_address_; - uint32_t end_address_; - uint16_t reg_; -}; - -using LocalInfoVector = std::vector<std::unique_ptr<LocalInfo>>; - class DebugInfoItem : public Item { public: DebugInfoItem(uint32_t debug_info_size, uint8_t* debug_info) @@ -1007,16 +974,10 @@ class DebugInfoItem : public Item { uint32_t GetDebugInfoSize() const { return debug_info_size_; } uint8_t* GetDebugInfo() const { return debug_info_.get(); } - PositionInfoVector& GetPositionInfo() { return positions_; } - LocalInfoVector& GetLocalInfo() { return locals_; } - private: uint32_t debug_info_size_; std::unique_ptr<uint8_t[]> debug_info_; - PositionInfoVector positions_; - LocalInfoVector locals_; - DISALLOW_COPY_AND_ASSIGN(DebugInfoItem); }; diff --git a/dexlayout/dex_verify.cc b/dexlayout/dex_verify.cc index 54581292ff..18ddc86e0c 100644 --- a/dexlayout/dex_verify.cc +++ b/dexlayout/dex_verify.cc @@ -893,109 +893,24 @@ bool VerifyDebugInfo(dex_ir::DebugInfoItem* orig, } return true; } - if (!VerifyPositionInfo(orig->GetPositionInfo(), - output->GetPositionInfo(), - orig->GetOffset(), - error_msg)) { + // TODO: Test for debug equivalence rather than byte array equality. + uint32_t orig_size = orig->GetDebugInfoSize(); + uint32_t output_size = output->GetDebugInfoSize(); + if (orig_size != output_size) { + *error_msg = "DebugInfoSize disagreed."; return false; } - return VerifyLocalInfo(orig->GetLocalInfo(), - output->GetLocalInfo(), - orig->GetOffset(), - error_msg); -} - -bool VerifyPositionInfo(dex_ir::PositionInfoVector& orig, - dex_ir::PositionInfoVector& output, - uint32_t orig_offset, - std::string* error_msg) { - if (orig.size() != output.size()) { - *error_msg = StringPrintf( - "Mismatched number of positions for debug info at offset %x: %zu vs %zu.", - orig_offset, - orig.size(), - output.size()); + uint8_t* orig_data = orig->GetDebugInfo(); + uint8_t* output_data = output->GetDebugInfo(); + if ((orig_data == nullptr && output_data != nullptr) || + (orig_data != nullptr && output_data == nullptr)) { + *error_msg = "DebugInfo null/non-null mismatch."; return false; } - for (size_t i = 0; i < orig.size(); ++i) { - if (orig[i]->address_ != output[i]->address_) { - *error_msg = StringPrintf( - "Mismatched position address for debug info at offset %x: %u vs %u.", - orig_offset, - orig[i]->address_, - output[i]->address_); - return false; - } - if (orig[i]->line_ != output[i]->line_) { - *error_msg = StringPrintf("Mismatched position line for debug info at offset %x: %u vs %u.", - orig_offset, - orig[i]->line_, - output[i]->line_); - return false; - } - } - return true; -} - -bool VerifyLocalInfo(dex_ir::LocalInfoVector& orig, - dex_ir::LocalInfoVector& output, - uint32_t orig_offset, - std::string* error_msg) { - if (orig.size() != output.size()) { - *error_msg = StringPrintf( - "Mismatched number of locals for debug info at offset %x: %zu vs %zu.", - orig_offset, - orig.size(), - output.size()); + if (memcmp(orig_data, output_data, orig_size) != 0) { + *error_msg = "DebugInfo bytes mismatch."; return false; } - for (size_t i = 0; i < orig.size(); ++i) { - if (orig[i]->name_ != output[i]->name_) { - *error_msg = StringPrintf("Mismatched local name for debug info at offset %x: %s vs %s.", - orig_offset, - orig[i]->name_.c_str(), - output[i]->name_.c_str()); - return false; - } - if (orig[i]->descriptor_ != output[i]->descriptor_) { - *error_msg = StringPrintf( - "Mismatched local descriptor for debug info at offset %x: %s vs %s.", - orig_offset, - orig[i]->descriptor_.c_str(), - output[i]->descriptor_.c_str()); - return false; - } - if (orig[i]->signature_ != output[i]->signature_) { - *error_msg = StringPrintf("Mismatched local signature for debug info at offset %x: %s vs %s.", - orig_offset, - orig[i]->signature_.c_str(), - output[i]->signature_.c_str()); - return false; - } - if (orig[i]->start_address_ != output[i]->start_address_) { - *error_msg = StringPrintf( - "Mismatched local start address for debug info at offset %x: %u vs %u.", - orig_offset, - orig[i]->start_address_, - output[i]->start_address_); - return false; - } - if (orig[i]->end_address_ != output[i]->end_address_) { - *error_msg = StringPrintf( - "Mismatched local end address for debug info at offset %x: %u vs %u.", - orig_offset, - orig[i]->end_address_, - output[i]->end_address_); - return false; - } - if (orig[i]->reg_ != output[i]->reg_) { - *error_msg = StringPrintf("Mismatched local reg for debug info at offset %x: %u vs %u.", - orig_offset, - orig[i]->reg_, - output[i]->reg_); - return false; - } - } return true; } diff --git a/dexlayout/dex_verify.h b/dexlayout/dex_verify.h index 58c95d6947..998939bbce 100644 --- a/dexlayout/dex_verify.h +++ b/dexlayout/dex_verify.h @@ -100,14 +100,6 @@ bool VerifyCode(dex_ir::CodeItem* orig, dex_ir::CodeItem* output, std::string* e bool VerifyDebugInfo(dex_ir::DebugInfoItem* orig, dex_ir::DebugInfoItem* output, std::string* error_msg); -bool VerifyPositionInfo(dex_ir::PositionInfoVector& orig, - dex_ir::PositionInfoVector& output, - uint32_t orig_offset, - std::string* error_msg); -bool VerifyLocalInfo(dex_ir::LocalInfoVector& orig, - dex_ir::LocalInfoVector& output, - uint32_t orig_offset, - std::string* error_msg); bool VerifyTries(dex_ir::TryItemVector* orig, dex_ir::TryItemVector* output, uint32_t orig_offset, diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index ade00723fd..40449ae8bd 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -820,37 +820,6 @@ void DexLayout::DumpCatches(const dex_ir::CodeItem* code) { } /* - * Dumps all positions table entries associated with the code. - */ -void DexLayout::DumpPositionInfo(const dex_ir::CodeItem* code) { - dex_ir::DebugInfoItem* debug_info = code->DebugInfo(); - if (debug_info == nullptr) { - return; - } - std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo(); - for (size_t i = 0; i < positions.size(); ++i) { - fprintf(out_file_, " 0x%04x line=%d\n", positions[i]->address_, positions[i]->line_); - } -} - -/* - * Dumps all locals table entries associated with the code. - */ -void DexLayout::DumpLocalInfo(const dex_ir::CodeItem* code) { - dex_ir::DebugInfoItem* debug_info = code->DebugInfo(); - if (debug_info == nullptr) { - return; - } - std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo(); - for (size_t i = 0; i < locals.size(); ++i) { - dex_ir::LocalInfo* entry = locals[i].get(); - fprintf(out_file_, " 0x%04x - 0x%04x reg=%d %s %s %s\n", - entry->start_address_, entry->end_address_, entry->reg_, - entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str()); - } -} - -/* * Dumps a single instruction. */ void DexLayout::DumpInstruction(const dex_ir::CodeItem* code, @@ -1093,9 +1062,59 @@ void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32 } /* + * Callback for dumping each positions table entry. + */ +static bool DumpPositionsCb(void* context, const DexFile::PositionInfo& entry) { + FILE* out_file = reinterpret_cast<FILE*>(context); + fprintf(out_file, " 0x%04x line=%d\n", entry.address_, entry.line_); + return false; +} + +/* + * Callback for dumping locals table entry. + */ +static void DumpLocalsCb(void* context, const DexFile::LocalInfo& entry) { + const char* signature = entry.signature_ != nullptr ? entry.signature_ : ""; + FILE* out_file = reinterpret_cast<FILE*>(context); + fprintf(out_file, " 0x%04x - 0x%04x reg=%d %s %s %s\n", + entry.start_address_, entry.end_address_, entry.reg_, + entry.name_, entry.descriptor_, signature); +} + +/* + * Lookup functions. + */ +static const char* StringDataByIdx(uint32_t idx, dex_ir::Collections& collections) { + dex_ir::StringId* string_id = collections.GetStringIdOrNullPtr(idx); + if (string_id == nullptr) { + return nullptr; + } + return string_id->Data(); +} + +static const char* StringDataByTypeIdx(uint16_t idx, dex_ir::Collections& collections) { + dex_ir::TypeId* type_id = collections.GetTypeIdOrNullPtr(idx); + if (type_id == nullptr) { + return nullptr; + } + dex_ir::StringId* string_id = type_id->GetStringId(); + if (string_id == nullptr) { + return nullptr; + } + return string_id->Data(); +} + + +/* * Dumps code of a method. */ -void DexLayout::DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) { +void DexLayout::DumpCode(uint32_t idx, + const dex_ir::CodeItem* code, + uint32_t code_offset, + const char* declaring_class_descriptor, + const char* method_name, + bool is_static, + const dex_ir::ProtoId* proto) { fprintf(out_file_, " registers : %d\n", code->RegistersSize()); fprintf(out_file_, " ins : %d\n", code->InsSize()); fprintf(out_file_, " outs : %d\n", code->OutsSize()); @@ -1111,10 +1130,48 @@ void DexLayout::DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t co DumpCatches(code); // Positions and locals table in the debug info. + dex_ir::DebugInfoItem* debug_info = code->DebugInfo(); fprintf(out_file_, " positions : \n"); - DumpPositionInfo(code); + if (debug_info != nullptr) { + DexFile::DecodeDebugPositionInfo(debug_info->GetDebugInfo(), + [this](uint32_t idx) { + return StringDataByIdx(idx, this->header_->GetCollections()); + }, + DumpPositionsCb, + out_file_); + } fprintf(out_file_, " locals : \n"); - DumpLocalInfo(code); + if (debug_info != nullptr) { + std::vector<const char*> arg_descriptors; + const dex_ir::TypeList* parameters = proto->Parameters(); + if (parameters != nullptr) { + const dex_ir::TypeIdVector* parameter_type_vector = parameters->GetTypeList(); + if (parameter_type_vector != nullptr) { + for (const dex_ir::TypeId* type_id : *parameter_type_vector) { + arg_descriptors.push_back(type_id->GetStringId()->Data()); + } + } + } + DexFile::DecodeDebugLocalInfo(debug_info->GetDebugInfo(), + "DexLayout in-memory", + declaring_class_descriptor, + arg_descriptors, + method_name, + is_static, + code->RegistersSize(), + code->InsSize(), + code->InsnsSize(), + [this](uint32_t idx) { + return StringDataByIdx(idx, this->header_->GetCollections()); + }, + [this](uint32_t idx) { + return + StringDataByTypeIdx(dchecked_integral_cast<uint16_t>(idx), + this->header_->GetCollections()); + }, + DumpLocalsCb, + out_file_); + } } /* @@ -1141,7 +1198,13 @@ void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* fprintf(out_file_, " code : (none)\n"); } else { fprintf(out_file_, " code -\n"); - DumpCode(idx, code, code->GetOffset()); + DumpCode(idx, + code, + code->GetOffset(), + back_descriptor, + name, + (flags & kAccStatic) != 0, + method_id->Proto()); } if (options_.disassemble_) { fputc('\n', out_file_); diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h index 9f6e8a4122..180d9bc87c 100644 --- a/dexlayout/dexlayout.h +++ b/dexlayout/dexlayout.h @@ -96,7 +96,13 @@ class DexLayout { void DumpClass(int idx, char** last_package); void DumpClassAnnotations(int idx); void DumpClassDef(int idx); - void DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset); + void DumpCode(uint32_t idx, + const dex_ir::CodeItem* code, + uint32_t code_offset, + const char* declaring_class_descriptor, + const char* method_name, + bool is_static, + const dex_ir::ProtoId* proto); void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation); void DumpEncodedValue(const dex_ir::EncodedValue* data); void DumpFileHeader(); diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h index 1b7c31859c..5dfbd9b6a1 100644 --- a/runtime/dex_file-inl.h +++ b/runtime/dex_file-inl.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_DEX_FILE_INL_H_ #include "base/bit_utils.h" +#include "base/casts.h" #include "base/logging.h" #include "base/stringpiece.h" #include "dex_file.h" @@ -220,6 +221,280 @@ InvokeType ClassDataItemIterator::GetMethodInvokeType(const DexFile::ClassDef& c } } +template<typename NewLocalCallback, typename IndexToStringData, typename TypeIndexToStringData> +bool DexFile::DecodeDebugLocalInfo(const uint8_t* stream, + const std::string& location, + const char* declaring_class_descriptor, + const std::vector<const char*>& arg_descriptors, + const std::string& method_name, + bool is_static, + uint16_t registers_size, + uint16_t ins_size, + uint16_t insns_size_in_code_units, + IndexToStringData index_to_string_data, + TypeIndexToStringData type_index_to_string_data, + NewLocalCallback new_local_callback, + void* context) { + if (stream == nullptr) { + return false; + } + std::vector<LocalInfo> local_in_reg(registers_size); + + uint16_t arg_reg = registers_size - ins_size; + if (!is_static) { + const char* descriptor = declaring_class_descriptor; + 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++; + } + + DecodeUnsignedLeb128(&stream); // Line. + uint32_t parameters_size = DecodeUnsignedLeb128(&stream); + uint32_t i; + if (parameters_size != arg_descriptors.size()) { + LOG(ERROR) << "invalid stream - problem with parameter iterator in " << location + << " for method " << method_name; + return false; + } + for (i = 0; i < parameters_size && i < arg_descriptors.size(); ++i) { + if (arg_reg >= registers_size) { + LOG(ERROR) << "invalid stream - arg reg >= reg size (" << arg_reg + << " >= " << registers_size << ") in " << location; + return false; + } + uint32_t name_idx = DecodeUnsignedLeb128P1(&stream); + const char* descriptor = arg_descriptors[i]; + local_in_reg[arg_reg].name_ = index_to_string_data(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': + arg_reg += 2; + break; + default: + arg_reg += 1; + break; + } + } + + uint32_t address = 0; + for (;;) { + uint8_t opcode = *stream++; + switch (opcode) { + case DBG_END_SEQUENCE: + // Emit all variables which are still alive at the end of the method. + for (uint16_t reg = 0; reg < registers_size; reg++) { + if (local_in_reg[reg].is_live_) { + local_in_reg[reg].end_address_ = insns_size_in_code_units; + new_local_callback(context, local_in_reg[reg]); + } + } + return true; + case DBG_ADVANCE_PC: + address += DecodeUnsignedLeb128(&stream); + break; + case DBG_ADVANCE_LINE: + DecodeSignedLeb128(&stream); // Line. + break; + case DBG_START_LOCAL: + case DBG_START_LOCAL_EXTENDED: { + uint16_t reg = DecodeUnsignedLeb128(&stream); + if (reg >= registers_size) { + LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= " + << registers_size << ") in " << location; + return false; + } + + uint32_t name_idx = DecodeUnsignedLeb128P1(&stream); + uint16_t descriptor_idx = DecodeUnsignedLeb128P1(&stream); + uint32_t signature_idx = dex::kDexNoIndex; + if (opcode == DBG_START_LOCAL_EXTENDED) { + signature_idx = DecodeUnsignedLeb128P1(&stream); + } + + // Emit what was previously there, if anything + if (local_in_reg[reg].is_live_) { + local_in_reg[reg].end_address_ = address; + new_local_callback(context, local_in_reg[reg]); + } + + local_in_reg[reg].name_ = index_to_string_data(name_idx); + local_in_reg[reg].descriptor_ = type_index_to_string_data(descriptor_idx);; + local_in_reg[reg].signature_ = index_to_string_data(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 >= registers_size) { + LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= " + << registers_size << ") in " << location; + return false; + } + // If the register is live, close it properly. Otherwise, closing an already + // closed register is sloppy, but harmless if no further action is taken. + if (local_in_reg[reg].is_live_) { + local_in_reg[reg].end_address_ = address; + new_local_callback(context, local_in_reg[reg]); + local_in_reg[reg].is_live_ = false; + } + break; + } + case DBG_RESTART_LOCAL: { + uint16_t reg = DecodeUnsignedLeb128(&stream); + if (reg >= registers_size) { + LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= " + << registers_size << ") in " << location; + return false; + } + // 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: + address += (opcode - DBG_FIRST_SPECIAL) / DBG_LINE_RANGE; + break; + } + } +} + +template<typename NewLocalCallback> +bool DexFile::DecodeDebugLocalInfo(const CodeItem* code_item, + bool is_static, + uint32_t method_idx, + NewLocalCallback new_local_callback, + void* context) const { + if (code_item == nullptr) { + return false; + } + std::vector<const char*> arg_descriptors; + DexFileParameterIterator it(*this, GetMethodPrototype(GetMethodId(method_idx))); + for (; it.HasNext(); it.Next()) { + arg_descriptors.push_back(it.GetDescriptor()); + } + return DecodeDebugLocalInfo(GetDebugInfoStream(code_item), + GetLocation(), + GetMethodDeclaringClassDescriptor(GetMethodId(method_idx)), + arg_descriptors, + this->PrettyMethod(method_idx), + is_static, + code_item->registers_size_, + code_item->ins_size_, + code_item->insns_size_in_code_units_, + [this](uint32_t idx) { + return StringDataByIdx(dex::StringIndex(idx)); + }, + [this](uint32_t idx) { + return StringByTypeIdx(dex::TypeIndex( + dchecked_integral_cast<uint16_t>(idx))); + }, + new_local_callback, + context); +} + +template<typename DexDebugNewPosition, typename IndexToStringData> +bool DexFile::DecodeDebugPositionInfo(const uint8_t* stream, + IndexToStringData index_to_string_data, + DexDebugNewPosition position_functor, + void* context) { + 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 (;;) { + 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_ = index_to_string_data(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_functor(context, entry)) { + return true; // early exit. + } + entry.prologue_end_ = false; + entry.epilogue_begin_ = false; + break; + } + } + } +} + +template<typename DexDebugNewPosition> +bool DexFile::DecodeDebugPositionInfo(const CodeItem* code_item, + DexDebugNewPosition position_functor, + void* context) const { + if (code_item == nullptr) { + return false; + } + return DecodeDebugPositionInfo(GetDebugInfoStream(code_item), + [this](uint32_t idx) { + return StringDataByIdx(dex::StringIndex(idx)); + }, + position_functor, + context); +} + } // namespace art #endif // ART_RUNTIME_DEX_FILE_INL_H_ diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index 08c047d8e9..f2c43f7f87 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -537,228 +537,6 @@ int32_t DexFile::FindCatchHandlerOffset(const CodeItem &code_item, uint32_t addr } } -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) { - 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))); - 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 false; - } - uint32_t name_idx = DecodeUnsignedLeb128P1(&stream); - const char* descriptor = it.GetDescriptor(); - local_in_reg[arg_reg].name_ = StringDataByIdx(dex::StringIndex(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': - arg_reg += 2; - break; - default: - arg_reg += 1; - break; - } - } - if (i != parameters_size || it.HasNext()) { - LOG(ERROR) << "invalid stream - problem with parameter iterator in " << GetLocation() - << " for method " << this->PrettyMethod(method_idx); - return false; - } - - uint32_t address = 0; - for (;;) { - uint8_t opcode = *stream++; - switch (opcode) { - case DBG_END_SEQUENCE: - // 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: - DecodeSignedLeb128(&stream); // Line. - break; - case DBG_START_LOCAL: - 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 false; - } - - uint32_t name_idx = DecodeUnsignedLeb128P1(&stream); - uint16_t descriptor_idx = DecodeUnsignedLeb128P1(&stream); - uint32_t signature_idx = dex::kDexNoIndex; - if (opcode == DBG_START_LOCAL_EXTENDED) { - signature_idx = DecodeUnsignedLeb128P1(&stream); - } - - // Emit what was previously there, if anything - if (local_in_reg[reg].is_live_) { - local_in_reg[reg].end_address_ = address; - local_cb(context, local_in_reg[reg]); - } - - local_in_reg[reg].name_ = StringDataByIdx(dex::StringIndex(name_idx)); - local_in_reg[reg].descriptor_ = - StringByTypeIdx(dex::TypeIndex(dchecked_integral_cast<uint16_t>(descriptor_idx)));; - local_in_reg[reg].signature_ = StringDataByIdx(dex::StringIndex(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 false; - } - // If the register is live, close it properly. Otherwise, closing an already - // closed register is sloppy, but harmless if no further action is taken. - if (local_in_reg[reg].is_live_) { - 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: { - 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 false; - } - // 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: - address += (opcode - DBG_FIRST_SPECIAL) / DBG_LINE_RANGE; - break; - } - } -} - -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); - 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 (;;) { - 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(dex::StringIndex(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, const PositionInfo& entry) { LineNumFromPcContext* context = reinterpret_cast<LineNumFromPcContext*>(raw_context); diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 5759684c55..6868d525e2 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -772,10 +772,6 @@ class DexFile { bool epilogue_begin_ = false; }; - // Callback for "new position table entry". - // Returning true causes the decoder to stop early. - typedef bool (*DexDebugNewPositionCb)(void* context, const PositionInfo& entry); - struct LocalInfo { LocalInfo() = default; @@ -899,11 +895,36 @@ class DexFile { }; // Returns false if there is no debugging information or if it cannot be decoded. - bool DecodeDebugLocalInfo(const CodeItem* code_item, bool is_static, uint32_t method_idx, - DexDebugNewLocalCb local_cb, void* context) const; + template<typename NewLocalCallback, typename IndexToStringData, typename TypeIndexToStringData> + static bool DecodeDebugLocalInfo(const uint8_t* stream, + const std::string& location, + const char* declaring_class_descriptor, + const std::vector<const char*>& arg_descriptors, + const std::string& method_name, + bool is_static, + uint16_t registers_size, + uint16_t ins_size, + uint16_t insns_size_in_code_units, + IndexToStringData index_to_string_data, + TypeIndexToStringData type_index_to_string_data, + NewLocalCallback new_local, + void* context); + template<typename NewLocalCallback> + bool DecodeDebugLocalInfo(const CodeItem* code_item, + bool is_static, + uint32_t method_idx, + NewLocalCallback new_local, + void* context) const; // Returns false if there is no debugging information or if it cannot be decoded. - bool DecodeDebugPositionInfo(const CodeItem* code_item, DexDebugNewPositionCb position_cb, + template<typename DexDebugNewPosition, typename IndexToStringData> + static bool DecodeDebugPositionInfo(const uint8_t* stream, + IndexToStringData index_to_string_data, + DexDebugNewPosition position_functor, + void* context); + template<typename DexDebugNewPosition> + bool DecodeDebugPositionInfo(const CodeItem* code_item, + DexDebugNewPosition position_functor, void* context) const; const char* GetSourceFile(const ClassDef& class_def) const { |