diff --git a/src/ccc/dwarf_section.cpp b/src/ccc/dwarf_section.cpp index 1821359..56ec589 100644 --- a/src/ccc/dwarf_section.cpp +++ b/src/ccc/dwarf_section.cpp @@ -4,6 +4,7 @@ #include "dwarf_section.h" #include "importer_flags.h" +#include "registers.h" namespace ccc::dwarf { @@ -351,6 +352,66 @@ Result DIE::parse_attribute(u32& offset) const return result; } +// ***************************************************************************** + +LocationDescription::LocationDescription(std::span block) + : m_block(block) {} + +Result LocationDescription::print(FILE* out) +{ + fprintf(out, "{"); + + u32 offset = 0; + while (offset < m_block.size()) { + if (offset != 0) { + fprintf(out, ","); + } + + Result atom = parse_atom(offset); + CCC_RETURN_IF_ERROR(atom); + + const char* op_name = location_op_to_string(atom->op); + CCC_ASSERT(op_name); + + fprintf(out, "%s", op_name); + + if (atom->value.has_value()) { + if ((atom->op == OP_REG || atom->op == OP_BASEREG) && *atom->value < 32) { + fprintf(out, "(%s)", mips::GPR_STRINGS[*atom->value]); + } else { + fprintf(out, "(0x%x)", *atom->value); + } + } + } + + fprintf(out, "}"); + + return Result(); +} + +Result LocationDescription::parse_atom(u32& offset) const +{ + LocationAtom atom; + + const u8* op = get_unaligned(m_block, offset); + CCC_CHECK(op, "Invalid location description (cannot read op)."); + offset += sizeof(u8); + + const char* op_name = location_op_to_string(*op); + CCC_CHECK(op_name, "Invalid location description (unknown op 0x%hhx).", *op); + + atom.op = static_cast(*op); + + if (*op == OP_REG || *op == OP_BASEREG || *op == OP_ADDR || *op == OP_CONST || *op == OP_80) { + const u32* value = get_unaligned(m_block, offset); + CCC_CHECK(value, "Invalid location descripton (cannot read value)."); + offset += sizeof(u32); + + atom.value = *value; + } + + return atom; +} // ***************************************************************************** @@ -432,47 +493,14 @@ Result SectionReader::print_attributes(FILE* out, const DIE& die) const break; } case FORM_REF: { - Result> referenced_die = DIE::parse(m_debug, value.reference(), NO_IMPORTER_FLAGS); - if (referenced_die.success()) { - if (referenced_die->has_value()) { - const char* referenced_die_tag = tag_to_string((*referenced_die)->tag()); - if (referenced_die_tag) { - fprintf(out, "%s", referenced_die_tag); - } else { - fprintf(out, "unknown(%hx)", (*referenced_die)->tag()); - } - } else { - // The DIE was less than 8 bytes in size. - fprintf(out, "null"); - } - } else { - // The DIE could not be read. - fprintf(out, "???"); - } - - fprintf(out, "@%x", value.reference()); + Result ref_result = print_ref_value(out, value); + CCC_RETURN_IF_ERROR(ref_result); break; } case FORM_BLOCK2: case FORM_BLOCK4: { - fprintf(out, "{"); - - size_t max_bytes_to_display = 3; - std::span block = value.block(); - - for (size_t i = 0; i < std::min(block.size(), max_bytes_to_display); i++) { - if (i != 0) { - fprintf(out, ","); - } - fprintf(out, "%02hhx", block[i]); - } - - if (block.size() > max_bytes_to_display) { - fprintf(out, ",..."); - } - - fprintf(out, "}@%x", offset); - + Result block_result = print_block_value(out, offset, attribute, value); + CCC_RETURN_IF_ERROR(block_result); break; } case FORM_DATA2: @@ -492,6 +520,67 @@ Result SectionReader::print_attributes(FILE* out, const DIE& die) const return Result(); } +Result SectionReader::print_ref_value(FILE* out, const Value& value) const +{ + Result> referenced_die = DIE::parse(m_debug, value.reference(), NO_IMPORTER_FLAGS); + if (referenced_die.success()) { + if (referenced_die->has_value()) { + const char* referenced_die_tag = tag_to_string((*referenced_die)->tag()); + if (referenced_die_tag) { + fprintf(out, "%s", referenced_die_tag); + } else { + fprintf(out, "unknown(%hx)", (*referenced_die)->tag()); + } + } else { + // The DIE was less than 8 bytes in size. + fprintf(out, "null"); + } + } else { + // The DIE could not be read. + fprintf(out, "???"); + } + + fprintf(out, "@%x", value.reference()); + + return Result(); +} + +Result SectionReader::print_block_value(FILE* out, u32 offset, Attribute attribute, const Value& value) const +{ + std::span block = value.block(); + + switch (attribute) { + case AT_location: { + LocationDescription location(value.block()); + + Result print_result = location.print(out); + CCC_RETURN_IF_ERROR(print_result); + + break; + } + default: { + fprintf(out, "{"); + + size_t max_bytes_to_display = 3; + + for (size_t i = 0; i < std::min(block.size(), max_bytes_to_display); i++) { + if (i != 0) { + fprintf(out, ","); + } + fprintf(out, "%02hhx", block[i]); + } + + if (block.size() > max_bytes_to_display) { + fprintf(out, ",..."); + } + + fprintf(out, "}@%x", offset); + } + } + + return Result(); +} + const char* tag_to_string(u32 tag) { switch (tag) { @@ -599,6 +688,7 @@ const char* attribute_to_string(u32 attribute) case AT_stride_size: return "stride_size"; case AT_upper_bound: return "upper_bound"; case AT_virtual: return "virtual"; + case AT_mangled_name: return "mangled_name"; case AT_overlay_id: return "overlay_id"; case AT_overlay_name: return "overlay_name"; } @@ -606,4 +696,20 @@ const char* attribute_to_string(u32 attribute) return nullptr; } +const char* location_op_to_string(u32 op) +{ + switch (op) { + case OP_REG: return "reg"; + case OP_BASEREG: return "basereg"; + case OP_ADDR: return "addr"; + case OP_CONST: return "const"; + case OP_DEREF2: return "deref2"; + case OP_DEREF: return "deref"; + case OP_ADD: return "add"; + case OP_80: return "op80"; + } + + return nullptr; +} + } diff --git a/src/ccc/dwarf_section.h b/src/ccc/dwarf_section.h index 621f14f..075647f 100644 --- a/src/ccc/dwarf_section.h +++ b/src/ccc/dwarf_section.h @@ -237,6 +237,34 @@ class DIE { u32 m_importer_flags; }; +enum LocationOp : u8 { + OP_REG = 0x01, + OP_BASEREG = 0x02, + OP_ADDR = 0x03, + OP_CONST = 0x04, + OP_DEREF2 = 0x05, + OP_DEREF = 0x06, + OP_ADD = 0x07, + OP_80 = 0x80 +}; + +struct LocationAtom { + LocationOp op; + std::optional value; +}; + +class LocationDescription { +public: + LocationDescription(std::span block); + + Result print(FILE* out); + +protected: + Result parse_atom(u32& offset) const; + + std::span m_block; +}; + class SectionReader { public: SectionReader(std::span debug, std::span line); @@ -245,6 +273,8 @@ class SectionReader { Result print_dies(FILE* out, DIE die, s32 depth) const; Result print_attributes(FILE* out, const DIE& die) const; + Result print_ref_value(FILE* out, const Value& value) const; + Result print_block_value(FILE* out, u32 offset, Attribute attribute, const Value& value) const; protected: std::span m_debug; @@ -254,5 +284,6 @@ class SectionReader { const char* tag_to_string(u32 tag); const char* form_to_string(u32 form); const char* attribute_to_string(u32 attribute); +const char* location_op_to_string(u32 op); }