Fix dexlayout debug info printing
Parsing local info and position info made shared debug info print
incorrectly. Remove the dexlayout structs that represent the pre-parsed
versions and print from the byte buffer.
Bug: 67664147
Test: make test-art-host
Change-Id: Iae33ae8ff486914d8d7a5973f81faaf3c95615a6
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 0c944ce..f75eacc 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -39,24 +39,6 @@
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 @@
}
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 5dcc87d..df3484c 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -966,39 +966,6 @@
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 @@
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 5458129..18ddc86 100644
--- a/dexlayout/dex_verify.cc
+++ b/dexlayout/dex_verify.cc
@@ -893,109 +893,24 @@
}
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 58c95d6..998939b 100644
--- a/dexlayout/dex_verify.h
+++ b/dexlayout/dex_verify.h
@@ -100,14 +100,6 @@
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 ade0072..40449ae 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -820,37 +820,6 @@
}
/*
- * 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 @@
}
/*
+ * 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 @@
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 @@
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 9f6e8a4..180d9bc 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -96,7 +96,13 @@
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 1b7c318..5dfbd9b 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 @@
}
}
+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 08c047d..f2c43f7 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -537,228 +537,6 @@
}
}
-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 5759684..6868d52 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -772,10 +772,6 @@
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 @@
};
// 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 {