Add "fixups" for ids referenced in code
Allow better visualization by determining which type_id, string_id,
method_id, and field_id values are used by code_items.
Bug: 29921113
Change-Id: Ia6ff72064104cd5c0868e972ca65536dbeb37b09
Test: dexlayout -s {some favorite apks}
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index bc909c3..0f07f23 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -21,6 +21,7 @@
*/
#include "dex_ir.h"
+#include "dex_instruction-inl.h"
#include "dex_ir_builder.h"
namespace art {
@@ -103,6 +104,102 @@
}
}
+static bool GetIdFromInstruction(Collections& collections,
+ const Instruction* dec_insn,
+ std::vector<TypeId*>* type_ids,
+ std::vector<StringId*>* string_ids,
+ std::vector<MethodId*>* method_ids,
+ std::vector<FieldId*>* field_ids) {
+ // Determine index and width of the string.
+ uint32_t index = 0;
+ switch (Instruction::FormatOf(dec_insn->Opcode())) {
+ // SOME NOT SUPPORTED:
+ // case Instruction::k20bc:
+ case Instruction::k21c:
+ case Instruction::k35c:
+ // case Instruction::k35ms:
+ case Instruction::k3rc:
+ // case Instruction::k3rms:
+ // case Instruction::k35mi:
+ // case Instruction::k3rmi:
+ index = dec_insn->VRegB();
+ break;
+ case Instruction::k31c:
+ index = dec_insn->VRegB();
+ break;
+ case Instruction::k22c:
+ // case Instruction::k22cs:
+ index = dec_insn->VRegC();
+ break;
+ default:
+ break;
+ } // switch
+
+ // Determine index type, and add reference to the appropriate collection.
+ switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
+ case Instruction::kIndexTypeRef:
+ if (index < collections.TypeIdsSize()) {
+ type_ids->push_back(collections.GetTypeId(index));
+ return true;
+ }
+ break;
+ case Instruction::kIndexStringRef:
+ if (index < collections.StringIdsSize()) {
+ string_ids->push_back(collections.GetStringId(index));
+ return true;
+ }
+ break;
+ case Instruction::kIndexMethodRef:
+ if (index < collections.MethodIdsSize()) {
+ method_ids->push_back(collections.GetMethodId(index));
+ return true;
+ }
+ break;
+ case Instruction::kIndexFieldRef:
+ if (index < collections.FieldIdsSize()) {
+ field_ids->push_back(collections.GetFieldId(index));
+ return true;
+ }
+ break;
+ case Instruction::kIndexUnknown:
+ case Instruction::kIndexNone:
+ case Instruction::kIndexVtableOffset:
+ case Instruction::kIndexFieldOffset:
+ default:
+ break;
+ } // switch
+ return false;
+}
+
+/*
+ * Get all the types, strings, methods, and fields referred to from bytecode.
+ */
+static bool GetIdsFromByteCode(Collections& collections,
+ const CodeItem* code,
+ std::vector<TypeId*>* type_ids,
+ std::vector<StringId*>* string_ids,
+ std::vector<MethodId*>* method_ids,
+ std::vector<FieldId*>* field_ids) {
+ bool has_id = false;
+ // Iterate over all instructions.
+ const uint16_t* insns = code->Insns();
+ for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) {
+ const Instruction* instruction = Instruction::At(&insns[insn_idx]);
+ const uint32_t insn_width = instruction->SizeInCodeUnits();
+ if (insn_width == 0) {
+ break;
+ }
+ has_id |= GetIdFromInstruction(collections,
+ instruction,
+ type_ids,
+ string_ids,
+ method_ids,
+ field_ids);
+ insn_idx += insn_width;
+ } // for
+ return has_id;
+}
+
EncodedValue* Collections::ReadEncodedValue(const uint8_t** data) {
const uint8_t encoded_value = *(*data)++;
const uint8_t type = encoded_value & 0x1f;
@@ -514,6 +611,26 @@
CodeItem* code_item = new CodeItem(
registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries, handler_list);
code_items_.AddItem(code_item, offset);
+ // Add "fixup" references to types, strings, methods, and fields.
+ // This is temporary, as we will probably want more detailed parsing of the
+ // instructions here.
+ std::unique_ptr<std::vector<TypeId*>> type_ids(new std::vector<TypeId*>());
+ std::unique_ptr<std::vector<StringId*>> string_ids(new std::vector<StringId*>());
+ std::unique_ptr<std::vector<MethodId*>> method_ids(new std::vector<MethodId*>());
+ std::unique_ptr<std::vector<FieldId*>> field_ids(new std::vector<FieldId*>());
+ if (GetIdsFromByteCode(*this,
+ code_item,
+ type_ids.get(),
+ string_ids.get(),
+ method_ids.get(),
+ field_ids.get())) {
+ CodeFixups* fixups = new CodeFixups(type_ids.release(),
+ string_ids.release(),
+ method_ids.release(),
+ field_ids.release());
+ code_item->SetCodeFixups(fixups);
+ }
+
return code_item;
}