diff --git a/src/dwarf/dwarf.c b/src/dwarf/dwarf.c new file mode 100644 index 00000000..6a224f34 --- /dev/null +++ b/src/dwarf/dwarf.c @@ -0,0 +1,266 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_v2(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_V2_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_v3(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_V3_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_v4(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_V4_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_v5(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_V5_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_gnu(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_GNU_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_llvm(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_LLVM_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_apple(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_APPLE_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind_mips(DW_AttribKind k) +{ + switch (k) { + #define X(_N,_C) case DW_Attrib_##_N: return _C; + DW_AttribKind_ClassFlags_MIPS_XList(X) + #undef X + } + return DW_AttribClass_Null; +} + +internal DW_AttribClass +dw_attrib_class_from_attrib_kind(DW_Version ver, DW_Ext ext, DW_AttribKind k) +{ + DW_AttribClass result = DW_AttribClass_Null; + + while (ext) { + U64 z = 64-clz64(ext); + if (z == 0) { + break; + } + U64 flag = 1 << (z-1); + ext &= ~flag; + + switch (flag) { + case DW_Ext_Null: break; + case DW_Ext_GNU: result = dw_attrib_class_from_attrib_kind_gnu(k); break; + case DW_Ext_LLVM: result = dw_attrib_class_from_attrib_kind_llvm(k); break; + case DW_Ext_APPLE: result = dw_attrib_class_from_attrib_kind_apple(k); break; + case DW_Ext_MIPS: result = dw_attrib_class_from_attrib_kind_mips(k); break; + default: InvalidPath; break; + } + + if (result != DW_AttribClass_Null) { + break; + } + } + + if (result == DW_AttribClass_Null) { + switch (ver) { + case DW_Version_Null: break; + case DW_Version_1: AssertAlways(!"DWARF V1 is not supported"); break; + case DW_Version_2: result = dw_attrib_class_from_attrib_kind_v2(k); break; + case DW_Version_3: result = dw_attrib_class_from_attrib_kind_v3(k); break; + case DW_Version_4: result = dw_attrib_class_from_attrib_kind_v4(k); break; + case DW_Version_5: result = dw_attrib_class_from_attrib_kind_v5(k); break; + default: InvalidPath; break; + } + } + + return result; +} + +internal DW_AttribClass +dw_attrib_class_from_form_kind(DW_Version ver, DW_FormKind k) +{ + #define X(_N,_C) case DW_Form_##_N: return _C; + switch (ver) { + case DW_Version_5: { + switch (k) { + DW_Form_AttribClass_V5_XList(X) + } + } break; + case DW_Version_4: { + switch (k) { + DW_Form_AttribClass_V4_XList(X) + } + } break; + case DW_Version_3: { + switch (k) { + DW_Form_AttribClass_V2_XList(X) + } + } break; + case DW_Version_2: { + switch (k) { + DW_Form_AttribClass_V2_XList(X) + } + } break; + case DW_Version_1: { + } break; + case DW_Version_Null: break; + } + #undef X + + return DW_AttribClass_Null; +} + +internal B32 +dw_are_attrib_class_and_form_kind_compatible(DW_Version ver, DW_AttribClass attrib_class, DW_FormKind form_kind) +{ + DW_AttribClass compat_flags = dw_attrib_class_from_form_kind(ver, form_kind); + B32 are_compat = (attrib_class & compat_flags) != 0; + return are_compat; +} + +internal String8 +dw_name_string_from_section_kind(DW_SectionKind k) +{ + switch (k) { + #define X(_N,_L,_M,_D) case DW_Section_##_N: return str8_lit(_L); + DW_SectionKind_XList(X) + #undef X + } + return str8_zero(); +} + +internal String8 +dw_mach_name_string_from_section_kind(DW_SectionKind k) +{ + switch (k) { + #define X(_N,_L,_M,_D) case DW_Section_##_N: return str8_lit(_M); + DW_SectionKind_XList(X) + #undef X + } + return str8_zero(); +} + +internal String8 +dw_dwo_name_string_from_section_kind(DW_SectionKind k) +{ + switch (k) { + #define X(_N,_L,_M,_D) case DW_Section_##_N: return str8_lit(_D); + DW_SectionKind_XList(X) + #undef X + } + return str8_zero(); +} + +internal U64 +dw_offset_size_from_mode(DW_Mode mode) +{ + U64 result = 0; + switch (mode) { + case DW_Mode_Null: break; + case DW_Mode_32Bit: result = 4; break; + case DW_Mode_64Bit: result = 8; break; + default: InvalidPath; break; + } + return result; +} + +internal DW_AttribClass +dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, B32 relaxed, DW_AttribKind attrib_kind, DW_FormKind form_kind) +{ + // NOTE(rjf): DWARF's spec specifies two mappings: + // (DW_AttribKind) => List(DW_AttribClass) + // (DW_FormKind) => List(DW_AttribClass) + // + // This function's purpose is to find the overlapping class between an + // DW_AttribKind and DW_FormKind. + + DW_AttribClass attrib_class = dw_attrib_class_from_attrib_kind(ver, ext, attrib_kind); + DW_AttribClass form_class = dw_attrib_class_from_form_kind(ver, form_kind); + + if(relaxed) + { + if(attrib_class == DW_AttribClass_Null || form_class == DW_AttribClass_Null) + { + attrib_class = dw_attrib_class_from_attrib_kind(DW_Version_Last, ext, attrib_kind); + form_class = dw_attrib_class_from_form_kind(DW_Version_Last, form_kind); + } + } + + DW_AttribClass result = DW_AttribClass_Null; + if(attrib_class != DW_AttribClass_Null && form_class != DW_AttribClass_Null) + { + result = DW_AttribClass_Undefined; + + for(U32 i = 0; i < 32; ++i) + { + U32 n = 1u << i; + if((attrib_class & n) != 0 && (form_class & n) != 0) + { + result = ((DW_AttribClass) n); + break; + } + } + } + + if (attrib_kind != DW_Attrib_Null && form_kind != DW_Form_Null) { + //Assert(result != DW_AttribClass_Null && result != DW_AttribClass_Undefined); + } + + return result; +} + diff --git a/src/dwarf/dwarf.h b/src/dwarf/dwarf.h new file mode 100644 index 00000000..cf108131 --- /dev/null +++ b/src/dwarf/dwarf.h @@ -0,0 +1,1690 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DWARF_H +#define DWARF_H + +typedef U16 DW_Version; +typedef enum DW_VersionEnum +{ + DW_Version_Null, + DW_Version_1, + DW_Version_2, + DW_Version_3, + DW_Version_4, + DW_Version_5, + DW_Version_Last = DW_Version_5 +} DW_VersionEnum; + +typedef U64 DW_Ext; +typedef enum DW_ExtEnum +{ + DW_Ext_Null, + + DW_Ext_GNU = (1 << 0), + DW_Ext_LLVM = (1 << 1), + DW_Ext_APPLE = (1 << 2), + DW_Ext_MIPS = (1 << 3), + + DW_Ext_All = DW_Ext_GNU|DW_Ext_LLVM|DW_Ext_APPLE|DW_Ext_MIPS, +} DW_ExtEnum; + +typedef enum DW_Mode +{ + DW_Mode_Null, + DW_Mode_32Bit, + DW_Mode_64Bit +} DW_Mode; + +#define DW_SectionKind_XList(X) \ + X(Null, "", "", "" ) \ + X(Abbrev, ".debug_abbrev", "__debug_abbrev", ".debug_abbrev.dwo" ) \ + X(ARanges, ".debug_aranges", "__debug_aranges", ".debug_aranges.dwo" ) \ + X(Frame, ".debug_frame", "__debug_frame", ".debug_frame.dwo" ) \ + X(Info, ".debug_info", "__debug_info", ".debug_info.dwo" ) \ + X(Line, ".debug_line", "__debug_line", ".debug_line.dwo" ) \ + X(Loc, ".debug_loc", "__debug_loc", ".debug_loc.dwo" ) \ + X(MacInfo, ".debug_macinfo", "__debug_macinfo", ".debug_macinfo.dwo" ) \ + X(PubNames, ".debug_pubnames", "__debug_pubnames", ".debug_pubnames.dwo" ) \ + X(PubTypes, ".debug_pubtypes", "__debug_pubtypes", ".debug_pubtypes.dwo" ) \ + X(Ranges, ".debug_ranges", "__debug_ranges", ".debug_ranges.dwo" ) \ + X(Str, ".debug_str", "__debug_str", ".debug_str.dwo" ) \ + X(Addr, ".debug_addr", "__debug_addr", ".debug_addr.dwo" ) \ + X(LocLists, ".debug_loclists", "__debug_loclists", ".debug_loclists.dwo" ) \ + X(RngLists, ".debug_rnglists", "__debug_rnglists", ".debug_rnglists.dwo" ) \ + X(StrOffsets, ".debug_stroffsets", "__debug_stroffsets", ".debug_stroffsets.dwo" ) \ + X(LineStr, ".debug_linestr", "__debug_linestr", ".debug_linestr.dwo" ) \ + X(Names, ".debug_names", "__debug_names", ".debug_names.dwo" ) + +typedef U64 DW_SectionKind; +typedef enum DW_SectionKindEnum +{ +#define X(_N,...) DW_Section_##_N, + DW_SectionKind_XList(X) +#undef X + DW_Section_Count +} DW_SectionKindEnum; + +#define DW_Language_XList(X) \ + X(Null, 0x00) \ + X(C89, 0x01) \ + X(C, 0x02) \ + X(Ada83, 0x03) \ + X(CPlusPlus, 0x04) \ + X(Cobol74, 0x05) \ + X(Cobol85, 0x06) \ + X(Fortran77, 0x07) \ + X(Fortran90, 0x08) \ + X(Pascal83, 0x09) \ + X(Modula2, 0x0A) \ + X(Java, 0x0B) \ + X(C99, 0x0C) \ + X(Ada95, 0x0D) \ + X(Fortran95, 0x0E) \ + X(PLI, 0x0F) \ + X(ObjectiveC, 0x10) \ + X(ObjectiveCPlusPlus, 0x11) \ + X(UPC, 0x12) \ + X(D, 0x13) \ + X(Python, 0x14) \ + X(OpenCL, 0x15) \ + X(Go, 0x16) \ + X(Modula3, 0x17) \ + X(Haskell, 0x18) \ + X(CPlusPlus03, 0x19) \ + X(CPlusPlus11, 0x1a) \ + X(OCaml, 0x1b) \ + X(Rust, 0x1c) \ + X(C11, 0x1d) \ + X(Swift, 0x1e) \ + X(Julia, 0x1f) \ + X(Dylan, 0x20) \ + X(CPlusPlus14, 0x21) \ + X(Fortran03, 0x22) \ + X(Fortran08, 0x23) \ + X(RenderScript, 0x24) \ + X(BLISS, 0x25) \ + X(MipsAssembler, 0x8001) \ + X(GoogleRenderScript, 0x8E57) \ + X(SunAssembler, 0x9001) \ + X(BorlandDelphi, 0xB000) + +typedef U32 DW_Language; +typedef enum DW_LanguageEnum +{ +#define X(_N, _ID) DW_Language_##_N = _ID, + DW_Language_XList(X) +#undef X + DW_Language_UserLo = 0x8000, + DW_Language_UserHi = 0xffff, +} DW_LanguageEnum; + +#define DW_StdOpcode_XList(X) \ + X(ExtendedOpcode, 0x00) \ + X(Copy, 0x01) \ + X(AdvancePc, 0x02) \ + X(AdvanceLine, 0x03) \ + X(SetFile, 0x04) \ + X(SetColumn, 0x05) \ + X(NegateStmt, 0x06) \ + X(SetBasicBlock, 0x07) \ + X(ConstAddPc, 0x08) \ + X(FixedAdvancePc, 0x09) \ + X(SetPrologueEnd, 0x0A) \ + X(SetEpilogueBegin, 0x0B) \ + X(SetIsa, 0x0C) \ + +typedef enum DW_StdOpcode +{ +#define X(_N,_ID) DW_StdOpcode_##_N = _ID, + DW_StdOpcode_XList(X) +#undef X + DW_StdOpcode_Count, +} DW_StdOpcode; + +#define DW_ExtOpcode_XList(X) \ + X(Undefined, 0x00) \ + X(EndSequence, 0x01) \ + X(SetAddress, 0x02) \ + X(DefineFile, 0x03) \ + X(SetDiscriminator, 0x04) \ + X(UserLo, 0x80) \ + X(UserHi, 0xff) + +typedef enum DW_ExtOpcode +{ +#define X(_N,_ID) DW_ExtOpcode_##_N = _ID, + DW_ExtOpcode_XList(X) +#undef X + DW_ExtOpcode_Count +} DW_ExtOpcode; + +#define DW_NameCase_XList(X) \ + X(Sensitive, 0x00) \ + X(Upper, 0x01) \ + X(Lower, 0x02) \ + X(Insensitive, 0x03) + +typedef enum DW_NameCase +{ +#define X(_N,_ID) DW_NameCase_##_N = _ID, + DW_NameCase_XList(X) +#undef X + DW_NameCase_Count +} DW_NameCase; + +#define DW_Tag_V3_XList(X) \ + X(ArrayType, 0x01) \ + X(ClassType, 0x02) \ + X(EntryPoint, 0x03) \ + X(EnumerationType, 0x04) \ + X(FormalParameter, 0x05) \ + X(ImportedDeclaration, 0x08) \ + X(Label, 0x0a) \ + X(LexicalBlock, 0x0b) \ + X(Member, 0x0d) \ + X(PointerType, 0x0f) \ + X(ReferenceType, 0x10) \ + X(CompileUnit, 0x11) \ + X(StringType, 0x12) \ + X(StructureType, 0x13) \ + X(SubroutineType, 0x15) \ + X(Typedef, 0x16) \ + X(UnionType, 0x17) \ + X(UnspecifiedParameters, 0x18) \ + X(Variant, 0x19) \ + X(CommonBlock, 0x1a) \ + X(CommonInclusion, 0x1b) \ + X(Inheritance, 0x1c) \ + X(InlinedSubroutine, 0x1d) \ + X(Module, 0x1e) \ + X(PtrToMemberType, 0x1f) \ + X(SetType, 0x20) \ + X(SubrangeType, 0x21) \ + X(WithStmt, 0x22) \ + X(AccessDeclaration, 0x23) \ + X(BaseType, 0x24) \ + X(CatchBlock, 0x25) \ + X(ConstType, 0x26) \ + X(Constant, 0x27) \ + X(Enumerator, 0x28) \ + X(FileType, 0x29) \ + X(Friend, 0x2a) \ + X(NameList, 0x2b) \ + X(NameListItem, 0x2c) \ + X(PackedType, 0x2d) \ + X(SubProgram, 0x2e) \ + X(TemplateTypeParameter, 0x2f) \ + X(TemplateValueParameter, 0x30) \ + X(ThrownType, 0x31) \ + X(TryBlock, 0x32) \ + X(VariantPart, 0x33) \ + X(Variable, 0x34) \ + X(VolatileType, 0x35) \ + X(DwarfProcedure, 0x36) \ + X(RestrictType, 0x37) \ + X(InterfaceType, 0x38) \ + X(Namespace, 0x39) \ + X(ImportedModule, 0x3a) \ + X(UnspecifiedType, 0x3b) \ + X(PartialUnit, 0x3c) \ + X(ImportedUnit, 0x3d) \ + X(Condition, 0x3f) \ + X(SharedType, 0x40) + +#define DW_Tag_V5_XList(X) \ + X(TypeUnit, 0x41) \ + X(RValueReferenceType, 0x42) \ + X(TemplateAlias, 0x43) \ + X(CoarrayType, 0x44) \ + X(GenericSubrange, 0x45) \ + X(DynamicType, 0x46) \ + X(AtomicType, 0x47) \ + X(CallSite, 0x48) \ + X(CallSiteParameter, 0x49) \ + X(SkeletonUnit, 0x4A) \ + X(ImmutableType, 0x4B) + +#define DW_Tag_GNU_XList(X) \ + X(GNU_CallSite, 0x4109) \ + X(GNU_CallSiteParameter, 0x410a) + +typedef U64 DW_TagKind; +typedef enum DW_TagKindEnum +{ +#define X(_N,_ID) DW_Tag_##_N = _ID, + DW_Tag_V3_XList(X) + DW_Tag_V5_XList(X) + DW_Tag_GNU_XList(X) +#undef X + DW_Tag_UserLo = 0x4080, + DW_Tag_UserHi = 0xffff +} DW_TagKindEnum; + +//- Attrib Class Encodings + +#define DW_AttribClass_V3_XList(X) \ + X(Null, 0) \ + X(Undefined, 1) \ + X(Address, 2) \ + X(Block, 3) \ + X(Const, 4) \ + X(ExprLoc, 5) \ + X(Flag, 6) \ + X(LinePtr, 7) \ + X(LocListPtr, 8) \ + X(MacPtr, 9) \ + X(RngListPtr, 10) \ + X(Reference, 11) \ + X(String, 12) + +#define DW_AttribClass_V4_XList(X) \ + X(LocList, 13) \ + X(RngList, 14) + +#define DW_AttribClass_V5_XList(X) \ + X(StrOffsetsPtr, 15) \ + X(AddrPtr, 16) + +typedef U32 DW_AttribClass; +typedef enum DW_AttribClassEnum +{ +#define X(_N,_ID) DW_AttribClass_##_N = (1 << _ID), + DW_AttribClass_V3_XList(X) + DW_AttribClass_V4_XList(X) + DW_AttribClass_V5_XList(X) +#undef X +} DW_AttribClassEnum; + +//- Form Encodings + +#define DW_Form_V2_XList(X) \ + X(Addr, 0x1) \ + X(Block2, 0x3) \ + X(Block4, 0x4) \ + X(Data2, 0x5) \ + X(Data4, 0x6) \ + X(Data8, 0x7) \ + X(String, 0x8) \ + X(Block, 0x9) \ + X(Block1, 0xa) \ + X(Data1, 0xb) \ + X(Flag, 0xc) \ + X(SData, 0xd) \ + X(Strp, 0xe) \ + X(UData, 0xf) \ + X(RefAddr, 0x10) \ + X(Ref1, 0x11) \ + X(Ref2, 0x12) \ + X(Ref4, 0x13) \ + X(Ref8, 0x14) \ + X(RefUData, 0x15) \ + X(Indirect, 0x16) + +#define DW_Form_AttribClass_V2_XList(X) \ + X(Addr, DW_AttribClass_Address) \ + X(Block2, DW_AttribClass_Block) \ + X(Block4, DW_AttribClass_Block) \ + X(Data2, DW_AttribClass_Const) \ + X(Data4, DW_AttribClass_Const) \ + X(Data8, DW_AttribClass_Const) \ + X(String, DW_AttribClass_String) \ + X(Block, DW_AttribClass_Block) \ + X(Block1, DW_AttribClass_Block) \ + X(Data1, DW_AttribClass_Const) \ + X(Flag, DW_AttribClass_Flag) \ + X(SData, DW_AttribClass_Const) \ + X(Strp, DW_AttribClass_String) \ + X(UData, DW_AttribClass_Const) \ + X(RefAddr, DW_AttribClass_Reference) \ + X(Ref1, DW_AttribClass_Reference) \ + X(Ref2, DW_AttribClass_Reference) \ + X(Ref4, DW_AttribClass_Reference) \ + X(Ref8, DW_AttribClass_Reference) \ + X(RefUData, DW_AttribClass_Reference) \ + X(Indirect, DW_AttribClass_Null) + +#define DW_Form_V4_XList(X) \ + X(SecOffset, 0x17) \ + X(ExprLoc, 0x18) \ + X(FlagPresent, 0x19) \ + X(RefSig8, 0x20) + +#define DW_Form_AttribClass_V4_XList(X) \ + X(Addr, DW_AttribClass_Address) \ + X(Block2, DW_AttribClass_Block) \ + X(Block4, DW_AttribClass_Block) \ + X(Data2, DW_AttribClass_Const) \ + X(Data4, DW_AttribClass_Const) \ + X(Data8, DW_AttribClass_Const) \ + X(String, DW_AttribClass_String) \ + X(Block, DW_AttribClass_Block) \ + X(Block1, DW_AttribClass_Block) \ + X(Data1, DW_AttribClass_Const) \ + X(Flag, DW_AttribClass_Flag) \ + X(SData, DW_AttribClass_Const) \ + X(Strp, DW_AttribClass_String) \ + X(UData, DW_AttribClass_Const) \ + X(RefAddr, DW_AttribClass_Reference) \ + X(Ref1, DW_AttribClass_Reference) \ + X(Ref2, DW_AttribClass_Reference) \ + X(Ref4, DW_AttribClass_Reference) \ + X(Ref8, DW_AttribClass_Reference) \ + X(RefUData, DW_AttribClass_Reference) \ + X(Indirect, DW_AttribClass_Null) \ + X(SecOffset, DW_AttribClass_LinePtr|DW_AttribClass_LocListPtr|DW_AttribClass_MacPtr|DW_AttribClass_RngListPtr) \ + X(ExprLoc, DW_AttribClass_ExprLoc) \ + X(FlagPresent, DW_AttribClass_Flag) \ + X(RefSig8, DW_AttribClass_Reference) + +#define DW_Form_V5_XList(X) \ + X(Strx, 0x1a) \ + X(Addrx, 0x1b) \ + X(RefSup4, 0x1c) \ + X(StrpSup, 0x1d) \ + X(Data16, 0x1e) \ + X(LineStrp, 0x1f) \ + X(ImplicitConst, 0x21) \ + X(LocListx, 0x22) \ + X(RngListx, 0x23) \ + X(RefSup8, 0x24) \ + X(Strx1, 0x25) \ + X(Strx2, 0x26) \ + X(Strx3, 0x27) \ + X(Strx4, 0x28) \ + X(Addrx1, 0x29) \ + X(Addrx2, 0x2a) \ + X(Addrx3, 0x2b) \ + X(Addrx4, 0x2c) + +#define DW_Form_AttribClass_V5_XList(X) \ + X(Addr, DW_AttribClass_Address) \ + X(Block2, DW_AttribClass_Block) \ + X(Block4, DW_AttribClass_Block) \ + X(Data2, DW_AttribClass_Const) \ + X(Data4, DW_AttribClass_Const) \ + X(Data8, DW_AttribClass_Const) \ + X(String, DW_AttribClass_String) \ + X(Block, DW_AttribClass_Block) \ + X(Block1, DW_AttribClass_Block) \ + X(Data1, DW_AttribClass_Const) \ + X(Flag, DW_AttribClass_Flag) \ + X(SData, DW_AttribClass_Const) \ + X(Strp, DW_AttribClass_String) \ + X(UData, DW_AttribClass_Const) \ + X(RefAddr, DW_AttribClass_Reference) \ + X(Ref1, DW_AttribClass_Reference) \ + X(Ref2, DW_AttribClass_Reference) \ + X(Ref4, DW_AttribClass_Reference) \ + X(Ref8, DW_AttribClass_Reference) \ + X(RefUData, DW_AttribClass_Reference) \ + X(Indirect, DW_AttribClass_Null) \ + X(SecOffset, DW_AttribClass_AddrPtr| \ + DW_AttribClass_LinePtr| \ + DW_AttribClass_LocList| \ + DW_AttribClass_LocListPtr| \ + DW_AttribClass_MacPtr| \ + DW_AttribClass_RngList| \ + DW_AttribClass_RngListPtr| \ + DW_AttribClass_StrOffsetsPtr) \ + X(ExprLoc, DW_AttribClass_ExprLoc) \ + X(FlagPresent, DW_AttribClass_Flag) \ + X(RefSig8, DW_AttribClass_Reference) \ + X(Strx, DW_AttribClass_String) \ + X(Addrx, DW_AttribClass_Address) \ + X(RefSup4, DW_AttribClass_Reference) \ + X(StrpSup, DW_AttribClass_String) \ + X(Data16, DW_AttribClass_Const) \ + X(LineStrp, DW_AttribClass_String) \ + X(ImplicitConst, DW_AttribClass_Const) \ + X(LocListx, DW_AttribClass_LocListPtr) \ + X(RngListx, DW_AttribClass_RngListPtr) \ + X(RefSup8, DW_AttribClass_Reference) \ + X(Strx1, DW_AttribClass_String) \ + X(Strx2, DW_AttribClass_String) \ + X(Strx3, DW_AttribClass_String) \ + X(Strx4, DW_AttribClass_String) \ + X(Addrx1, DW_AttribClass_Address) \ + X(Addrx2, DW_AttribClass_Address) \ + X(Addrx3, DW_AttribClass_Address) \ + X(Addrx4, DW_AttribClass_Address) + +typedef U64 DW_FormKind; +typedef enum DW_FormEnum +{ + DW_Form_Null, +#define X(_N, _ID) DW_Form_##_N = _ID, + DW_Form_V2_XList(X) + DW_Form_V4_XList(X) + DW_Form_V5_XList(X) +#undef X +} DW_FormEnum; + +//- Attributes DWARF2 + +#define DW_AttribKind_V2_XList(X) \ + X(Sibling, 0x1) \ + X(Location, 0x2) \ + X(Name, 0x3) \ + X(Ordering, 0x9) \ + X(ByteSize, 0xB) \ + X(BitOffset, 0xC) \ + X(BitSize, 0xD) \ + X(StmtList, 0x10) \ + X(LowPc, 0x11) \ + X(HighPc, 0x12) \ + X(Language, 0x13) \ + X(Discr, 0x15) \ + X(DiscrValue, 0x16) \ + X(Visibility, 0x17) \ + X(Import, 0x18) \ + X(StringLength, 0x19) \ + X(CommonReference, 0x1a) \ + X(CompDir, 0x1b) \ + X(ConstValue, 0x1c) \ + X(ContainingType, 0x1d) \ + X(DefaultValue, 0x1e) \ + X(Inline, 0x20) \ + X(IsOptional, 0x21) \ + X(LowerBound, 0x22) \ + X(Producer, 0x25) \ + X(Prototyped, 0x27) \ + X(ReturnAddr, 0x2a) \ + X(StartScope, 0x2c) \ + X(BitStride, 0x2e) \ + X(UpperBound, 0x2f) \ + X(AbstractOrigin, 0x31) \ + X(Accessibility, 0x32) \ + X(AddressClass, 0x33) \ + X(Artificial, 0x34) \ + X(BaseTypes, 0x35) \ + X(CallingConvention, 0x36) \ + X(Count, 0x37) \ + X(DataMemberLocation, 0x38) \ + X(DeclColumn, 0x39) \ + X(DeclFile, 0x3a) \ + X(DeclLine, 0x3b) \ + X(Declaration, 0x3c) \ + X(DiscrList, 0x3d) \ + X(Encoding, 0x3e) \ + X(External, 0x3f) \ + X(FrameBase, 0x40) \ + X(Friend, 0x41) \ + X(IdentifierCase, 0x42) \ + X(MacroInfo, 0x43) \ + X(NameListItem, 0x44) \ + X(Priority, 0x45) \ + X(Segment, 0x46) \ + X(Specification, 0x47) \ + X(StaticLink, 0x48) \ + X(Type, 0x49) \ + X(UseLocation, 0x4a) \ + X(VariableParameter, 0x4b) \ + X(Virtuality, 0x4c) \ + X(VTableElemLocation, 0x4d) + +#define DW_AttribKind_ClassFlags_V2_XList(X) \ + X(Sibling, DW_AttribClass_Reference) \ + X(Location, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Name, DW_AttribClass_String) \ + X(Ordering, DW_AttribClass_Const) \ + X(ByteSize, DW_AttribClass_Const) \ + X(BitOffset, DW_AttribClass_Const) \ + X(BitSize, DW_AttribClass_Const) \ + X(StmtList, DW_AttribClass_Const) \ + X(LowPc, DW_AttribClass_Address) \ + X(HighPc, DW_AttribClass_Address) \ + X(Language, DW_AttribClass_Const) \ + X(Discr, DW_AttribClass_Reference) \ + X(DiscrValue, DW_AttribClass_Const) \ + X(Visibility, DW_AttribClass_Const) \ + X(Import, DW_AttribClass_Reference) \ + X(StringLength, DW_AttribClass_Block|DW_AttribClass_Const) \ + X(CommonReference, DW_AttribClass_Reference) \ + X(CompDir, DW_AttribClass_String) \ + X(ConstValue, DW_AttribClass_String|DW_AttribClass_Const|DW_AttribClass_Block) \ + X(ContainingType, DW_AttribClass_Reference) \ + X(DefaultValue, DW_AttribClass_Reference) \ + X(Inline, DW_AttribClass_Const) \ + X(IsOptional, DW_AttribClass_Flag) \ + X(LowerBound, DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(Producer, DW_AttribClass_String) \ + X(Prototyped, DW_AttribClass_Flag) \ + X(ReturnAddr, DW_AttribClass_Block|DW_AttribClass_Const) \ + X(StartScope, DW_AttribClass_Const) \ + X(BitStride, DW_AttribClass_Const) /* dwarf-v1 DW_Attrib_stride_size*/ \ + X(UpperBound, DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(AbstractOrigin, DW_AttribClass_Reference) \ + X(Accessibility, DW_AttribClass_Const) \ + X(AddressClass, DW_AttribClass_Const) \ + X(Artificial, DW_AttribClass_Flag) \ + X(BaseTypes, DW_AttribClass_Reference) \ + X(CallingConvention, DW_AttribClass_Const) \ + X(Count, DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(DataMemberLocation, DW_AttribClass_Block|DW_AttribClass_Reference) \ + X(DeclColumn, DW_AttribClass_Const) \ + X(DeclFile, DW_AttribClass_Const) \ + X(DeclLine, DW_AttribClass_Const) \ + X(Declaration, DW_AttribClass_Flag) \ + X(DiscrList, DW_AttribClass_Block) \ + X(Encoding, DW_AttribClass_Const) \ + X(External, DW_AttribClass_Flag) \ + X(FrameBase, DW_AttribClass_Block|DW_AttribClass_Const) \ + X(Friend, DW_AttribClass_Reference) \ + X(IdentifierCase, DW_AttribClass_Const) \ + X(MacroInfo, DW_AttribClass_Const) \ + X(NameListItem, DW_AttribClass_Block) \ + X(Priority, DW_AttribClass_Reference) \ + X(Segment, DW_AttribClass_Block|DW_AttribClass_Const) \ + X(Specification, DW_AttribClass_Reference) \ + X(StaticLink, DW_AttribClass_Block|DW_AttribClass_Const) \ + X(Type, DW_AttribClass_Reference) \ + X(UseLocation, DW_AttribClass_Block|DW_AttribClass_Const) \ + X(VariableParameter, DW_AttribClass_Flag) \ + X(Virtuality, DW_AttribClass_Const) \ + X(VTableElemLocation, DW_AttribClass_Block|DW_AttribClass_Reference) + +//- Attributes DWARF3 + +#define DW_AttribKind_V3_XList(X) \ + X(Allocated, 0x4e) \ + X(Associated, 0x4f) \ + X(DataLocation, 0x50) \ + X(ByteStride, 0x51) \ + X(EntryPc, 0x52) \ + X(UseUtf8, 0x53) \ + X(Extension, 0x54) \ + X(Ranges, 0x55) \ + X(Trampoline, 0x56) \ + X(CallColumn, 0x57) \ + X(CallFile, 0x58) \ + X(CallLine, 0x59) \ + X(Description, 0x5a) \ + X(BinaryScale, 0x5b) \ + X(DecimalScale, 0x5c) \ + X(Small, 0x5d) \ + X(DecimalSign, 0x5e) \ + X(DigitCount, 0x5f) \ + X(PictureString, 0x60) \ + X(Mutable, 0x61) \ + X(ThreadsScaled, 0x62) \ + X(Explicit, 0x63) \ + X(ObjectPointer, 0x64) \ + X(Endianity, 0x65) \ + X(Elemental, 0x66) \ + X(Pure, 0x67) \ + X(Recursive, 0x68) + +#define DW_AttribKind_ClassFlags_V3_XList(X) \ + X(Sibling, DW_AttribClass_Reference) \ + X(Location, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(Name, DW_AttribClass_String) \ + X(Ordering, DW_AttribClass_Const) \ + X(ByteSize, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(BitOffset, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(BitSize, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(StmtList, DW_AttribClass_LinePtr) \ + X(LowPc, DW_AttribClass_Address) \ + X(HighPc, DW_AttribClass_Address) \ + X(Language, DW_AttribClass_Const) \ + X(Discr, DW_AttribClass_Reference) \ + X(DiscrValue, DW_AttribClass_Const) \ + X(Visibility, DW_AttribClass_Const) \ + X(Import, DW_AttribClass_Reference) \ + X(StringLength, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(CommonReference, DW_AttribClass_Reference) \ + X(CompDir, DW_AttribClass_String) \ + X(ConstValue, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_String) \ + X(ContainingType, DW_AttribClass_Reference) \ + X(DefaultValue, DW_AttribClass_Reference) \ + X(Inline, DW_AttribClass_Const) \ + X(IsOptional, DW_AttribClass_Flag) \ + X(LowerBound, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(Producer, DW_AttribClass_String) \ + X(Prototyped, DW_AttribClass_Flag) \ + X(ReturnAddr, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(StartScope, DW_AttribClass_Const) \ + X(BitStride, DW_AttribClass_Const) \ + X(UpperBound, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(AbstractOrigin, DW_AttribClass_Reference) \ + X(Accessibility, DW_AttribClass_Const) \ + X(AddressClass, DW_AttribClass_Const) \ + X(Artificial, DW_AttribClass_Flag) \ + X(BaseTypes, DW_AttribClass_Reference) \ + X(CallingConvention, DW_AttribClass_Const) \ + X(Count, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(DataMemberLocation, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_LocListPtr) \ + X(DeclColumn, DW_AttribClass_Const) \ + X(DeclFile, DW_AttribClass_Const) \ + X(DeclLine, DW_AttribClass_Const) \ + X(Declaration, DW_AttribClass_Flag) \ + X(DiscrList, DW_AttribClass_Block) \ + X(Encoding, DW_AttribClass_Const) \ + X(External, DW_AttribClass_Flag) \ + X(FrameBase, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(Friend, DW_AttribClass_Reference) \ + X(IdentifierCase, DW_AttribClass_Const) \ + X(MacroInfo, DW_AttribClass_MacPtr) \ + X(NameListItem, DW_AttribClass_Block) \ + X(Priority, DW_AttribClass_Reference) \ + X(Segment, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(Specification, DW_AttribClass_Reference) \ + X(StaticLink, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(Type, DW_AttribClass_Reference) \ + X(UseLocation, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(VariableParameter, DW_AttribClass_Flag) \ + X(Virtuality, DW_AttribClass_Const) \ + X(VTableElemLocation, DW_AttribClass_Block|DW_AttribClass_LocListPtr) \ + X(Allocated, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(Associated, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(DataLocation, DW_AttribClass_Block) \ + X(ByteStride, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_Reference) \ + X(EntryPc, DW_AttribClass_Address) \ + X(UseUtf8, DW_AttribClass_Flag) \ + X(Extension, DW_AttribClass_Reference) \ + X(Ranges, DW_AttribClass_RngListPtr) \ + X(Trampoline, DW_AttribClass_Address|DW_AttribClass_Flag|DW_AttribClass_Reference|DW_AttribClass_String) \ + X(CallColumn, DW_AttribClass_Const) \ + X(CallFile, DW_AttribClass_Const) \ + X(CallLine, DW_AttribClass_Const) \ + X(Description, DW_AttribClass_String) \ + X(BinaryScale, DW_AttribClass_Const) \ + X(DecimalScale, DW_AttribClass_Const) \ + X(Small, DW_AttribClass_Reference) \ + X(DecimalSign, DW_AttribClass_Const) \ + X(DigitCount, DW_AttribClass_Const) \ + X(PictureString, DW_AttribClass_String) \ + X(Mutable, DW_AttribClass_Flag) \ + X(ThreadsScaled, DW_AttribClass_Flag) \ + X(Explicit, DW_AttribClass_Flag) \ + X(ObjectPointer, DW_AttribClass_Reference) \ + X(Endianity, DW_AttribClass_Const) \ + X(Elemental, DW_AttribClass_Flag) \ + X(Pure, DW_AttribClass_Flag) \ + X(Recursive, DW_AttribClass_Flag) + +//- Attributes DWARF4 + +#define DW_AttribKind_V4_XList(X) \ + X(Signature, 0x69) \ + X(MainSubProgram, 0x6a) \ + X(DataBitOffset, 0x6b) \ + X(ConstExpr, 0x6c) \ + X(EnumClass, 0x6d) \ + X(LinkageName, 0x6e) + +#define DW_AttribKind_ClassFlags_V4_XList(X) \ + X(Sibling, DW_AttribClass_Reference) \ + X(Location, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Name, DW_AttribClass_String) \ + X(Ordering, DW_AttribClass_Const) \ + X(ByteSize, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(BitOffset, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(BitSize, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(StmtList, DW_AttribClass_LinePtr) \ + X(LowPc, DW_AttribClass_Address) \ + X(HighPc, DW_AttribClass_Address|DW_AttribClass_Const) \ + X(Language, DW_AttribClass_Const) \ + X(Discr, DW_AttribClass_Reference) \ + X(DiscrValue, DW_AttribClass_Const) \ + X(Visibility, DW_AttribClass_Const) \ + X(Import, DW_AttribClass_Reference) \ + X(StringLength, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(CommonReference, DW_AttribClass_Reference) \ + X(CompDir, DW_AttribClass_String) \ + X(ConstValue, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_String) \ + X(ContainingType, DW_AttribClass_Reference) \ + X(DefaultValue, DW_AttribClass_Reference) \ + X(Inline, DW_AttribClass_Const) \ + X(IsOptional, DW_AttribClass_Flag) \ + X(LowerBound, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(Producer, DW_AttribClass_String) \ + X(Prototyped, DW_AttribClass_Flag) \ + X(ReturnAddr, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(StartScope, DW_AttribClass_Const|DW_AttribClass_RngListPtr) \ + X(BitStride, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(UpperBound, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(AbstractOrigin, DW_AttribClass_Reference) \ + X(Accessibility, DW_AttribClass_Const) \ + X(AddressClass, DW_AttribClass_Const) \ + X(Artificial, DW_AttribClass_Flag) \ + X(BaseTypes, DW_AttribClass_Reference) \ + X(CallingConvention, DW_AttribClass_Const) \ + X(Count, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(DataMemberLocation, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(DeclColumn, DW_AttribClass_Const) \ + X(DeclFile, DW_AttribClass_Const) \ + X(DeclLine, DW_AttribClass_Const) \ + X(Declaration, DW_AttribClass_Flag) \ + X(DiscrList, DW_AttribClass_Block) \ + X(Encoding, DW_AttribClass_Const) \ + X(External, DW_AttribClass_Flag) \ + X(FrameBase, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Friend, DW_AttribClass_Reference) \ + X(IdentifierCase, DW_AttribClass_Const) \ + X(MacroInfo, DW_AttribClass_MacPtr) \ + X(NameListItem, DW_AttribClass_Reference) \ + X(Priority, DW_AttribClass_Reference) \ + X(Segment, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Specification, DW_AttribClass_Reference) \ + X(StaticLink, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Type, DW_AttribClass_Reference) \ + X(UseLocation, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(VariableParameter, DW_AttribClass_Flag) \ + X(Virtuality, DW_AttribClass_Const) \ + X(VTableElemLocation, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Allocated, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(Associated, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(DataLocation, DW_AttribClass_ExprLoc) \ + X(ByteStride, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(EntryPc, DW_AttribClass_Address) \ + X(UseUtf8, DW_AttribClass_Flag) \ + X(Extension, DW_AttribClass_Reference) \ + X(Ranges, DW_AttribClass_RngListPtr) \ + X(Trampoline, DW_AttribClass_Address|DW_AttribClass_Flag|DW_AttribClass_Reference|DW_AttribClass_String) \ + X(CallColumn, DW_AttribClass_Const) \ + X(CallFile, DW_AttribClass_Const) \ + X(CallLine, DW_AttribClass_Const) \ + X(Description, DW_AttribClass_String) \ + X(BinaryScale, DW_AttribClass_Const) \ + X(DecimalScale, DW_AttribClass_Const) \ + X(Small, DW_AttribClass_Reference) \ + X(DecimalSign, DW_AttribClass_Const) \ + X(DigitCount, DW_AttribClass_Const) \ + X(PictureString, DW_AttribClass_String) \ + X(Mutable, DW_AttribClass_Flag) \ + X(ThreadsScaled, DW_AttribClass_Flag) \ + X(Explicit, DW_AttribClass_Flag) \ + X(ObjectPointer, DW_AttribClass_Reference) \ + X(Endianity, DW_AttribClass_Const) \ + X(Elemental, DW_AttribClass_Flag) \ + X(Pure, DW_AttribClass_Flag) \ + X(Recursive, DW_AttribClass_Flag) \ + X(Signature, DW_AttribClass_Reference) \ + X(MainSubProgram, DW_AttribClass_Flag) \ + X(DataBitOffset, DW_AttribClass_Const) \ + X(ConstExpr, DW_AttribClass_Flag) \ + X(EnumClass, DW_AttribClass_Flag) \ + X(LinkageName, DW_AttribClass_String) + +//- Attributes DWARF5 + +#define DW_AttribKind_V5_XList(X) \ + X(StringLengthBitSize, 0x6f) \ + X(StringLengthByteSize, 0x70) \ + X(Rank, 0x71) \ + X(StrOffsetsBase, 0x72) \ + X(AddrBase, 0x73) \ + X(RngListsBase, 0x74) \ + X(DwoName, 0x76) \ + X(Reference, 0x77) \ + X(RValueReference, 0x78) \ + X(Macros, 0x79) \ + X(CallAllCalls, 0x7a) \ + X(CallAllSourceCalls, 0x7b) \ + X(CallAllTailCalls, 0x7c) \ + X(CallReturnPc, 0x7d) \ + X(CallValue, 0x7e) \ + X(CallOrigin, 0x7f) \ + X(CallParameter, 0x80) \ + X(CallPc, 0x81) \ + X(CallTailCall, 0x82) \ + X(CallTarget, 0x83) \ + X(CallTargetClobbered, 0x84) \ + X(CallDataLocation, 0x85) \ + X(CallDataValue, 0x86) \ + X(NoReturn, 0x87) \ + X(Alignment, 0x88) \ + X(ExportSymbols, 0x89) \ + X(Deleted, 0x8a) \ + X(Defaulted, 0x8b) \ + X(LocListsBase, 0x8c) + +#define DW_AttribKind_ClassFlags_V5_XList(X) \ + X(Sibling, DW_AttribClass_Reference) \ + X(Location, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(Name, DW_AttribClass_String) \ + X(Ordering, DW_AttribClass_Const) \ + X(ByteSize, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(BitOffset, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(BitSize, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(StmtList, DW_AttribClass_LinePtr) \ + X(LowPc, DW_AttribClass_Address) \ + X(HighPc, DW_AttribClass_Address|DW_AttribClass_Const) \ + X(Language, DW_AttribClass_Const) \ + X(Discr, DW_AttribClass_Reference) \ + X(DiscrValue, DW_AttribClass_Const) \ + X(Visibility, DW_AttribClass_Const) \ + X(Import, DW_AttribClass_Reference) \ + X(StringLength, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(CommonReference, DW_AttribClass_Reference) \ + X(CompDir, DW_AttribClass_String) \ + X(ConstValue, DW_AttribClass_Block|DW_AttribClass_Const|DW_AttribClass_String) \ + X(ContainingType, DW_AttribClass_Reference) \ + X(DefaultValue, DW_AttribClass_Reference) \ + X(Inline, DW_AttribClass_Const) \ + X(IsOptional, DW_AttribClass_Flag) \ + X(LowerBound, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(Producer, DW_AttribClass_String) \ + X(Prototyped, DW_AttribClass_Flag) \ + X(ReturnAddr, DW_AttribClass_ExprLoc|DW_AttribClass_LocListPtr) \ + X(StartScope, DW_AttribClass_Const|DW_AttribClass_RngListPtr) \ + X(BitStride, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(UpperBound, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(AbstractOrigin, DW_AttribClass_Reference) \ + X(Accessibility, DW_AttribClass_Const) \ + X(AddressClass, DW_AttribClass_Const) \ + X(Artificial, DW_AttribClass_Flag) \ + X(BaseTypes, DW_AttribClass_Reference) \ + X(CallingConvention, DW_AttribClass_Const) \ + X(Count, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(DataMemberLocation, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_LocList) \ + X(DeclColumn, DW_AttribClass_Const) \ + X(DeclFile, DW_AttribClass_Const) \ + X(DeclLine, DW_AttribClass_Const) \ + X(Declaration, DW_AttribClass_Flag) \ + X(DiscrList, DW_AttribClass_Block) \ + X(Encoding, DW_AttribClass_Const) \ + X(External, DW_AttribClass_Flag) \ + X(FrameBase, DW_AttribClass_ExprLoc|DW_AttribClass_LocList) \ + X(Friend, DW_AttribClass_Reference) \ + X(IdentifierCase, DW_AttribClass_Const) \ + X(MacroInfo, DW_AttribClass_MacPtr) \ + X(NameListItem, DW_AttribClass_Reference) \ + X(Priority, DW_AttribClass_Reference) \ + X(Segment, DW_AttribClass_ExprLoc|DW_AttribClass_LocList) \ + X(Specification, DW_AttribClass_Reference) \ + X(StaticLink, DW_AttribClass_ExprLoc|DW_AttribClass_LocList) \ + X(Type, DW_AttribClass_Reference) \ + X(UseLocation, DW_AttribClass_ExprLoc|DW_AttribClass_LocList) \ + X(VariableParameter, DW_AttribClass_Flag) \ + X(Virtuality, DW_AttribClass_Const) \ + X(VTableElemLocation, DW_AttribClass_ExprLoc|DW_AttribClass_LocList) \ + X(Allocated, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(Associated, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(DataLocation, DW_AttribClass_ExprLoc) \ + X(ByteStride, DW_AttribClass_Const|DW_AttribClass_ExprLoc|DW_AttribClass_Reference) \ + X(EntryPc, DW_AttribClass_Address|DW_AttribClass_Const) \ + X(UseUtf8, DW_AttribClass_Flag) \ + X(Extension, DW_AttribClass_Reference) \ + X(Ranges, DW_AttribClass_RngList) \ + X(Trampoline, DW_AttribClass_Address|DW_AttribClass_Flag|DW_AttribClass_Reference|DW_AttribClass_String) \ + X(CallColumn, DW_AttribClass_Const) \ + X(CallFile, DW_AttribClass_Const) \ + X(CallLine, DW_AttribClass_Const) \ + X(Description, DW_AttribClass_String) \ + X(BinaryScale, DW_AttribClass_Const) \ + X(DecimalScale, DW_AttribClass_Const) \ + X(Small, DW_AttribClass_Reference) \ + X(DecimalSign, DW_AttribClass_Const) \ + X(DigitCount, DW_AttribClass_Const) \ + X(PictureString, DW_AttribClass_String) \ + X(Mutable, DW_AttribClass_Flag) \ + X(ThreadsScaled, DW_AttribClass_Flag) \ + X(Explicit, DW_AttribClass_Flag) \ + X(ObjectPointer, DW_AttribClass_Reference) \ + X(Endianity, DW_AttribClass_Const) \ + X(Elemental, DW_AttribClass_Flag) \ + X(Pure, DW_AttribClass_Flag) \ + X(Recursive, DW_AttribClass_Flag) \ + X(Signature, DW_AttribClass_Reference) \ + X(MainSubProgram, DW_AttribClass_Flag) \ + X(DataBitOffset, DW_AttribClass_Const) \ + X(ConstExpr, DW_AttribClass_Flag) \ + X(EnumClass, DW_AttribClass_Flag) \ + X(LinkageName, DW_AttribClass_String) \ + X(StringLengthBitSize, DW_AttribClass_Const) \ + X(StringLengthByteSize, DW_AttribClass_Const) \ + X(Rank, DW_AttribClass_Const|DW_AttribClass_ExprLoc) \ + X(StrOffsetsBase, DW_AttribClass_StrOffsetsPtr) \ + X(AddrBase, DW_AttribClass_AddrPtr) \ + X(RngListsBase, DW_AttribClass_RngListPtr) \ + X(DwoName, DW_AttribClass_String) \ + X(Reference, DW_AttribClass_Flag) \ + X(RValueReference, DW_AttribClass_Flag) \ + X(Macros, DW_AttribClass_MacPtr) \ + X(CallAllCalls, DW_AttribClass_Flag) \ + X(CallAllSourceCalls, DW_AttribClass_Flag) \ + X(CallAllTailCalls, DW_AttribClass_Flag) \ + X(CallReturnPc, DW_AttribClass_Address) \ + X(CallValue, DW_AttribClass_ExprLoc) \ + X(CallOrigin, DW_AttribClass_ExprLoc) \ + X(CallParameter, DW_AttribClass_Reference) \ + X(CallPc, DW_AttribClass_Address) \ + X(CallTailCall, DW_AttribClass_Flag) \ + X(CallTarget, DW_AttribClass_ExprLoc) \ + X(CallTargetClobbered, DW_AttribClass_ExprLoc) \ + X(CallDataLocation, DW_AttribClass_ExprLoc) \ + X(CallDataValue, DW_AttribClass_ExprLoc) \ + X(NoReturn, DW_AttribClass_Flag) \ + X(Alignment, DW_AttribClass_Const) \ + X(ExportSymbols, DW_AttribClass_Flag) \ + X(Deleted, DW_AttribClass_Flag) \ + X(Defaulted, DW_AttribClass_Const) \ + X(LocListsBase, DW_AttribClass_LocListPtr) + +//- Attributes GNU + +#define DW_AttribKind_GNU_XList(X) \ + X(GNU_Vector, 0x2107) \ + X(GNU_GuardedBy, 0x2108) \ + X(GNU_PtGuardedBy, 0x2109) \ + X(GNU_Guarded, 0x210a) \ + X(GNU_PtGuarded, 0x210b) \ + X(GNU_LocksExcluded, 0x210c) \ + X(GNU_ExclusiveLocksRequired, 0x210d) \ + X(GNU_SharedLocksRequired, 0x210e) \ + X(GNU_OdrSignature, 0x210f) \ + X(GNU_TemplateName, 0x2110) \ + X(GNU_CallSiteValue, 0x2111) \ + X(GNU_CallSiteDataValue, 0x2112) \ + X(GNU_CallSiteTarget, 0x2113) \ + X(GNU_CallSiteTargetClobbered, 0x2114) \ + X(GNU_TailCall, 0x2115) \ + X(GNU_AllTailCallsSites, 0x2116) \ + X(GNU_AllCallSites, 0x2117) \ + X(GNU_AllSourceCallSites, 0x2118) \ + X(GNU_Macros, 0x2119) \ + X(GNU_Deleted, 0x211a) \ + X(GNU_DwoName, 0x2130) \ + X(GNU_DwoId, 0x2131) \ + X(GNU_RangesBase, 0x2132) \ + X(GNU_AddrBase, 0x2133) \ + X(GNU_PubNames, 0x2134) \ + X(GNU_PubTypes, 0x2135) \ + X(GNU_Discriminator, 0x2136) \ + X(GNU_LocViews, 0x2137) \ + X(GNU_EntryView, 0x2138) \ + X(GNU_DescriptiveType, 0x2302) \ + X(GNU_Numerator, 0x2303) \ + X(GNU_Denominator, 0x2304) \ + X(GNU_Bias, 0x2305) + +#define DW_AttribKind_ClassFlags_GNU_XList(X) \ + X(GNU_Vector, DW_AttribClass_Flag) \ + X(GNU_GuardedBy, DW_AttribClass_Undefined) \ + X(GNU_PtGuardedBy, DW_AttribClass_Undefined) \ + X(GNU_Guarded, DW_AttribClass_Undefined) \ + X(GNU_PtGuarded, DW_AttribClass_Undefined) \ + X(GNU_LocksExcluded, DW_AttribClass_Undefined) \ + X(GNU_ExclusiveLocksRequired, DW_AttribClass_Undefined) \ + X(GNU_SharedLocksRequired, DW_AttribClass_Undefined) \ + X(GNU_OdrSignature, DW_AttribClass_Undefined) \ + X(GNU_TemplateName, DW_AttribClass_Undefined) \ + X(GNU_CallSiteValue, DW_AttribClass_ExprLoc) \ + X(GNU_CallSiteDataValue, DW_AttribClass_ExprLoc) \ + X(GNU_CallSiteTarget, DW_AttribClass_ExprLoc) \ + X(GNU_CallSiteTargetClobbered, DW_AttribClass_ExprLoc) \ + X(GNU_TailCall, DW_AttribClass_Flag) \ + X(GNU_AllTailCallsSites, DW_AttribClass_Flag) \ + X(GNU_AllCallSites, DW_AttribClass_Flag) \ + X(GNU_AllSourceCallSites, DW_AttribClass_Flag) \ + X(GNU_Macros, DW_AttribClass_Flag) \ + X(GNU_Deleted, DW_AttribClass_Undefined) \ + X(GNU_DwoName, DW_AttribClass_String) \ + X(GNU_DwoId, DW_AttribClass_Const) \ + X(GNU_RangesBase, DW_AttribClass_Undefined) \ + X(GNU_AddrBase, DW_AttribClass_AddrPtr) \ + X(GNU_PubNames, DW_AttribClass_Flag) \ + X(GNU_PubTypes, DW_AttribClass_Undefined) \ + X(GNU_Discriminator, DW_AttribClass_Const) \ + X(GNU_LocViews, DW_AttribClass_Undefined) \ + X(GNU_EntryView, DW_AttribClass_Undefined) \ + X(GNU_DescriptiveType, DW_AttribClass_Undefined) \ + X(GNU_Numerator, DW_AttribClass_Undefined) \ + X(GNU_Denominator, DW_AttribClass_Undefined) \ + X(GNU_Bias, DW_AttribClass_Undefined) + +//- Attributes LLVM + +#define DW_AttribKind_LLVM_XList(X) \ + X(LLVM_IncludePath, 0x3e00) \ + X(LLVM_ConfigMacros, 0x3e01) \ + X(LLVM_SysRoot, 0x3e02) \ + X(LLVM_TagOffset, 0x3e03) \ + X(LLVM_ApiNotes, 0x3e07) + +#define DW_AttribKind_ClassFlags_LLVM_XList(X) \ + X(LLVM_IncludePath, DW_AttribClass_String) \ + X(LLVM_ConfigMacros, DW_AttribClass_String) \ + X(LLVM_SysRoot, DW_AttribClass_String) \ + X(LLVM_TagOffset, DW_AttribClass_Undefined) \ + X(LLVM_ApiNotes, DW_AttribClass_String) + +//- Attributes Apple + +#define DW_AttribKind_APPLE_XList(X) \ + X(APPLE_Optimized, 0x3fe1) \ + X(APPLE_Flags, 0x3fe2) \ + X(APPLE_Isa, 0x3fe3) \ + X(APPLE_Block, 0x3fe4) \ + X(APPLE_MajorRuntimeVers, 0x3fe5) \ + X(APPLE_RuntimeClass, 0x3fe6) \ + X(APPLE_OmitFramePtr, 0x3fe7) \ + X(APPLE_PropertyName, 0x3fe8) \ + X(APPLE_PropertyGetter, 0x3fe9) \ + X(APPLE_PropertySetter, 0x3fea) \ + X(APPLE_PropertyAttribute, 0x3feb) \ + X(APPLE_ObjcCompleteType, 0x3fec) \ + X(APPLE_Property, 0x3fed) \ + X(APPLE_ObjDirect, 0x3fee) \ + X(APPLE_Sdk, 0x3fef) + +#define DW_AttribKind_ClassFlags_APPLE_XList(X) \ + X(APPLE_Optimized, DW_AttribClass_Flag) \ + X(APPLE_Flags, DW_AttribClass_Flag) \ + X(APPLE_Isa, DW_AttribClass_Flag) \ + X(APPLE_Block, DW_AttribClass_Undefined) \ + X(APPLE_MajorRuntimeVers, DW_AttribClass_Undefined) \ + X(APPLE_RuntimeClass, DW_AttribClass_Undefined) \ + X(APPLE_OmitFramePtr, DW_AttribClass_Flag) \ + X(APPLE_PropertyName, DW_AttribClass_Undefined) \ + X(APPLE_PropertyGetter, DW_AttribClass_Undefined) \ + X(APPLE_PropertySetter, DW_AttribClass_Undefined) \ + X(APPLE_PropertyAttribute, DW_AttribClass_Undefined) \ + X(APPLE_ObjcCompleteType, DW_AttribClass_Undefined) \ + X(APPLE_Property, DW_AttribClass_Undefined) \ + X(APPLE_ObjDirect, DW_AttribClass_Undefined) \ + X(APPLE_Sdk, DW_AttribClass_String) + +//- Attributes MIPS + +#define DW_AttribKind_MIPS_XList(X) \ + X(MIPS_Fde, 0x2001) \ + X(MIPS_LoopBegin, 0x2002) \ + X(MIPS_TailLoopBegin, 0x2003) \ + X(MIPS_EpilogBegin, 0x2004) \ + X(MIPS_LoopUnrollFactor, 0x2005) \ + X(MIPS_SoftwarePipelineDepth, 0x2006) \ + X(MIPS_LinkageName, 0x2007) \ + X(MIPS_Stride, 0x2008) \ + X(MIPS_AbstractName, 0x2009) \ + X(MIPS_CloneOrigin, 0x200a) \ + X(MIPS_HasInlines, 0x200b) \ + X(MIPS_StrideByte, 0x200c) \ + X(MIPS_StrideElem, 0x200d) \ + X(MIPS_PtrDopeType, 0x200e) \ + X(MIPS_AllocatableDopeType, 0x200f) \ + X(MIPS_AssumedShapeDopeType, 0x2010) \ + X(MIPS_AssumedSize, 0x2011) + +#define DW_AttribKind_ClassFlags_MIPS_XList(X) \ + X(MIPS_Fde, DW_AttribClass_Block) \ + X(MIPS_LoopBegin, DW_AttribClass_Block) \ + X(MIPS_TailLoopBegin, DW_AttribClass_Block) \ + X(MIPS_EpilogBegin, DW_AttribClass_Block) \ + X(MIPS_LoopUnrollFactor, DW_AttribClass_Block) \ + X(MIPS_SoftwarePipelineDepth, DW_AttribClass_Block) \ + X(MIPS_LinkageName, DW_AttribClass_String) \ + X(MIPS_Stride, DW_AttribClass_Block) \ + X(MIPS_AbstractName, DW_AttribClass_String) \ + X(MIPS_CloneOrigin, DW_AttribClass_String) \ + X(MIPS_HasInlines, DW_AttribClass_Reference) \ + X(MIPS_StrideByte, DW_AttribClass_Reference) \ + X(MIPS_StrideElem, DW_AttribClass_Reference) \ + X(MIPS_PtrDopeType, DW_AttribClass_Reference) \ + X(MIPS_AllocatableDopeType, DW_AttribClass_Reference) \ + X(MIPS_AssumedShapeDopeType, DW_AttribClass_Reference) \ + X(MIPS_AssumedSize, DW_AttribClass_Reference) + +typedef U32 DW_AttribKind; +typedef enum DW_AttribKindEnum +{ + DW_Attrib_Null, +#define X(_N,_ID,...) DW_Attrib_##_N = _ID, + DW_AttribKind_V2_XList(X) + DW_AttribKind_V3_XList(X) + DW_AttribKind_V4_XList(X) + DW_AttribKind_V5_XList(X) + DW_AttribKind_GNU_XList(X) + DW_AttribKind_LLVM_XList(X) + DW_AttribKind_APPLE_XList(X) + DW_AttribKind_MIPS_XList(X) +#undef X + DW_Attrib_UserLo = 0x2000, + DW_Attrib_UserHi = 0x3fff +} DW_AttribKindEnum; + +#define DW_AttribTypeEncodingKind_XList(X) \ + X(Null, 0x00) \ + X(Address, 0x01) \ + X(Boolean, 0x02) \ + X(ComplexFloat, 0x03) \ + X(Float, 0x04) \ + X(Signed, 0x05) \ + X(SignedChar, 0x06) \ + X(Unsigned, 0x07) \ + X(UnsignedChar, 0x08) \ + X(ImaginaryFloat, 0x09) \ + X(PackedDecimal, 0x0A) \ + X(NumericString, 0x0B) \ + X(Edited, 0x0C) \ + X(SignedFixed, 0x0D) \ + X(UnsignedFixed, 0x0E) \ + X(DecimalFloat, 0x0F) \ + X(Utf, 0x10) \ + X(Ucs, 0x11) \ + X(Ascii, 0x12) + +typedef U64 DW_AttribTypeEncodingKind; +typedef enum DW_AttribTypeEncodingKindEnum +{ +#define X(_N,_ID) DW_AttribTypeEncodingKind_##_N = _ID, + DW_AttribTypeEncodingKind_XList(X) +#undef X +} DW_AttribTypeEncodingKindEnum; + +#define DW_CallingConventionKind_XList(X) \ + X(DW_CallingConvention_Normal, 0x0) \ + X(DW_CallingConvention_Program, 0x1) \ + X(DW_CallingConvention_NoCall, 0x2) \ + X(DW_CallingConvention_PassByValue, 0x1) \ + X(DW_CallingConvention_PassByReference, 0x2) + +typedef U64 DW_CallingConventionKind; +typedef enum DW_CallingConventionKindEnum +{ +#define X(_N,_ID) DW_CallingConventionKind_##_N = _ID, + DW_CallingConventionKind_XList(X) +#undef X +} DW_CallingConventionKindEnum; + +#define DW_AccessKind_XList(X) \ + X(DW_Access_Public, 0x00) \ + X(DW_Access_Private, 0x01) \ + X(DW_Access_Protected, 0x02) + +typedef U64 DW_AccessKind; +typedef enum DW_AccessKindEnum +{ +#define X(_N,_ID) DW_AccessKind_##_N = _ID, + DW_AccessKind_XList(X) +#undef X +} DW_AccessKindEnum; + +#define DW_VirtualityKind_XList(X) \ + X(None, 0x00) \ + X(Virtual, 0x01) \ + X(PureVirtual, 0x02) + +typedef U64 DW_VirtualityKind; +typedef enum DW_VirtualityEnum +{ +#define X(_N,_ID) DW_VirtualityKind_##_N = _ID, + DW_VirtualityKind_XList(X) +#undef X +} DW_VirtualityEnum; + +#define DW_RngListEntryKind(X) \ + X(EndOfList, 0x00) \ + X(BaseAddressX, 0x01) \ + X(StartxEndx, 0x02) \ + X(StartxLength, 0x03) \ + X(OffsetPair, 0x04) \ + X(BaseAddress, 0x05) \ + X(StartEnd, 0x06) \ + X(StartLength, 0x07) + +typedef U64 DW_RngListEntryKind; +typedef enum DW_RngListEntryKindEnum +{ +#define X(_N,_ID) DW_RngListEntryKind_##_N = _ID, + DW_RngListEntryKind(X) +#undef X +} DW_RngListEntryKindEnum; + +#define DW_LocListEntry_XList(X) \ + X(EndOfList, 0x00) \ + X(BaseAddressX, 0x01) \ + X(StartXEndX, 0x02) \ + X(StartXLength, 0x03) \ + X(OffsetPair, 0x04) \ + X(DefaultLocation, 0x05) \ + X(BaseAddress, 0x06) \ + X(StartEnd, 0x07) \ + X(StartLength, 0x08) + +typedef U64 DW_LocListEntryKind; +typedef enum DW_LocListEntryEnum +{ +#define X(_N,_ID) DW_LocListEntryKind_##_N = _ID, + DW_LocListEntry_XList(X) +#undef X +} DW_LocListEntryEnum; + +#define DW_CompUnitKind_XList(X) \ + X(Reserved, 0) \ + X(Compile, 1) \ + X(Type, 2) \ + X(Partial, 3) \ + X(Skeleton, 4) \ + X(SplitCompile, 5) \ + X(SplitType, 6) + +typedef U8 DW_CompUnitKind; +typedef enum DW_CompUnitKindEnum +{ +#define X(_N, _ID) DW_CompUnitKind_##_N = _ID, + DW_CompUnitKind_XList(X) +#undef X + DW_CompUnitKind_UserLo = 0x80, + DW_CompUnitKind_UserHi = 0xff +} DW_CompUnitKindEnum; + +typedef enum DW_LNCT +{ + DW_LNCT_Path = 0x1, + DW_LNCT_DirectoryIndex = 0x2, + DW_LNCT_TimeStamp = 0x3, + DW_LNCT_Size = 0x4, + DW_LNCT_MD5 = 0x5, + DW_LNCT_UserLo = 0x2000, + DW_LNCT_UserHi = 0x3fff +} DW_LNCT; + +#define DW_CFA_Kind1_XList(X) \ + X(Nop, 0x0) \ + X(SetLoc, 0x1) \ + X(AdvanceLoc1, 0x2) \ + X(AdvanceLoc2, 0x3) \ + X(AdvanceLoc4, 0x4) \ + X(OffsetExt, 0x5) \ + X(RestoreExt, 0x6) \ + X(Undefined, 0x7) \ + X(SameValue, 0x8) \ + X(Register, 0x9) \ + X(RememberState, 0xA) \ + X(RestoreState, 0xB) \ + X(DefCfa, 0xC) \ + X(DefCfaRegister, 0xD) \ + X(DefCfaOffset, 0xE) \ + X(DefCfaExpr, 0xF) \ + X(Expr, 0x10) \ + X(OffsetExtSf, 0x11) \ + X(DefCfaSf, 0x12) \ + X(DefCfaOffsetSf, 0x13) \ + X(ValOffset, 0x14) \ + X(ValOffsetSf, 0x15) \ + X(ValExpr, 0x16) + +#define DW_CFA_Kind2_XList(X) \ + X(AdvanceLoc, 0x40) \ + X(Offset, 0x80) \ + X(Restore, 0xC0) + +typedef U8 DW_CFA; +typedef enum DW_CFAEnum +{ +#define X(_N, _ID) DW_CFA_##_N = _ID, + DW_CFA_Kind1_XList(X) + DW_CFA_Kind2_XList(X) +#undef X + + DW_CFA_OplKind1 = DW_CFA_ValExpr, + DW_CFA_OplKind2 = DW_CFA_Restore, +} DW_CFAEnum; + +typedef U8 DW_CFAMask; +enum +{ + // kind1: opcode: [0,5] zeroes:[6,7]; kind2: operand:[0,5] opcode:[6,7] + DW_CFAMask_OpcodeHi = 0xC0, + DW_CFAMask_Operand = 0x3F, + DW_CFAMask_Count = 2 +}; + +//////////////////////////////// +// Expression Opcodes + +#define DW_Expr_V3_XList(X) \ + X(Null, 0x00) \ + X(Addr, 0x03) \ + X(Deref, 0x06) \ + X(Const1U, 0x08) \ + X(Const1S, 0x09) \ + X(Const2U, 0x0a) \ + X(Const2S, 0x0b) \ + X(Const4U, 0x0c) \ + X(Const4S, 0x0d) \ + X(Const8U, 0x0e) \ + X(Const8S, 0x0f) \ + X(ConstU, 0x10) \ + X(ConstS, 0x11) \ + X(Dup, 0x12) \ + X(Drop, 0x13) \ + X(Over, 0x14) \ + X(Pick, 0x15) \ + X(Swap, 0x16) \ + X(Rot, 0x17) \ + X(XDeref, 0x18) \ + X(Abs, 0x19) \ + X(And, 0x1a) \ + X(Div, 0x1b) \ + X(Minus, 0x1c) \ + X(Mod, 0x1d) \ + X(Mul, 0x1e) \ + X(Neg, 0x1f) \ + X(Not, 0x20) \ + X(Or, 0x21) \ + X(Plus, 0x22) \ + X(PlusUConst, 0x23) \ + X(Shl, 0x24) \ + X(Shr, 0x25) \ + X(Shra, 0x26) \ + X(Xor, 0x27) \ + X(Skip, 0x2f) \ + X(Bra, 0x28) \ + X(Eq, 0x29) \ + X(Ge, 0x2a) \ + X(Gt, 0x2b) \ + X(Le, 0x2c) \ + X(Lt, 0x2d) \ + X(Ne, 0x2e) \ + X(Lit0, 0x30) \ + X(Lit1, 0x31) \ + X(Lit2, 0x32) \ + X(Lit3, 0x33) \ + X(Lit4, 0x34) \ + X(Lit5, 0x35) \ + X(Lit6, 0x36) \ + X(Lit7, 0x37) \ + X(Lit8, 0x38) \ + X(Lit9, 0x39) \ + X(Lit10, 0x3a) \ + X(Lit11, 0x3b) \ + X(Lit12, 0x3c) \ + X(Lit13, 0x3d) \ + X(Lit14, 0x3e) \ + X(Lit15, 0x3f) \ + X(Lit16, 0x40) \ + X(Lit17, 0x41) \ + X(Lit18, 0x42) \ + X(Lit19, 0x43) \ + X(Lit20, 0x44) \ + X(Lit21, 0x45) \ + X(Lit22, 0x46) \ + X(Lit23, 0x47) \ + X(Lit24, 0x48) \ + X(Lit25, 0x49) \ + X(Lit26, 0x4a) \ + X(Lit27, 0x4b) \ + X(Lit28, 0x4c) \ + X(Lit29, 0x4d) \ + X(Lit30, 0x4e) \ + X(Lit31, 0x4f) \ + X(Reg0, 0x50) \ + X(Reg1, 0x51) \ + X(Reg2, 0x52) \ + X(Reg3, 0x53) \ + X(Reg4, 0x54) \ + X(Reg5, 0x55) \ + X(Reg6, 0x56) \ + X(Reg7, 0x57) \ + X(Reg8, 0x58) \ + X(Reg9, 0x59) \ + X(Reg10, 0x5a) \ + X(Reg11, 0x5b) \ + X(Reg12, 0x5c) \ + X(Reg13, 0x5d) \ + X(Reg14, 0x5e) \ + X(Reg15, 0x5f) \ + X(Reg16, 0x60) \ + X(Reg17, 0x61) \ + X(Reg18, 0x62) \ + X(Reg19, 0x63) \ + X(Reg20, 0x64) \ + X(Reg21, 0x65) \ + X(Reg22, 0x66) \ + X(Reg23, 0x67) \ + X(Reg24, 0x68) \ + X(Reg25, 0x69) \ + X(Reg26, 0x6a) \ + X(Reg27, 0x6b) \ + X(Reg28, 0x6c) \ + X(Reg29, 0x6d) \ + X(Reg30, 0x6e) \ + X(Reg31, 0x6f) \ + X(BReg0, 0x70) \ + X(BReg1, 0x71) \ + X(BReg2, 0x72) \ + X(BReg3, 0x73) \ + X(BReg4, 0x74) \ + X(BReg5, 0x75) \ + X(BReg6, 0x76) \ + X(BReg7, 0x77) \ + X(BReg8, 0x78) \ + X(BReg9, 0x79) \ + X(BReg10, 0x7a) \ + X(BReg11, 0x7b) \ + X(BReg12, 0x7c) \ + X(BReg13, 0x7d) \ + X(BReg14, 0x7e) \ + X(BReg15, 0x7f) \ + X(BReg16, 0x80) \ + X(BReg17, 0x81) \ + X(BReg18, 0x82) \ + X(BReg19, 0x83) \ + X(BReg20, 0x84) \ + X(BReg21, 0x85) \ + X(BReg22, 0x86) \ + X(BReg23, 0x87) \ + X(BReg24, 0x88) \ + X(BReg25, 0x89) \ + X(BReg26, 0x8a) \ + X(BReg27, 0x8b) \ + X(BReg28, 0x8c) \ + X(BReg29, 0x8d) \ + X(BReg30, 0x8e) \ + X(BReg31, 0x8f) \ + X(RegX, 0x90) \ + X(FBReg, 0x91) \ + X(BRegX, 0x92) \ + X(Piece, 0x93) \ + X(DerefSize, 0x94) \ + X(XDerefSize, 0x95) \ + X(Nop, 0x96) \ + X(PushObjectAddress, 0x97) \ + X(Call2, 0x98) \ + X(Call4, 0x99) \ + X(CallRef, 0x9a) \ + X(FormTlsAddress, 0x9b) \ + X(CallFrameCfa, 0x9c) \ + X(BitPiece, 0x9d) + +#define DW_Expr_V4_XList(X) \ + X(ImplicitValue, 0x9e) \ + X(StackValue, 0x9f) + +#define DW_Expr_V5_XList(X) \ + X(ImplicitPointer, 0xa0) \ + X(Addrx, 0xa1) \ + X(Constx, 0xa2) \ + X(EntryValue, 0xa3) \ + X(ConstType, 0xa4) \ + X(RegvalType, 0xa5) \ + X(DerefType, 0xa6) \ + X(XderefType, 0xa7) \ + X(Convert, 0xa8) \ + X(ReInterpret, 0xa9) + +#define DW_Expr_GNU_XList(X) \ + X(GNU_PushTlsAddress, 0xe0) \ + X(GNU_UnInit, 0xf0) +typedef U64 DW_ExprOp; +typedef enum DW_ExprOpEnum +{ +#define X(_N, _ID) DW_ExprOp_##_N = _ID, + DW_Expr_V3_XList(X) + DW_Expr_V4_XList(X) + DW_Expr_V5_XList(X) + DW_Expr_GNU_XList(X) +#undef X +} DW_ExprOpEnum; + +//- Regs + +#define DW_Regs_X86_XList(X) \ + X(Eax, 0, eax, 0, 4) \ + X(Ecx, 1, ecx, 0, 4) \ + X(Edx, 2, edx, 0, 4) \ + X(Ebx, 3, ebx, 0, 4) \ + X(Esp, 4, esp, 0, 4) \ + X(Ebp, 5, ebp, 0, 4) \ + X(Esi, 6, esi, 0, 4) \ + X(Edi, 7, edi, 0, 4) \ + X(Eip, 8, eip, 0, 4) \ + X(Eflags, 9, eflags, 0, 4) \ + X(Trapno, 10, nil, 0, 0) \ + X(St0, 11, st0, 0, 10) \ + X(St1, 12, st1, 0, 10) \ + X(St2, 13, st2, 0, 10) \ + X(St3, 14, st3, 0, 10) \ + X(St4, 15, st4, 0, 10) \ + X(St5, 16, st5, 0, 10) \ + X(St6, 17, st6, 0, 10) \ + X(St7, 18, st7, 0, 10) \ + X(Xmm0, 21, xmm0, 0, 16) \ + X(Xmm1, 22, xmm1, 0, 16) \ + X(Xmm2, 23, xmm2, 0, 16) \ + X(Xmm3, 24, xmm3, 0, 16) \ + X(Xmm4, 25, xmm4, 0, 16) \ + X(Xmm5, 26, xmm5, 0, 16) \ + X(Xmm6, 27, xmm6, 0, 16) \ + X(Xmm7, 28, xmm7, 0, 16) \ + X(Mm0, 29, mm0, 0, 4) \ + X(Mm1, 30, mm1, 0, 4) \ + X(Mm2, 31, mm2, 0, 4) \ + X(Mm3, 32, mm3, 0, 4) \ + X(Mm4, 33, mm4, 0, 4) \ + X(Mm5, 34, mm5, 0, 4) \ + X(Mm6, 35, mm6, 0, 4) \ + X(Mm7, 36, mm7, 0, 4) \ + X(Fcw, 37, fcw, 0, 2) \ + X(Fsw, 38, fsw, 0, 2) \ + X(Mxcsr, 39, mxcsr, 0, 4) \ + X(Es, 40, es, 0, 2) \ + X(Cs, 41, cs, 0, 2) \ + X(Ss, 42, ss, 0, 2) \ + X(Ds, 43, ds, 0, 2) \ + X(Fs, 44, fs, 0, 2) \ + X(Gs, 45, gs, 0, 2) \ + X(Tr, 48, nil, 0, 0) \ + X(Ldtr, 49, nil, 0, 0) + +#define DW_Regs_X64_XList(X) \ + X(Rax, 0, rax, 0, 8) \ + X(Rdx, 1, rdx, 0, 8) \ + X(Rcx, 2, rcx, 0, 8) \ + X(Rbx, 3, rbx, 0, 8) \ + X(Rsi, 4, rsi, 0, 8) \ + X(Rdi, 5, rdi, 0, 8) \ + X(Rbp, 6, rbp, 0, 8) \ + X(Rsp, 7, rsp, 0, 8) \ + X(R8, 8, r8, 0, 8) \ + X(R9, 9, r9, 0, 8) \ + X(R10, 10, r10, 0, 8) \ + X(R11, 11, r11, 0, 8) \ + X(R12, 12, r12, 0, 8) \ + X(R13, 13, r13, 0, 8) \ + X(R14, 14, r14, 0, 8) \ + X(R15, 15, r15, 0, 8) \ + X(Rip, 16, rip, 0, 8) \ + X(Xmm0, 17, ymm0, 0, 16) \ + X(Xmm1, 18, ymm1, 0, 16) \ + X(Xmm2, 19, ymm2, 0, 16) \ + X(Xmm3, 20, ymm3, 0, 16) \ + X(Xmm4, 21, ymm4, 0, 16) \ + X(Xmm5, 22, ymm5, 0, 16) \ + X(Xmm6, 23, ymm6, 0, 16) \ + X(Xmm7, 24, ymm7, 0, 16) \ + X(Xmm8, 25, ymm8, 0, 16) \ + X(Xmm9, 26, ymm9, 0, 16) \ + X(Xmm10, 27, ymm10, 0, 16) \ + X(Xmm11, 28, ymm11, 0, 16) \ + X(Xmm12, 29, ymm12, 0, 16) \ + X(Xmm13, 30, ymm13, 0, 16) \ + X(Xmm14, 31, ymm14, 0, 16) \ + X(Xmm15, 32, ymm15, 0, 16) \ + X(St0, 33, st0, 0, 10) \ + X(St1, 34, st1, 0, 10) \ + X(St2, 35, st2, 0, 10) \ + X(St3, 36, st3, 0, 10) \ + X(St4, 37, st4, 0, 10) \ + X(St5, 38, st5, 0, 10) \ + X(St6, 39, st6, 0, 10) \ + X(St7, 40, st7, 0, 10) \ + X(Mm0, 41, mm0, 0, 8) \ + X(Mm1, 42, mm1, 0, 8) \ + X(Mm2, 43, mm2, 0, 8) \ + X(Mm3, 44, mm3, 0, 8) \ + X(Mm4, 45, mm4, 0, 8) \ + X(Mm5, 46, mm5, 0, 8) \ + X(Mm6, 47, mm6, 0, 8) \ + X(Mm7, 48, mm7, 0, 8) \ + X(Rflags, 49, rflags, 0, 4) \ + X(Es, 50, es, 0, 2) \ + X(Cs, 51, cs, 0, 2) \ + X(Ss, 52, ss, 0, 2) \ + X(Ds, 53, ds, 0, 2) \ + X(Fs, 54, fs, 0, 2) \ + X(Gs, 55, gs, 0, 2) \ + X(FsBase, 58, nil, 0, 0) \ + X(GsBase, 59, nil, 0, 0) \ + X(Tr, 62, nil, 0, 0) \ + X(Ldtr, 63, nil, 0, 0) + +typedef U32 DW_RegX86; +typedef enum DW_RegX86Enum +{ +#define X(_N,_ID,...) DW_Reg_x86_##_N = _ID, + DW_Regs_X86_XList(X) +#undef X +} DW_RegX86Enum; + +typedef U32 DW_RegX64; +typedef enum DW_RegX64Enum +{ +#define X(_N,_ID,...) DW_Reg_x64_##_N = _ID, + DW_Regs_X64_XList(X) +#undef X +} DW_RegX64Enum; + +//////////////////////////////// + +//- Attrib Class Encodings + +// Speced Encodings +internal DW_AttribClass dw_attrib_class_from_attrib_kind_v2(DW_AttribKind k); +internal DW_AttribClass dw_attrib_class_from_attrib_kind_v3(DW_AttribKind k); +internal DW_AttribClass dw_attrib_class_from_attrib_kind_v4(DW_AttribKind k); +internal DW_AttribClass dw_attrib_class_from_attrib_kind_v5(DW_AttribKind k); + +// Extensions +internal DW_AttribClass dw_attrib_class_from_attrib_kind_gnu (DW_AttribKind k); +internal DW_AttribClass dw_attrib_class_from_attrib_kind_llvm (DW_AttribKind k); +internal DW_AttribClass dw_attrib_class_from_attrib_kind_apple(DW_AttribKind k); +internal DW_AttribClass dw_attrib_class_from_attrib_kind_mips (DW_AttribKind k); + +internal DW_AttribClass dw_attrib_class_from_attrib_kind(DW_Version ver, DW_Ext ext, DW_AttribKind v); + +//- Form Class Encodings + +internal DW_AttribClass dw_attrib_class_from_form_kind(DW_Version ver, DW_FormKind k); + +internal B32 dw_are_attrib_class_and_form_kind_compatible(DW_Version ver, DW_AttribClass attrib_class, DW_FormKind form_kind); + +//- Section Names + +internal String8 dw_name_string_from_section_kind (DW_SectionKind k); +internal String8 dw_mach_name_string_from_section_kind(DW_SectionKind k); +internal String8 dw_dwo_name_string_from_section_kind (DW_SectionKind k); + +//////////////////////////////// + +internal U64 dw_offset_size_from_mode(DW_Mode mode); + +//////////////////////////////// + +internal DW_AttribClass dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, B32 relaxed, DW_AttribKind attrib, DW_FormKind form_kind); + +#endif // DWARF_H diff --git a/src/dwarf/dwarf_enum.c b/src/dwarf/dwarf_enum.c new file mode 100644 index 00000000..68b29463 --- /dev/null +++ b/src/dwarf/dwarf_enum.c @@ -0,0 +1,225 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal String8 +dw_string_from_expr_op(Arena *arena, DW_Version ver, DW_Ext ext, DW_ExprOp op) +{ + String8 result = {0}; + + #define X(_N,...) case DW_ExprOp_##_N: result = str8_lit(Stringify(_N)); goto exit; + switch (ext) { + case DW_Ext_Null: break; + case DW_Ext_LLVM: break; + case DW_Ext_APPLE: break; + case DW_Ext_MIPS: break; + case DW_Ext_GNU: DW_Expr_GNU_XList(X); break; + } + + switch (ver) { + case DW_Version_5: { + switch (op) { + DW_Expr_V5_XList(X) + } + } // fall-through + case DW_Version_4: { + switch (op) { + DW_Expr_V4_XList(X) + } + } // fall-through + case DW_Version_3: { + switch (op) { + DW_Expr_V3_XList(X) + } + } // fall-through + case DW_Version_2: + case DW_Version_1: + case DW_Version_Null: + break; + } + #undef X + + result = push_str8f(arena, "%x", op); + +exit:; + return result; +} + +internal String8 +dw_string_from_tag_kind(Arena *arena, DW_TagKind kind) +{ + switch (kind) { + #define X(_N,_ID) case DW_Tag_##_N: return str8_lit(Stringify(_N)); + DW_Tag_V3_XList(X) + DW_Tag_V5_XList(X) + DW_Tag_GNU_XList(X) + #undef X + } + return push_str8f(arena, "%llx", kind); +} + +internal String8 +dw_string_from_attrib_kind(Arena *arena, DW_Version ver, DW_Ext ext, DW_AttribKind kind) +{ + #define X(_N,...) case DW_Attrib_##_N: return str8_lit(Stringify(_N)); + + while (ext) { + U64 z = 64-clz64(ext); + if (z == 0) { + break; + } + U64 flag = 1 << (z-1); + ext &= ~flag; + + switch (flag) { + case DW_Ext_Null: break; + case DW_Ext_GNU: switch (kind) { DW_AttribKind_GNU_XList(X) } break; + case DW_Ext_LLVM: switch (kind) { DW_AttribKind_LLVM_XList(X) } break; + case DW_Ext_APPLE: switch (kind) { DW_AttribKind_APPLE_XList(X) } break; + case DW_Ext_MIPS: switch (kind) { DW_AttribKind_MIPS_XList(X) } break; + default: InvalidPath; break; + } + } + + switch (ver) { + case DW_Version_5: { + switch (kind) { + DW_AttribKind_V5_XList(X) + } + } // fall-through + case DW_Version_4: { + switch (kind) { + DW_AttribKind_V4_XList(X) + } + } // fall-through + case DW_Version_3: { + switch (kind) { + DW_AttribKind_V3_XList(X) + } + } // fall-through + case DW_Version_2: { + switch (kind) { + DW_AttribKind_V2_XList(X) + } + } // fall-through + case DW_Version_1: { + } // fall-through + case DW_Version_Null: break; + } + #undef X + + return str8_zero(); +} + +internal String8 +dw_string_from_form_kind(Arena *arena, DW_Version ver, DW_FormKind kind) +{ + #define X(_N,...) case DW_Form_##_N: return str8_lit(Stringify(_N)); + switch (ver) { + case DW_Version_5: { + switch (kind) { + DW_Form_V5_XList(X) + } + } // fall-through + case DW_Version_4: { + switch (kind) { + DW_Form_V4_XList(X) + } + } // fall-through + case DW_Version_3: + case DW_Version_2: { + switch (kind) { + DW_Form_V2_XList(X) + } + } // fall-through + case DW_Version_Null: break; + } + #undef X + String8 result = push_str8f(arena, "%x", kind); + return result; +} + +internal String8 +dw_string_from_language(Arena *arena, DW_Language kind) +{ + switch (kind) { + #define X(_N,_ID) case DW_Language_##_N: return str8_lit(Stringify(_N)); + DW_Language_XList(X) + #undef X + } + return push_str8f(arena, "%x", kind); +} + +internal String8 +dw_string_from_std_opcode(Arena *arena, DW_StdOpcode kind) +{ + switch (kind) { + #define X(_N,_ID) case DW_StdOpcode_##_N: return str8_lit(Stringify(_N)); + DW_StdOpcode_XList(X) + #undef X + } + return push_str8f(arena, "%x", kind); +} + +internal String8 +dw_string_from_ext_opcode(Arena *arena, DW_ExtOpcode kind) +{ + switch (kind) { + #define X(_N,_ID) case DW_ExtOpcode_##_N: return str8_lit(Stringify(_N)); + DW_ExtOpcode_XList(X) + #undef X + default: InvalidPath; break; + } + return push_str8f(arena, "%x", kind); +} + +internal String8 +dw_string_from_loc_list_entry_kind(Arena *arena, DW_LocListEntryKind kind) +{ + NotImplemented; + return str8_zero(); +} + +internal String8 +dw_string_from_section_kind(Arena *arena, DW_SectionKind kind) +{ + NotImplemented; + return str8_zero(); +} + +internal String8 +dw_string_from_rng_list_entry_kind(Arena *arena, DW_RngListEntryKind kind) +{ + NotImplemented; + return str8_zero(); +} + +internal String8 +dw_string_from_register(Arena *arena, Arch arch, U64 reg_id) +{ + String8 reg_str = str8_zero(); + switch (arch) { + case Arch_Null: break; + case Arch_x86: { + switch (reg_id) { + #define X(_N, _ID, ...) case DW_Reg_x86_##_N: reg_str = str8_lit(Stringify(_ID)); break; + DW_Regs_X86_XList(X) + #undef X + } + } break; + case Arch_x64: { + switch (reg_id) { + #define X(_N, _ID, ...) case DW_Reg_x64_##_N: reg_str = str8_lit(Stringify(_ID)); break; + DW_Regs_X64_XList(X) + #undef X + } + } break; + case Arch_arm32: NotImplemented; break; + case Arch_arm64: NotImplemented; break; + default: InvalidPath; break; + } + if (reg_str.size == 0) { + reg_str = push_str8f(arena, "%#llx", reg_id); + } + return reg_str; +} + diff --git a/src/dwarf/dwarf_enum.h b/src/dwarf/dwarf_enum.h index 6158c409..1bbc3898 100644 --- a/src/dwarf/dwarf_enum.h +++ b/src/dwarf/dwarf_enum.h @@ -1,11 +1,15 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -internal String8 dw_string_from_expr_op(Arena *arena, DW_ExprOp op); +#ifndef DWARF_ENUM_H +#define DWARF_ENUM_H + +internal String8 dw_string_from_expr_op(Arena *arena, DW_Version ver, DW_Ext ext, DW_ExprOp op); internal String8 dw_string_from_tag_kind(Arena *arena, DW_TagKind kind); -internal String8 dw_string_from_attrib_kind(Arena *arena, DW_AttribKind kind); -internal String8 dw_string_from_form_kind(Arena *arena, DW_FormKind kind); +internal String8 dw_string_from_attrib_kind(Arena *arena, DW_Version ver, DW_Ext ext, DW_AttribKind kind); +internal String8 dw_string_from_form_kind(Arena *arena, DW_Version ver, DW_FormKind kind); //internal String8 dw_string_from_register(Arena *arena, Arch arch, U64 reg_id); +#endif // DWARF_ENUM_H diff --git a/src/dwarf/dwarf_expr.c b/src/dwarf/dwarf_expr.c index 094ad78c..fe4fd9a1 100644 --- a/src/dwarf/dwarf_expr.c +++ b/src/dwarf/dwarf_expr.c @@ -9,7 +9,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) DW_SimpleLoc result = {DW_SimpleLocKind_Empty}; U8 op = 0; - if (based_range_read(base, range, 0, 1, &op)) { + if (dw_based_range_read(base, range, 0, 1, &op)) { // step params U64 size_param = 0; B32 is_signed = 0; @@ -48,7 +48,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) const_n: { U64 x = 0; - step_cursor += based_range_read(base, range, step_cursor, size_param, &x); + step_cursor += dw_based_range_read(base, range, step_cursor, size_param, &x); if (is_signed) { x = extend_sign64(x, size_param); @@ -61,7 +61,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) case DW_ExprOp_Addr: { U64 offset = 0; - step_cursor += based_range_read(base, range, step_cursor, 8, &offset); + step_cursor += dw_based_range_read(base, range, step_cursor, 8, &offset); U64 x = text_section_base + offset; result.kind = DW_SimpleLocKind_Address; result.addr = x; @@ -70,7 +70,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) case DW_ExprOp_ConstU: { U64 x = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &x); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &x); result.kind = DW_SimpleLocKind_Address; result.addr = x; } break; @@ -78,7 +78,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) case DW_ExprOp_ConstS: { U64 x = 0; - step_cursor += based_range_read_sleb128(base, range, step_cursor, (S64*)&x); + step_cursor += dw_based_range_read_sleb128(base, range, step_cursor, (S64*)&x); result.kind = DW_SimpleLocKind_Address; result.addr = x; } break; @@ -106,7 +106,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) case DW_ExprOp_RegX: { U64 reg_idx = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, ®_idx); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, ®_idx); result.kind = DW_SimpleLocKind_Register; result.reg_idx = reg_idx; } break; @@ -117,7 +117,7 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) case DW_ExprOp_ImplicitValue: { U64 size = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &size); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &size); if (step_cursor + size <= range.max) { result.kind = DW_SimpleLocKind_ValueLong; result.val_long.str = (U8*)base + range.min + step_cursor; @@ -141,15 +141,15 @@ dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) case DW_ExprOp_Piece: { U64 size = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &size); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &size); result.kind = DW_SimpleLocKind_Empty; } break; case DW_ExprOp_BitPiece: { U64 bit_size = 0, bit_off = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &bit_size); - step_cursor += based_range_read_uleb128(base, range, step_cursor, &bit_off); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &bit_size); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &bit_off); result.kind = DW_SimpleLocKind_Empty; } break; @@ -222,7 +222,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf // decode op U64 op_offset = cursor; U8 op = 0; - if (based_range_read(task_base, task_range, op_offset, 1, &op)) { + if (dw_based_range_read(task_base, task_range, op_offset, 1, &op)) { U64 after_op_off = cursor + 1; // require piece op after 'implicit' location descriptions @@ -267,26 +267,26 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf const_n: { U64 x = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, size_param, &x); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, size_param, &x); } break; case DW_ExprOp_Addr: { U64 offset = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, 8, &offset); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, 8, &offset); result.flags |= DW_ExprFlag_UsesTextBase; } break; case DW_ExprOp_ConstU: { U64 x = 0; - step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &x); + step_cursor += dw_based_range_read_uleb128(task_base, task_range, step_cursor, &x); } break; case DW_ExprOp_ConstS: { U64 x = 0; - step_cursor += based_range_read_sleb128(task_base, task_range, step_cursor, (S64*)&x); + step_cursor += dw_based_range_read_sleb128(task_base, task_range, step_cursor, (S64*)&x); } break; @@ -295,7 +295,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_FBReg: { S64 offset = 0; - step_cursor += based_range_read_sleb128(task_base, task_range, step_cursor, &offset); + step_cursor += dw_based_range_read_sleb128(task_base, task_range, step_cursor, &offset); result.flags |= DW_ExprFlag_UsesFrameBase; } break; @@ -312,15 +312,15 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: { S64 offset = 0; - step_cursor += based_range_read_sleb128(task_base, task_range, step_cursor, &offset); + step_cursor += dw_based_range_read_sleb128(task_base, task_range, step_cursor, &offset); result.flags |= DW_ExprFlag_UsesRegisters; } break; case DW_ExprOp_BRegX: { U64 reg_idx = 0; S64 offset = 0; - step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, ®_idx); - step_cursor += based_range_read_sleb128(task_base, task_range, step_cursor, &offset); + step_cursor += dw_based_range_read_uleb128(task_base, task_range, step_cursor, ®_idx); + step_cursor += dw_based_range_read_sleb128(task_base, task_range, step_cursor, &offset); result.flags |= DW_ExprFlag_UsesRegisters; } break; @@ -334,7 +334,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_Pick: { U64 idx = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, 1, &idx); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, 1, &idx); } break; case DW_ExprOp_Over: @@ -350,7 +350,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_DerefSize: { U64 size = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, 1, &size); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, 1, &size); result.flags |= DW_ExprFlag_UsesMemory; } break; @@ -394,7 +394,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_PlusUConst: { U64 y = 0; - step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &y); + step_cursor += dw_based_range_read_uleb128(task_base, task_range, step_cursor, &y); } break; case DW_ExprOp_Shl: @@ -418,7 +418,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_Bra: { S16 d = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, 2, &d); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, 2, &d); result.flags |= DW_ExprFlag_NonLinearFlow; } break; @@ -427,7 +427,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf callN: { U64 p = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, size_param, &p); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, size_param, &p); result.flags |= DW_ExprFlag_UsesCallResolution|DW_ExprFlag_NonLinearFlow; // add to task list @@ -476,7 +476,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_RegX: { U64 reg_idx = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, size_param, ®_idx); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, size_param, ®_idx); last_was_implicit_loc = 1; } break; @@ -486,7 +486,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_ImplicitValue: { U64 size = 0; - step_cursor += based_range_read(task_base, task_range, step_cursor, size_param, &size); + step_cursor += dw_based_range_read(task_base, task_range, step_cursor, size_param, &size); if (step_cursor + size > task_range.max) { result.flags |= DW_ExprFlag_BadData; goto finish; @@ -506,7 +506,7 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_Piece: { U64 size = 0; - step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &size); + step_cursor += dw_based_range_read_uleb128(task_base, task_range, step_cursor, &size); result.flags |= DW_ExprFlag_UsesComposite; last_was_implicit_loc = 0; @@ -515,8 +515,8 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf case DW_ExprOp_BitPiece: { U64 bit_size = 0; U64 bit_off = 0; - step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &bit_size); - step_cursor += based_range_read_uleb128(task_base, task_range, step_cursor, &bit_off); + step_cursor += dw_based_range_read_uleb128(task_base, task_range, step_cursor, &bit_size); + step_cursor += dw_based_range_read_uleb128(task_base, task_range, step_cursor, &bit_off); result.flags |= DW_ExprFlag_UsesComposite; last_was_implicit_loc = 0; @@ -590,7 +590,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp // decode op U64 op_offset = cursor; U8 op = 0; - if (based_range_read(base, range, op_offset, 1, &op)) { + if (dw_based_range_read(base, range, op_offset, 1, &op)) { U64 after_op_off = cursor + 1; // require piece op after 'implicit' location descriptions @@ -639,7 +639,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp const_n: { U64 x = 0; - step_cursor += based_range_read(base, range, step_cursor, size_param, &x); + step_cursor += dw_based_range_read(base, range, step_cursor, size_param, &x); if (is_signed) { x = extend_sign64(x, size_param); } @@ -649,13 +649,13 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_Addr: { U64 offset = 0; - step_cursor += based_range_read(base, range, step_cursor, 8, &offset); + step_cursor += dw_based_range_read(base, range, step_cursor, 8, &offset); // earlier versions of GCC emit TLS offset with DW_ExprOp_Addr. B32 is_text_relative; { U8 next_op = 0; - based_range_read_struct(base, range, step_cursor, &next_op); + dw_based_range_read_struct(base, range, step_cursor, &next_op); is_text_relative = (next_op != DW_ExprOp_GNU_PushTlsAddress); } @@ -677,14 +677,14 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_ConstU: { U64 x = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &x); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &x); dw_expr__stack_push(scratch.arena, &stack, x); } break; case DW_ExprOp_ConstS: { U64 x = 0; - step_cursor += based_range_read_sleb128(base, range, step_cursor, (S64*)&x); + step_cursor += dw_based_range_read_sleb128(base, range, step_cursor, (S64*)&x); dw_expr__stack_push(scratch.arena, &stack, x); } break; @@ -694,7 +694,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_FBReg: { S64 offset = 0; - step_cursor += based_range_read_sleb128(base, range, step_cursor, &offset); + step_cursor += dw_based_range_read_sleb128(base, range, step_cursor, &offset); if (config->frame_base != 0) { U64 x = *config->frame_base + offset; dw_expr__stack_push(scratch.arena, &stack, x); @@ -718,7 +718,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: { S64 offset = 0; - step_cursor += based_range_read_sleb128(base, range, step_cursor, &offset); + step_cursor += dw_based_range_read_sleb128(base, range, step_cursor, &offset); U64 reg_idx = op - DW_ExprOp_BReg0; DW_RegsX64 *regs = config->regs; if (regs != 0) { @@ -741,8 +741,8 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_BRegX: { U64 reg_idx = 0; S64 offset = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, ®_idx); - step_cursor += based_range_read_sleb128(base, range, step_cursor, &offset); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, ®_idx); + step_cursor += dw_based_range_read_sleb128(base, range, step_cursor, &offset); DW_RegsX64 *regs = config->regs; if (regs != 0) { @@ -779,7 +779,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_Pick: { U64 idx = 0; - step_cursor += based_range_read(base, range, step_cursor, 1, &idx); + step_cursor += dw_based_range_read(base, range, step_cursor, 1, &idx); U64 x = dw_expr__stack_pick(&stack, idx); dw_expr__stack_push(scratch.arena, &stack, x); } break; @@ -832,7 +832,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_DerefSize: { U64 raw_size = 0; - step_cursor += based_range_read(base, range, step_cursor, 1, &raw_size); + step_cursor += dw_based_range_read(base, range, step_cursor, 1, &raw_size); U64 size = ClampTop(raw_size, 8); U64 addr = dw_expr__stack_pop(&stack); @@ -983,7 +983,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_PlusUConst: { U64 y = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &y); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &y); U64 z = dw_expr__stack_pop(&stack); U64 x = y + z; dw_expr__stack_push(scratch.arena, &stack, x); @@ -1088,14 +1088,14 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_Skip: { S16 d = 0; - step_cursor += based_range_read(base, range, step_cursor, 2, &d); + step_cursor += dw_based_range_read(base, range, step_cursor, 2, &d); step_cursor = step_cursor + d; } break; case DW_ExprOp_Bra: { S16 d = 0; - step_cursor += based_range_read(base, range, step_cursor, 2, &d); + step_cursor += dw_based_range_read(base, range, step_cursor, 2, &d); U64 b = dw_expr__stack_pop(&stack); if (b != 0) { step_cursor = step_cursor + d; @@ -1105,7 +1105,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_Call2: { U16 p = 0; - step_cursor += based_range_read(base, range, step_cursor, 2, &p); + step_cursor += dw_based_range_read(base, range, step_cursor, 2, &p); if (config->call.func != 0) { String8 sub_data = config->call.func(config->call.user_ptr, p); dw_expr__call_push(scratch.arena, &call_stack, sub_data.str, sub_data.size); @@ -1119,7 +1119,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_Call4: { U32 p = 0; - step_cursor += based_range_read(base, range, step_cursor, 4, &p); + step_cursor += dw_based_range_read(base, range, step_cursor, 4, &p); if (config->call.func != 0) { String8 sub_data = config->call.func(config->call.user_ptr, p); dw_expr__call_push(scratch.arena, &call_stack, sub_data.str, sub_data.size); @@ -1165,7 +1165,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_RegX: { U64 reg_idx = 0; - step_cursor += based_range_read(base, range, step_cursor, size_param, ®_idx); + step_cursor += dw_based_range_read(base, range, step_cursor, size_param, ®_idx); stashed_loc.kind = DW_SimpleLocKind_Register; stashed_loc.reg_idx = reg_idx; } break; @@ -1176,7 +1176,7 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_ImplicitValue: { U64 size = 0; - step_cursor += based_range_read(base, range, step_cursor, size_param, &size); + step_cursor += dw_based_range_read(base, range, step_cursor, size_param, &size); if (step_cursor + size <= range.max) { void *data = (U8*)base + range.min + step_cursor; stashed_loc.kind = DW_SimpleLocKind_ValueLong; @@ -1216,13 +1216,13 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp case DW_ExprOp_Piece: { U64 size = 0; - step_cursor += based_range_read_uleb128(base, range, step_cursor, &size); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &size); bit_size = size*8; } break; case DW_ExprOp_BitPiece: { - step_cursor += based_range_read_uleb128(base, range, step_cursor, &bit_size); - step_cursor += based_range_read_uleb128(base, range, step_cursor, &bit_off); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &bit_size); + step_cursor += dw_based_range_read_uleb128(base, range, step_cursor, &bit_off); is_bit_loc = 1; } break; } diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index d1919758..ee0df7ef 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -68,61 +68,18 @@ dw_hash_from_string(String8 string) return hash64; } -internal DW_AttribClass -dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, DW_AttribKind attrib_kind, DW_FormKind form_kind) -{ - // NOTE(rjf): DWARF's spec specifies two mappings: - // (DW_AttribKind) => List(DW_AttribClass) - // (DW_FormKind) => List(DW_AttribClass) - // - // This function's purpose is to find the overlapping class between an - // DW_AttribKind and DW_FormKind. - - DW_AttribClass attrib_class = dw_attrib_class_from_attrib_kind(ver, ext, attrib_kind); - DW_AttribClass form_class = dw_attrib_class_from_form_kind(ver, form_kind); - - // rust compiler is busted, it writes version 5 attributes - if(ver == DW_Version_2 && lang == DW_Language_Rust && (attrib_class == DW_AttribClass_Null || form_class == DW_AttribClass_Null)) - { - attrib_class = dw_attrib_class_from_attrib_kind(DW_Version_5, ext, attrib_kind); - form_class = dw_attrib_class_from_form_kind(DW_Version_5, form_kind); - } - - DW_AttribClass result = DW_AttribClass_Null; - if(attrib_class != DW_AttribClass_Null && form_class != DW_AttribClass_Null) - { - result = DW_AttribClass_Undefined; - - for(U32 i = 0; i < 32; ++i) - { - U32 n = 1u << i; - if((attrib_class & n) != 0 && (form_class & n) != 0) - { - result = ((DW_AttribClass) n); - break; - } - } - - Assert(result != DW_AttribClass_Undefined); - } - - return result; -} - //////////////////////////////// //~ rjf: DWARF-Specific Based Range Reads internal U64 -based_range_read(void *base, Rng1U64 range, U64 offset, U64 size, void *out) +dw_based_range_read(void *base, Rng1U64 range, U64 offset, U64 size, void *out) { String8 data = str8((U8*)base+range.min, dim_1u64(range)); return str8_deserial_read(data, offset, out, size, 1); } -#define based_range_read_struct(base, range, offset, out) based_range_read(base, range, offset, sizeof(*out), out) - internal String8 -based_range_read_string(void *base, Rng1U64 range, U64 offset) +dw_based_range_read_string(void *base, Rng1U64 range, U64 offset) { String8 data = str8((U8*)base+range.min, dim_1u64(range)); String8 result = {0}; @@ -131,23 +88,33 @@ based_range_read_string(void *base, Rng1U64 range, U64 offset) } internal void * -based_range_ptr(void *base, Rng1U64 range, U64 offset) +dw_based_range_ptr(void *base, Rng1U64 range, U64 offset) { Assert(offset < dim_1u64(range)); U8 *data = (U8*)base + range.min + offset; return data; } +internal void * +dw_based_range_ptr_size(void *base, Rng1U64 range, U64 offset, U64 size) +{ + void *ptr = 0; + if (size > 0 && offset + size <= dim_1u64(range)) { + ptr = dw_based_range_ptr(base, range, offset); + } + return ptr; +} + internal U64 -based_range_read_uleb128(void *base, Rng1U64 range, U64 offset, U64 *out_value) +dw_based_range_read_uleb128(void *base, Rng1U64 range, U64 offset, U64 *out_value) { U64 value = 0; U64 bytes_read = 0; U64 shift = 0; U8 byte = 0; - for(U64 read_offset = offset; - based_range_read_struct(base, range, read_offset, &byte) == 1; - read_offset += 1) + for(U64 cursor = offset; + dw_based_range_read_struct(base, range, cursor, &byte) == 1; + cursor += 1) { bytes_read += 1; U8 val = byte & 0x7fu; @@ -166,15 +133,15 @@ based_range_read_uleb128(void *base, Rng1U64 range, U64 offset, U64 *out_value) } internal U64 -based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_value) +dw_based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_value) { - U64 value = 0; + U64 value = 0; U64 bytes_read = 0; - U64 shift = 0; - U8 byte = 0; - for(U64 read_offset = offset; - based_range_read_struct(base, range, read_offset, &byte) == 1; - read_offset += 1) + U64 shift = 0; + U8 byte = 0; + for(U64 cursor = offset; + dw_based_range_read_struct(base, range, cursor, &byte) == 1; + cursor += 1) { bytes_read += 1; U8 val = byte & 0x7fu; @@ -196,26 +163,24 @@ based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_value) return bytes_read; } -//////////////////////////////// - internal U64 dw_based_range_read_length(void *base, Rng1U64 range, U64 offset, U64 *out_value) { U64 bytes_read = 0; U64 value = 0; U32 first32 = 0; - if(based_range_read_struct(base, range, offset, &first32)) + if(dw_based_range_read_struct(base, range, offset, &first32)) { // NOTE(rjf): DWARF 32-bit => use the first 32 bits as the size. if(first32 != max_U32) { - value = (U64)first32; + value = (U64)first32; bytes_read = sizeof(U32); } // NOTE(rjf): DWARF 64-bit => first 32 are just a marker, use the next 64 bits as the size. - else if(based_range_read_struct(base, range, offset + sizeof(U32), &value)) + else if(dw_based_range_read_struct(base, range, offset + sizeof(U32), &value)) { - value = 0; + value = 0; bytes_read = sizeof(U32) + sizeof(U64); } } @@ -236,7 +201,7 @@ dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev U64 sub_kind_off = id_off; U64 id = 0; { - U64 bytes_read = based_range_read_uleb128(base, range, id_off, &id); + U64 bytes_read = dw_based_range_read_uleb128(base, range, id_off, &id); sub_kind_off += bytes_read; total_bytes_read += bytes_read; } @@ -246,8 +211,8 @@ dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev U64 next_off = sub_kind_off; if(id != 0) { - U64 bytes_read = based_range_read_uleb128(base, range, sub_kind_off, &sub_kind); - next_off += bytes_read; + U64 bytes_read = dw_based_range_read_uleb128(base, range, sub_kind_off, &sub_kind); + next_off += bytes_read; total_bytes_read += bytes_read; } @@ -255,7 +220,7 @@ dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev U8 has_children = 0; if(id != 0) { - total_bytes_read += based_range_read_struct(base, range, next_off, &has_children); + total_bytes_read += dw_based_range_read_struct(base, range, next_off, &has_children); } //- rjf: fill abbrev @@ -286,8 +251,8 @@ dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW U64 sub_kind_off = id_off; U64 id = 0; { - U64 bytes_read = based_range_read_uleb128(base, range, id_off, &id); - sub_kind_off += bytes_read; + U64 bytes_read = dw_based_range_read_uleb128(base, range, id_off, &id); + sub_kind_off += bytes_read; total_bytes_read += bytes_read; } @@ -295,8 +260,8 @@ dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW U64 sub_kind = 0; U64 next_off = sub_kind_off; { - U64 bytes_read = based_range_read_uleb128(base, range, sub_kind_off, &sub_kind); - next_off += bytes_read; + U64 bytes_read = dw_based_range_read_uleb128(base, range, sub_kind_off, &sub_kind); + next_off += bytes_read; total_bytes_read += bytes_read; } @@ -304,7 +269,7 @@ dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW U64 implicit_const = 0; if(sub_kind == DW_Form_ImplicitConst) { - U64 bytes_read = based_range_read_uleb128(base, range, next_off, &implicit_const); + U64 bytes_read = dw_based_range_read_uleb128(base, range, next_off, &implicit_const); total_bytes_read += bytes_read; } @@ -318,8 +283,8 @@ dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW abbrev.id = id; if(sub_kind == DW_Form_ImplicitConst) { - abbrev.flags |= DW_AbbrevFlag_HasImplicitConst; - abbrev.const_value = implicit_const; + abbrev.flags |= DW_AbbrevFlag_HasImplicitConst; + abbrev.const_value = implicit_const; } *out_abbrev = abbrev; } @@ -372,7 +337,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ { read_fixed_uint:; U64 value = 0; - bytes_read = based_range_read(base, range, offset, bytes_to_read, &value); + bytes_read = dw_based_range_read(base, range, offset, bytes_to_read, &value); form_value.v[0] = value; } break; @@ -381,7 +346,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ case DW_Form_Addrx: case DW_Form_LocListx: case DW_Form_RngListx: { U64 value = 0; - bytes_read = based_range_read_uleb128(base, range, offset, &value); + bytes_read = dw_based_range_read_uleb128(base, range, offset, &value); form_value.v[0] = value; } break; @@ -389,7 +354,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ case DW_Form_SData: { S64 value = 0; - bytes_read = based_range_read_sleb128(base, range, offset, &value); + bytes_read = dw_based_range_read_sleb128(base, range, offset, &value); form_value.v[0] = value; } break; @@ -400,7 +365,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ { read_fixed_uint_skip:; U64 size = 0; - bytes_read = based_range_read(base, range, offset, bytes_to_read, &size); + bytes_read = dw_based_range_read(base, range, offset, bytes_to_read, &size); form_value.v[0] = size; form_value.v[1] = offset; bytes_read += size; @@ -410,7 +375,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ case DW_Form_Block: { U64 size = 0; - bytes_read = based_range_read_uleb128(base, range, offset, &size); + bytes_read = dw_based_range_read_uleb128(base, range, offset, &size); form_value.v[0] = size; form_value.v[1] = offset; bytes_read += size; @@ -421,8 +386,8 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ { U64 value1 = 0; U64 value2 = 0; - bytes_read += based_range_read_struct(base, range, offset, &value1); - bytes_read += based_range_read_struct(base, range, offset + sizeof(U64), &value2); + bytes_read += dw_based_range_read_struct(base, range, offset, &value1); + bytes_read += dw_based_range_read_struct(base, range, offset + sizeof(U64), &value2); form_value.v[0] = value1; form_value.v[1] = value2; } break; @@ -430,7 +395,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ //- rjf: strings case DW_Form_String: { - String8 string = based_range_read_string(base, range, offset); + String8 string = dw_based_range_read_string(base, range, offset); bytes_read = string.size + 1; U64 string_offset = offset; U64 string_size = (offset + bytes_read) - string_offset; @@ -451,7 +416,7 @@ dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_ case DW_Form_ExprLoc: { U64 size = 0; - bytes_read = based_range_read_uleb128(base, range, offset, &size); + bytes_read = dw_based_range_read_uleb128(base, range, offset, &size); form_value.v[0] = offset + bytes_read; form_value.v[1] = size; bytes_read += size; @@ -631,8 +596,8 @@ dw_v4_range_list_from_range_offset(Arena *arena, DW_SectionArray *sections, U64 { U64 v0 = 0; U64 v1 = 0; - read_off += based_range_read(base, rng, read_off, addr_size, &v0); - read_off += based_range_read(base, rng, read_off, addr_size, &v1); + read_off += dw_based_range_read(base, rng, read_off, addr_size, &v0); + read_off += dw_based_range_read(base, rng, read_off, addr_size, &v1); //- rjf: base address entry if((addr_size == 4 && v0 == 0xffffffff) || @@ -681,15 +646,15 @@ dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_SectionArray *section U64 cu_info_off = 0; U64 cu_info_len = 0; cursor += dw_based_range_read_length(base, rng, cursor, &table_length); - cursor += based_range_read_struct(base, rng, cursor, &unit_version); - cursor += based_range_read(base, rng, cursor, off_size, &cu_info_off); + cursor += dw_based_range_read_struct(base, rng, cursor, &unit_version); + cursor += dw_based_range_read(base, rng, cursor, off_size, &cu_info_off); cursor += dw_based_range_read_length(base, rng, cursor, &cu_info_len); for(;;) { U64 info_off = 0; { - U64 bytes_read = based_range_read(base, rng, cursor, off_size, &info_off); + U64 bytes_read = dw_based_range_read(base, rng, cursor, off_size, &info_off); cursor += bytes_read; if(bytes_read == 0) { @@ -700,7 +665,7 @@ dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_SectionArray *section //- rjf: if we got a nonzero .debug_info offset, we've found a valid entry. if(info_off != 0) { - String8 string = based_range_read_string(base, rng, cursor); + String8 string = dw_based_range_read_string(base, rng, cursor); cursor += string.size + 1; U64 hash = dw_hash_from_string(string); @@ -727,8 +692,8 @@ dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_SectionArray *section } cursor += bytes_read; } - cursor += based_range_read_struct(base, rng, cursor, &unit_version); - cursor += based_range_read(base, rng, cursor, off_size, &cu_info_off); + cursor += dw_based_range_read_struct(base, rng, cursor, &unit_version); + cursor += dw_based_range_read(base, rng, cursor, off_size, &cu_info_off); cursor += dw_based_range_read_length(base, rng, cursor, &cu_info_len); } } @@ -759,12 +724,12 @@ dw_v5_offset_from_offs_section_base_index(DW_SectionArray *sections, DW_SectionK //- rjf: parse version U16 version = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &version); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &version); Assert(version == 5); // must be 5 as of V5. //- rjf: parse padding U16 padding = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &padding); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &padding); Assert(padding == 0); // must be 0 as of V5. //- rjf: read @@ -803,28 +768,28 @@ dw_v5_addr_from_addrs_section_base_index(DW_SectionArray *sections, DW_SectionKi //- rjf: parse version U16 version = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &version); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &version); Assert(version == 5); // must be 5 as of V5. //- rjf: parse address size U8 address_size = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &address_size); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &address_size); //- rjf: parse segment selector size U8 segment_selector_size = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &segment_selector_size); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &segment_selector_size); //- rjf: read U64 entry_size = address_size + segment_selector_size; U64 count = (unit_length - sizeof(U16)*2) / entry_size; if(0 <= index && index < count) { - void *entry = (U8 *)based_range_ptr(sec_base, rng, cursor) + entry_size*index; + void *entry = (U8 *)dw_based_range_ptr(sec_base, rng, cursor) + entry_size*index; Rng1U64 entry_rng = rng_1u64(0, entry_size); U64 segment = 0; U64 addr = 0; - based_range_read(entry, entry_rng, 0, sizeof(segment), &segment); - based_range_read(entry, entry_rng, segment_selector_size, sizeof(addr), &addr); + dw_based_range_read(entry, entry_rng, 0, sizeof(segment), &segment); + dw_based_range_read(entry, entry_rng, segment_selector_size, sizeof(addr), &addr); result = addr; } @@ -861,24 +826,24 @@ dw_v5_sec_offset_from_rnglist_or_loclist_section_base_index(DW_SectionArray *sec //- rjf: parse version U16 version = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &version); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &version); Assert(version == 5); // must be 5 as of V5. //- rjf: parse address size U8 address_size = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &address_size); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &address_size); //- rjf: parse segment selector size U8 segment_selector_size = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &segment_selector_size); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &segment_selector_size); //- rjf: parse offset entry count U32 offset_entry_count = 0; - cursor += based_range_read_struct(sec_base, rng, cursor, &offset_entry_count); + cursor += dw_based_range_read_struct(sec_base, rng, cursor, &offset_entry_count); //- rjf: read from offsets array U64 table_off = cursor; - void *offsets_arr = based_range_ptr(sec_base, rng, cursor); + void *offsets_arr = dw_based_range_ptr(sec_base, rng, cursor); if(0 <= index && index < (U64)offset_entry_count) { U64 rnglist_offset = 0; @@ -908,7 +873,7 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW for(B32 done = 0; !done;) { U8 kind8 = 0; - cursor += based_range_read_struct(base, rng, cursor, &kind8); + cursor += dw_based_range_read_struct(base, rng, cursor, &kind8); DW_RngListEntryKind kind = (DW_RngListEntryKind)kind8; switch(kind) @@ -923,7 +888,7 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW case DW_RngListEntryKind_BaseAddressX: { U64 base_addr_idx = 0; - cursor += based_range_read_uleb128(base, rng, cursor, &base_addr_idx); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &base_addr_idx); base_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, base_addr_idx); } break; @@ -931,8 +896,8 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW { U64 start_addr_idx = 0; U64 end_addr_idx = 0; - cursor += based_range_read_uleb128(base, rng, cursor, &start_addr_idx); - cursor += based_range_read_uleb128(base, rng, cursor, &end_addr_idx); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &start_addr_idx); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &end_addr_idx); U64 start_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, start_addr_idx); U64 end_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, end_addr_idx); rng1u64_list_push(arena, &list, rng_1u64(start_addr, end_addr)); @@ -942,8 +907,8 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW { U64 start_addr_idx = 0; U64 length = 0; - cursor += based_range_read_uleb128(base, rng, cursor, &start_addr_idx); - cursor += based_range_read_uleb128(base, rng, cursor, &length); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &start_addr_idx); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &length); U64 start_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, start_addr_idx); U64 end_addr = start_addr + length; rng1u64_list_push(arena, &list, rng_1u64(start_addr, end_addr)); @@ -953,8 +918,8 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW { U64 start_offset = 0; U64 end_offset = 0; - cursor += based_range_read_uleb128(base, rng, cursor, &start_offset); - cursor += based_range_read_uleb128(base, rng, cursor, &end_offset); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &start_offset); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &end_offset); rng1u64_list_push(arena, &list, rng_1u64(start_offset + base_addr, end_offset + base_addr)); } break; @@ -963,7 +928,7 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW case DW_RngListEntryKind_BaseAddress: { U64 new_base_addr = 0; - cursor += based_range_read(base, rng, cursor, addr_size, &new_base_addr); + cursor += dw_based_range_read(base, rng, cursor, addr_size, &new_base_addr); base_addr = new_base_addr; } break; @@ -971,8 +936,8 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW { U64 start = 0; U64 end = 0; - cursor += based_range_read(base, rng, cursor, addr_size, &start); - cursor += based_range_read(base, rng, cursor, addr_size, &end); + cursor += dw_based_range_read(base, rng, cursor, addr_size, &start); + cursor += dw_based_range_read(base, rng, cursor, addr_size, &end); rng1u64_list_push(arena, &list, rng_1u64(start, end)); } break; @@ -980,8 +945,8 @@ dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW { U64 start = 0; U64 length = 0; - cursor += based_range_read(base, rng, cursor, addr_size, &start); - cursor += based_range_read_uleb128(base, rng, cursor, &length); + cursor += dw_based_range_read(base, rng, cursor, addr_size, &start); + cursor += dw_based_range_read_uleb128(base, rng, cursor, &length); rng1u64_list_push(arena, &list, rng_1u64(start, start+length)); } break; } @@ -1085,7 +1050,7 @@ dw_attrib_value_from_form_value(DW_SectionArray *sections, U64 str_offset = dw_v5_offset_from_offs_section_base_index(sections, DW_Section_StrOffsets, resolve_params.debug_str_offs_base, str_index); void *base = dw_base_from_sec(sections, section); Rng1U64 range = dw_range_from_sec(sections, section); - String8 string = based_range_read_string(base, range, str_offset); + String8 string = dw_based_range_read_string(base, range, str_offset); value.section = section; value.v[0] = str_offset; value.v[1] = value.v[0] + string.size; @@ -1136,7 +1101,7 @@ dw_attrib_value_from_form_value(DW_SectionArray *sections, DW_SectionKind section = DW_Section_Str; void *base = dw_base_from_sec(sections, section); Rng1U64 range = dw_range_from_sec(sections, section); - String8 string = based_range_read_string(base, range, form_value.v[0]); + String8 string = dw_based_range_read_string(base, range, form_value.v[0]); value.section = section; value.v[0] = form_value.v[0]; value.v[1] = value.v[0] + string.size; @@ -1147,7 +1112,7 @@ dw_attrib_value_from_form_value(DW_SectionArray *sections, DW_SectionKind section = DW_Section_LineStr; void *base = dw_base_from_sec(sections, section); Rng1U64 range = dw_range_from_sec(sections, section); - String8 string = based_range_read_string(base, range, form_value.v[0]); + String8 string = dw_based_range_read_string(base, range, form_value.v[0]); value.section = section; value.v[0] = form_value.v[0]; value.v[1] = value.v[0] + string.size; @@ -1193,7 +1158,7 @@ dw_string_from_attrib_value(DW_SectionArray *sections, DW_AttribValue value) Rng1U64 range = dw_range_from_sec(sections, section_kind); String8 string = {0}; - string.str = (U8 *)based_range_ptr(base, range, value.v[0]); + string.str = (U8 *)dw_based_range_ptr(base, range, value.v[0]); string.size = value.v[1] - value.v[0]; return string; } @@ -1236,7 +1201,8 @@ dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, DW_Language lang, U64 address_size, U64 info_off, - U64 abbrev_off) + U64 abbrev_off, + B32 relaxed) { //- rjf: set up prereqs DW_Mode info_mode = sections->v[DW_Section_Info].mode; @@ -1267,18 +1233,17 @@ dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, //- rjf: extract attrib info from abbrev DW_AttribKind attrib_kind = (DW_AttribKind)abbrev.id; DW_FormKind form_kind = (DW_FormKind)abbrev.sub_kind; - DW_AttribClass attrib_class = dw_pick_attrib_value_class(ver, ext, lang, attrib_kind, form_kind); + DW_AttribClass attrib_class = dw_pick_attrib_value_class(ver, ext, lang, relaxed, attrib_kind, form_kind); //- rjf: parse the form value from the file DW_AttribValue form_value = {0}; if(good_abbrev) { - // NOTE(nick): This is a special case form. Basically it let's user to - // define attribute form in the .debug_info. + // Special case form that allows user to encode attribute form in .debug_info if(form_kind == DW_Form_Indirect) { U64 override_form_kind = 0; - info_read_off += based_range_read_uleb128(info_base, info_range, info_read_off, &override_form_kind); + info_read_off += dw_based_range_read_uleb128(info_base, info_range, info_read_off, &override_form_kind); form_kind = (DW_FormKind)override_form_kind; } U64 bytes_read = dw_based_range_read_attrib_form_value(info_base, info_range, info_read_off, info_mode, address_size, @@ -1314,7 +1279,8 @@ dw_tag_from_info_offset(Arena *arena, DW_Ext ext, DW_Language lang, U64 address_size, - U64 info_offset) + U64 info_offset, + B32 relaxed) { void *info_base = dw_base_from_sec(sections, DW_Section_Info); Rng1U64 info_range = dw_range_from_sec(sections, DW_Section_Info); @@ -1328,7 +1294,7 @@ dw_tag_from_info_offset(Arena *arena, //- rjf: read abbrev ID U64 abbrev_id = 0; - info_read_off += based_range_read_uleb128(info_base, info_range, info_read_off, &abbrev_id); + info_read_off += dw_based_range_read_uleb128(info_base, info_range, info_read_off, &abbrev_id); B32 good_abbrev_id = abbrev_id != 0; //- rjf: figure out abbrev offset for this ID @@ -1356,7 +1322,7 @@ dw_tag_from_info_offset(Arena *arena, DW_AttribList attribs = {0}; if(good_tag_abbrev) { - DW_AttribListParseResult attribs_parse = dw_parse_attrib_list_from_info_abbrev_offsets(arena, sections, ver, ext, lang, address_size, info_read_off, abbrev_read_off); + DW_AttribListParseResult attribs_parse = dw_parse_attrib_list_from_info_abbrev_offsets(arena, sections, ver, ext, lang, address_size, info_read_off, abbrev_read_off, relaxed); attribs_info_off = info_read_off; attribs_abbrev_off = abbrev_read_off; info_read_off = attribs_parse.max_info_off; @@ -1460,7 +1426,7 @@ dw_v5_header_offset_from_table_offset(DW_SectionArray *sections, DW_SectionKind // rjf: try max header, and if it works, the header is the max size, otherwise we will // need to rely on the min header size U32 first32 = 0; - based_range_read_struct(addr_base, addr_rng, past_header-max_header_size, &first32); + dw_based_range_read_struct(addr_base, addr_rng, past_header-max_header_size, &first32); if(first32 == max_U32) { header_size = max_header_size; @@ -1501,8 +1467,40 @@ dw_comp_unit_ranges_from_info(Arena *arena, DW_Section info) return result; } +internal DW_Ext +dw_ext_from_params(String8 producer, Arch arch, ImageType image_type) +{ + DW_Ext ext = DW_Ext_Null; + switch (image_type) { + case Image_Null: break; + case Image_COFF_PE: { + if (str8_match(str8_lit("clang"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + ext = DW_Ext_GNU | DW_Ext_LLVM; + } else if (str8_match(str8_lit("GNU"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + ext = DW_Ext_GNU; + } + } break; + case Image_ELF32: + case Image_ELF64: { + if (str8_match(str8_lit("clang"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + ext = DW_Ext_GNU | DW_Ext_LLVM; + } else if (str8_match(str8_lit("GNU"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + ext = DW_Ext_GNU; + } + } break; + case Image_Macho: { + if (str8_match(str8_lit("clang"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + ext = DW_Ext_LLVM | DW_Ext_APPLE; + } else if (str8_match(str8_lit("GNU"), producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { + ext = DW_Ext_GNU | DW_Ext_APPLE; + } + } break; + } + return ext; +} + internal DW_CompRoot -dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) +dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range, B32 relaxed) { Temp scratch = scratch_begin(&arena, 1); @@ -1524,7 +1522,7 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) B32 got_version = 0; DW_Version version = 0; U64 unit_off = version_off; - if(based_range_read_struct(info_base, range, version_off, &version)) + if(dw_based_range_read_struct(info_base, range, version_off, &version)) { unit_off += sizeof(version); got_version = 1; @@ -1544,28 +1542,28 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) default: break; case DW_Version_2: { abbrev_base = 0; - next_off += based_range_read(info_base, range, next_off, 4, &abbrev_base); - next_off += based_range_read(info_base, range, next_off, 1, &address_size); + next_off += dw_based_range_read(info_base, range, next_off, 4, &abbrev_base); + next_off += dw_based_range_read(info_base, range, next_off, 1, &address_size); got_unit_kind = 1; } break; case DW_Version_3: case DW_Version_4: { next_off += dw_based_range_read_length(info_base, range, next_off, &abbrev_base); - next_off += based_range_read(info_base, range, next_off, 1, &address_size); + next_off += dw_based_range_read(info_base, range, next_off, 1, &address_size); got_unit_kind = 1; } break; case DW_Version_5: { - next_off += based_range_read_struct(info_base, range, next_off, &unit_kind); - next_off += based_range_read(info_base, range, next_off, 1, &address_size); + next_off += dw_based_range_read_struct(info_base, range, next_off, &unit_kind); + next_off += dw_based_range_read(info_base, range, next_off, 1, &address_size); next_off += dw_based_range_read_length(info_base, range, next_off, &abbrev_base); got_unit_kind = 1; //- rjf: parse DWO ID if appropriate if(unit_kind == DW_CompUnitKind_Skeleton || is_info_dwo) { - next_off += based_range_read(info_base, range, next_off, 8, &spec_dwo_id); + next_off += dw_based_range_read(info_base, range, next_off, 8, &spec_dwo_id); } } break; } @@ -1584,7 +1582,7 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) if(got_unit_kind) { U64 comp_root_tag_off = range.min + next_off; - comp_unit_tag = dw_tag_from_info_offset(scratch.arena, sections, abbrev_table, version, DW_Ext_Null, DW_Language_Null, address_size, comp_root_tag_off); + comp_unit_tag = dw_tag_from_info_offset(scratch.arena, sections, abbrev_table, version, DW_Ext_Null, DW_Language_Null, address_size, comp_root_tag_off, relaxed); got_comp_unit_tag = 1; } @@ -1630,7 +1628,7 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) String8 external_dwo_name = {0}; String8 external_gnu_dwo_name = {0}; U64 gnu_dwo_id = 0; - U64 language = 0; + DW_Language language = 0; U64 name_case = 0; B32 use_utf8 = 0; U64 low_pc = 0; @@ -1665,13 +1663,13 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) case DW_Attrib_CompDir: compile_dir = dw_string_from_attrib_value(sections, value); break; case DW_Attrib_DwoName: external_dwo_name = dw_string_from_attrib_value(sections, value); break; case DW_Attrib_GNU_DwoName: external_gnu_dwo_name = dw_string_from_attrib_value(sections, value); break; - case DW_Attrib_GNU_DwoId: gnu_dwo_id = value.v[0]; break; - case DW_Attrib_Language: language = value.v[0]; break; - case DW_Attrib_IdentifierCase: name_case = value.v[0]; break; - case DW_Attrib_UseUtf8: use_utf8 = (B32)value.v[0]; break; - case DW_Attrib_LowPc: low_pc = value.v[0]; break; + case DW_Attrib_GNU_DwoId: gnu_dwo_id = value.v[0]; break; + case DW_Attrib_Language: language = safe_cast_u32(value.v[0]); break; + case DW_Attrib_IdentifierCase: name_case = value.v[0]; break; + case DW_Attrib_UseUtf8: use_utf8 = (B32)value.v[0]; break; + case DW_Attrib_LowPc: low_pc = value.v[0]; break; case DW_Attrib_HighPc: high_pc = value.v[0]; high_pc_is_relative = attrib->value_class != DW_AttribClass_Address; break; - case DW_Attrib_Ranges: ranges_attrib_value = value; break; + case DW_Attrib_Ranges: ranges_attrib_value = value; break; case DW_Attrib_StmtList: line_base = value.v[0]; break; default: break; } @@ -1686,7 +1684,6 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) unit.size = size; unit.kind = unit_kind; unit.version = version; - unit.ext = DW_Ext_Null; unit.address_size = address_size; unit.abbrev_off = abbrev_base; unit.info_off = range.min; @@ -1700,10 +1697,10 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) unit.stroffs_base = resolve_params.debug_str_offs_base; //- rjf: fill out general info - unit.name = name; - unit.producer = producer; - unit.compile_dir = compile_dir; - unit.external_dwo_name = external_dwo_name.size != 0 ? external_dwo_name : external_gnu_dwo_name; + unit.name = name; + unit.producer = producer; + unit.compile_dir = compile_dir; + unit.external_dwo_name = external_dwo_name.size ? external_dwo_name : external_gnu_dwo_name; if(external_dwo_name.size) { unit.dwo_id = spec_dwo_id; @@ -1712,13 +1709,14 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) { unit.dwo_id = gnu_dwo_id; } - unit.language = (DW_Language)language; - unit.name_case = name_case; - unit.use_utf8 = use_utf8; - unit.line_off = line_base; - unit.low_pc = low_pc; - unit.high_pc = high_pc; + unit.language = language; + unit.name_case = name_case; + unit.use_utf8 = use_utf8; + unit.line_off = line_base; + unit.low_pc = low_pc; + unit.high_pc = high_pc; unit.ranges_attrib_value = ranges_attrib_value; + unit.base_addr = unit.low_pc; //- rjf: fill fixup of low/high PC situation if(high_pc_is_relative) @@ -1726,24 +1724,6 @@ dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range) unit.high_pc += unit.low_pc; } - //- rjf: fill base address - { - unit.base_addr = unit.low_pc; - } - - //- rjf: build+fill directory and file tables - { - DW_Mode line_mode = dw_mode_from_sec(sections, DW_Section_Line); - void *line_base = dw_base_from_sec(sections, DW_Section_Line); - Rng1U64 line_rng = dw_range_from_sec(sections, DW_Section_Line); - DW_LineVMHeader vm_header = {0}; - U64 read_size = dw_read_line_vm_header(arena, line_base, line_rng, unit.line_off, line_mode, sections, &unit, &vm_header); - if (read_size > 0) { - unit.dir_table = vm_header.dir_table; - unit.file_table = vm_header.file_table; - } - } - scratch_end(scratch); return unit; } @@ -1802,8 +1782,7 @@ dw_push_line(Arena *arena, DW_LineTableParseResult *tbl, DW_LineVMState *vm_stat if(seq == 0 || start_of_sequence) { // ERROR! do not emit sequences with only one line... - if (seq) Assert(seq->count > 1); - + Assert(seq && seq->count > 1); seq = dw_push_line_seq(arena, tbl); } @@ -1827,9 +1806,11 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ Rng1U64 line_info_range = dw_range_from_sec(sections, DW_Section_Line); U64 read_off_start = root->line_off - line_info_range.min; U64 cursor = read_off_start; + + DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(root); DW_LineVMHeader vm_header = {0}; - cursor += dw_read_line_vm_header(arena, base, line_info_range, cursor, mode, sections, root, &vm_header); + cursor += dw_read_line_vm_header(arena, base, line_info_range, cursor, mode, sections, resolve_params, root->compile_dir, root->name, &vm_header); //- rjf: prep state for VM DW_LineVMState vm_state = {0}; @@ -1842,7 +1823,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ for (;!error && cursor < vm_header.unit_opl;) { //- rjf: parse opcode U8 opcode = 0; - cursor += based_range_read_struct(base, line_info_range, cursor, &opcode); + cursor += dw_based_range_read_struct(base, line_info_range, cursor, &opcode); //- rjf: do opcode action switch (opcode) { @@ -1887,7 +1868,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ for(U8 i = 0; i < num_operands; ++i) { U64 operand = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &operand); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &operand); } } else @@ -1913,28 +1894,28 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_StdOpcode_AdvancePc: { U64 advance = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &advance); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &advance); dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); } break; case DW_StdOpcode_AdvanceLine: { S64 s = 0; - cursor += based_range_read_sleb128(base, line_info_range, cursor, &s); + cursor += dw_based_range_read_sleb128(base, line_info_range, cursor, &s); vm_state.line += s; } break; case DW_StdOpcode_SetFile: { U64 file_index = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &file_index); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &file_index); vm_state.file_index = file_index; } break; case DW_StdOpcode_SetColumn: { U64 column = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &column); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &column); vm_state.column = column; } break; @@ -1957,7 +1938,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_StdOpcode_FixedAdvancePc: { U16 operand = 0; - cursor += based_range_read_struct(base, line_info_range, cursor, &operand); + cursor += dw_based_range_read_struct(base, line_info_range, cursor, &operand); vm_state.address += operand; vm_state.op_index = 0; } break; @@ -1975,7 +1956,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_StdOpcode_SetIsa: { U64 v = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &v); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &v); vm_state.isa = v; } break; @@ -1983,10 +1964,10 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_StdOpcode_ExtendedOpcode: { U64 length = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &length); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &length); U64 start_off = cursor; U8 extended_opcode = 0; - cursor += based_range_read_struct(base, line_info_range, cursor, &extended_opcode); + cursor += dw_based_range_read_struct(base, line_info_range, cursor, &extended_opcode); switch (extended_opcode) { case DW_ExtOpcode_EndSequence: @@ -2000,7 +1981,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_ExtOpcode_SetAddress: { U64 address = 0; - cursor += based_range_read(base, line_info_range, cursor, root->address_size, &address); + cursor += dw_based_range_read(base, line_info_range, cursor, root->address_size, &address); vm_state.address = address; vm_state.op_index = 0; vm_state.busted_seq = address != 0; // !(dbg->acceptable_vrange.min <= address && address < dbg->acceptable_vrange.max); @@ -2008,14 +1989,14 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_ExtOpcode_DefineFile: { - String8 file_name = based_range_read_string(base, line_info_range, cursor); + String8 file_name = dw_based_range_read_string(base, line_info_range, cursor); U64 dir_index = 0; U64 modify_time = 0; U64 file_size = 0; cursor += file_name.size + 1; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &dir_index); - cursor += based_range_read_uleb128(base, line_info_range, cursor, &modify_time); - cursor += based_range_read_uleb128(base, line_info_range, cursor, &file_size); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &dir_index); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &modify_time); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &file_size); // TODO(rjf): Not fully implemented. By the DWARF V4 spec, the above is // all that needs to be parsed, but the rest of the work that needs to @@ -2030,7 +2011,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ case DW_ExtOpcode_SetDiscriminator: { U64 v = 0; - cursor += based_range_read_uleb128(base, line_info_range, cursor, &v); + cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &v); vm_state.discriminator = v; } break; @@ -2039,7 +2020,7 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ U64 num_skip = cursor - (start_off + length); cursor += num_skip; - if (based_range_ptr(base, line_info_range, cursor) == 0 || start_off + length > cursor) { + if (dw_based_range_ptr(base, line_info_range, cursor) == 0 || start_off + length > cursor) { error = 1; } @@ -2051,13 +2032,53 @@ dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_ return result; } +internal String8 +dw_path_from_file_idx(Arena *arena, DW_LineVMHeader *vm, U64 file_idx) +{ + Temp scratch = scratch_begin(&arena, 1); + + DW_LineFile *lf = &vm->file_table.v[file_idx]; + String8 dir = vm->dir_table.v[lf->dir_idx]; + PathStyle style = path_style_from_str8(dir); + if (style == PathStyle_Null || style == PathStyle_Relative) { + style = path_style_from_str8(lf->file_name); + } + + String8List path_list = {0}; + + if (str8_match(str8_lit(".."), dir, StringMatchFlag_RightSideSloppy)) { + String8List comp_dir_list = str8_split_path(scratch.arena, vm->dir_table.v[0]); + str8_list_concat_in_place(&path_list, &comp_dir_list); + } + + String8List dir_list = str8_split_path(scratch.arena, dir); + str8_list_concat_in_place(&path_list, &dir_list); + + str8_list_push(scratch.arena, &path_list, lf->file_name); + + str8_path_list_resolve_dots_in_place(&path_list, style); + + String8 path = str8_path_list_join_by_style(arena, &path_list, style); + + scratch_end(scratch); + return path; +} + internal U64 -dw_read_line_file(void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_CompRoot *unit, U8 address_size, U64 format_count, Rng1U64 *formats, DW_LineFile *line_file_out) +dw_read_line_file(void *line_base, + Rng1U64 line_rng, + U64 line_off, + DW_Mode mode, + DW_SectionArray *sections, + DW_AttribValueResolveParams resolve_params, + U8 address_size, + U64 format_count, + Rng1U64 *formats, + DW_LineFile *line_file_out) { MemoryZeroStruct(line_file_out); - DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(unit); - U64 line_off_start = line_off; + U64 line_off_start = line_off; for (U64 format_idx = 0; format_idx < format_count; ++format_idx) { DW_LNCT lnct = (DW_LNCT)formats[format_idx].min; @@ -2121,55 +2142,55 @@ dw_read_line_file(void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, } internal U64 -dw_read_line_vm_header(Arena *arena, - void *line_base, - Rng1U64 line_rng, - U64 line_off, - DW_Mode mode, - DW_SectionArray *sections, - DW_CompRoot *unit, - DW_LineVMHeader *header_out) +dw_read_line_vm_header(Arena *arena, + void *line_base, + Rng1U64 line_rng, + U64 line_off, + DW_Mode mode, + DW_SectionArray *sections, + DW_AttribValueResolveParams resolve_params, + String8 compile_dir, + String8 unit_name, + DW_LineVMHeader *header_out) { - U64 line_off_start = line_off; - Temp scratch = scratch_begin(&arena, 1); + + MemoryZeroStruct(header_out); //- rjf: parse unit length - header_out->unit_length = 0; - { - line_off += dw_based_range_read_length(line_base, line_rng, line_off, &header_out->unit_length); - } - - header_out->unit_opl = line_off + header_out->unit_length; + U64 unit_length = 0; + U64 unit_length_size = dw_based_range_read_length(line_base, line_rng, line_off, &unit_length); + header_out->unit_length = unit_length; + header_out->unit_opl = line_off + unit_length + unit_length_size; + + U64 cursor = unit_length_size; + Rng1U64 parse_rng = rng_1u64(line_off, header_out->unit_opl); + //- rjf: parse version and header length - line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->version); - - if (header_out->version == DW_Version_5) { - line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->address_size); - line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->segment_selector_size); - } + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->version); + if(header_out->version == DW_Version_5) { - U64 off_size = dw_offset_size_from_mode(mode); - line_off += based_range_read(line_base, line_rng, line_off, off_size, &header_out->header_length); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->address_size); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->segment_selector_size); } + cursor += dw_based_range_read(line_base, parse_rng, cursor, dw_offset_size_from_mode(mode), &header_out->header_length); + //- rjf: calculate program offset - header_out->program_off = line_off + header_out->header_length; + header_out->program_off = parse_rng.min + cursor + header_out->header_length; //- rjf: parse minimum instruction length - { - line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->min_inst_len); - } + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->min_inst_len); //- rjf: parse max ops for instruction - switch (header_out->version) + switch(header_out->version) { case DW_Version_5: case DW_Version_4: { - line_off += based_range_read_struct(line_base, line_rng, line_off, &header_out->max_ops_for_inst); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->max_ops_for_inst); Assert(header_out->max_ops_for_inst > 0); } break; case DW_Version_3: @@ -2182,88 +2203,89 @@ dw_read_line_vm_header(Arena *arena, } //- rjf: parse rest of program info - based_range_read_struct(line_base, line_rng, line_off + 0 * sizeof(U8), &header_out->default_is_stmt); - based_range_read_struct(line_base, line_rng, line_off + 1 * sizeof(U8), &header_out->line_base); - based_range_read_struct(line_base, line_rng, line_off + 2 * sizeof(U8), &header_out->line_range); - based_range_read_struct(line_base, line_rng, line_off + 3 * sizeof(U8), &header_out->opcode_base); - line_off += 4 * sizeof(U8); - Assert(header_out->opcode_base != 0 && header_out->opcode_base > 0); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->default_is_stmt); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->line_base); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->line_range); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->opcode_base); //- rjf: calculate opcode length array - header_out->num_opcode_lens = header_out->opcode_base - 1u; - header_out->opcode_lens = (U8 *)based_range_ptr(line_base, line_rng, line_off); - line_off += header_out->num_opcode_lens * sizeof(U8); + header_out->num_opcode_lens = header_out->opcode_base > 0 ? header_out->opcode_base - 1u : 0; + header_out->opcode_lens = dw_based_range_ptr_size(line_base, parse_rng, cursor, header_out->num_opcode_lens * sizeof(header_out->opcode_lens[0])); + cursor += header_out->num_opcode_lens * sizeof(header_out->opcode_lens[0]); - if (header_out->version == DW_Version_5) { + if(header_out->version == DW_Version_5) + { //- parse directory names U8 directory_entry_format_count = 0; - line_off += based_range_read_struct(line_base, line_rng, line_off, &directory_entry_format_count); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &directory_entry_format_count); Assert(directory_entry_format_count == 1); Rng1U64 *directory_entry_formats = push_array(scratch.arena, Rng1U64, directory_entry_format_count); - for (U8 format_idx = 0; format_idx < directory_entry_format_count; ++format_idx) + for(U8 format_idx = 0; format_idx < directory_entry_format_count; ++format_idx) { U64 content_type_code = 0, form_code = 0; - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &content_type_code); - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &form_code); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &content_type_code); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &form_code); directory_entry_formats[format_idx] = rng_1u64(content_type_code, form_code); } + U64 directories_count = 0; - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &directories_count); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &directories_count); header_out->dir_table.count = directories_count; header_out->dir_table.v = push_array(arena, String8, header_out->dir_table.count); - for (U64 dir_idx = 0; dir_idx < directories_count; ++dir_idx) + for(U64 dir_idx = 0; dir_idx < directories_count; ++dir_idx) { DW_LineFile line_file; - line_off += dw_read_line_file(line_base, - line_rng, - line_off, - mode, - sections, - unit, - header_out->address_size, - directory_entry_format_count, - directory_entry_formats, - &line_file); + cursor += dw_read_line_file(line_base, + parse_rng, + cursor, + mode, + sections, + resolve_params, + header_out->address_size, + directory_entry_format_count, + directory_entry_formats, + &line_file); header_out->dir_table.v[dir_idx] = push_str8_copy(arena, line_file.file_name); } + //- parse file table U8 file_name_entry_format_count = 0; - line_off += based_range_read_struct(line_base, line_rng, line_off, &file_name_entry_format_count); + cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &file_name_entry_format_count); Rng1U64 *file_name_entry_formats = push_array(scratch.arena, Rng1U64, file_name_entry_format_count); - for (U8 format_idx = 0; format_idx < file_name_entry_format_count; ++format_idx) + for(U8 format_idx = 0; format_idx < file_name_entry_format_count; ++format_idx) { U64 content_type_code = 0, form_code = 0; - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &content_type_code); - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &form_code); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &content_type_code); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &form_code); file_name_entry_formats[format_idx] = rng_1u64(content_type_code, form_code); } + U64 file_names_count = 0; - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &file_names_count); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &file_names_count); header_out->file_table.count = file_names_count; header_out->file_table.v = push_array(arena, DW_LineFile, header_out->file_table.count); - for (U64 file_idx = 0; file_idx < file_names_count; ++file_idx) + for(U64 file_idx = 0; file_idx < file_names_count; ++file_idx) { - line_off += dw_read_line_file(line_base, - line_rng, - line_off, - mode, - sections, - unit, - header_out->address_size, - file_name_entry_format_count, - file_name_entry_formats, - &header_out->file_table.v[file_idx]); + cursor += dw_read_line_file(line_base, + parse_rng, + cursor, + mode, + sections, + resolve_params, + header_out->address_size, + file_name_entry_format_count, + file_name_entry_formats, + &header_out->file_table.v[file_idx]); } } - else + else { - String8List dir_list = {0}; - - str8_list_push(scratch.arena, &dir_list, unit->compile_dir); + String8List dir_list = {0}; + str8_list_push(scratch.arena, &dir_list, compile_dir); for (;;) { - String8 dir = based_range_read_string(line_base, line_rng, line_off); - line_off += dir.size + 1; + String8 dir = dw_based_range_read_string(line_base, parse_rng, cursor); + cursor += dir.size + 1; if (dir.size == 0) { break; @@ -2276,25 +2298,25 @@ dw_read_line_vm_header(Arena *arena, //- rjf: push 0-index file (compile file) { DW_LineVMFileNode *node = push_array(scratch.arena, DW_LineVMFileNode, 1); - node->file.file_name = unit->name; + node->file.file_name = unit_name; SLLQueuePush(file_list.first, file_list.last, node); file_list.node_count += 1; } - for (;;) + for(;;) { - String8 file_name = based_range_read_string(line_base, line_rng, line_off); + String8 file_name = dw_based_range_read_string(line_base, parse_rng, cursor); U64 dir_index = 0; U64 modify_time = 0; U64 file_size = 0; - line_off += file_name.size + 1; - if (file_name.size == 0) + cursor += file_name.size + 1; + if(file_name.size == 0) { break; } - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &dir_index); - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &modify_time); - line_off += based_range_read_uleb128(line_base, line_rng, line_off, &file_size); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &dir_index); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &modify_time); + cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &file_size); DW_LineVMFileNode *node = push_array(scratch.arena, DW_LineVMFileNode, 1); node->file.file_name = file_name; @@ -2309,6 +2331,7 @@ dw_read_line_vm_header(Arena *arena, { header_out->dir_table.count = dir_list.node_count; header_out->dir_table.v = push_array(arena, String8, header_out->dir_table.count); + String8Node *n = dir_list.first; for(U64 idx = 0; n != 0 && idx < header_out->dir_table.count; idx += 1, n = n->next) { @@ -2319,7 +2342,8 @@ dw_read_line_vm_header(Arena *arena, //- rjf: build file table { header_out->file_table.count = file_list.node_count; - header_out->file_table.v = push_array(arena, DW_LineFile, header_out->file_table.count); + header_out->file_table.v = push_array(arena, DW_LineFile, header_out->file_table.count); + U64 file_idx = 0; DW_LineVMFileNode *file_node = file_list.first; for(; file_node != 0; file_idx += 1, file_node = file_node->next) @@ -2331,10 +2355,8 @@ dw_read_line_vm_header(Arena *arena, } } } - - U64 result = line_off - line_off_start; scratch_end(scratch); - return result; + return cursor; } diff --git a/src/dwarf/dwarf_parse.h b/src/dwarf/dwarf_parse.h index f7b8b1b2..6cce84b8 100644 --- a/src/dwarf/dwarf_parse.h +++ b/src/dwarf/dwarf_parse.h @@ -50,6 +50,7 @@ struct DW_AbbrevTable typedef struct DW_Section DW_Section; struct DW_Section { + String8 name; String8 data; DW_Mode mode; B32 is_dwo; @@ -201,7 +202,6 @@ struct DW_CompRoot U64 size; DW_CompUnitKind kind; DW_Version version; - DW_Ext ext; U64 address_size; U64 abbrev_off; U64 info_off; @@ -228,10 +228,6 @@ struct DW_CompRoot U64 high_pc; DW_AttribValue ranges_attrib_value; U64 base_addr; - - // NOTE(rjf): Line/File Info For This Comp Unit - String8Array dir_table; - DW_LineVMFileArray file_table; }; //////////////////////////////// @@ -314,32 +310,32 @@ struct DW_TagStubList typedef struct DW_LineVMHeader DW_LineVMHeader; struct DW_LineVMHeader { - U64 unit_length; - U64 unit_opl; - U16 version; - U8 address_size; // NOTE(nick): duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str. - U8 segment_selector_size; - U64 header_length; - U64 program_off; - U8 min_inst_len; - U8 max_ops_for_inst; - U8 default_is_stmt; - S8 line_base; - U8 line_range; - U8 opcode_base; - U64 num_opcode_lens; - U8 *opcode_lens; - String8Array dir_table; - DW_LineVMFileArray file_table; + U64 unit_length; + U64 unit_opl; + DW_Version version; + U8 address_size; // Duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str. + U8 segment_selector_size; + U64 header_length; + U64 program_off; + U8 min_inst_len; + U8 max_ops_for_inst; + U8 default_is_stmt; + S8 line_base; + U8 line_range; + U8 opcode_base; + U64 num_opcode_lens; + U8 *opcode_lens; + String8Array dir_table; + DW_LineVMFileArray file_table; }; typedef struct DW_LineVMState DW_LineVMState; struct DW_LineVMState { - U64 address; // NOTE(nick): Address of a machine instruction. - U32 op_index; // NOTE(nick): This is used by the VLIW instructions to indicate index of operation inside the instruction. + U64 address; // Address of a machine instruction. + U32 op_index; // This is used by the VLIW instructions to indicate index of operation inside the instruction. - // NOTE(nick): Line table doesn't contain full path to a file, instead + // Line table doesn't contain full path to a file, instead // DWARF encodes path as two indices. First index will point into a directory // table, and second points into a file name table. U32 file_index; @@ -347,10 +343,10 @@ struct DW_LineVMState U32 line; U32 column; - B32 is_stmt; // NOTE(nick): Indicates that "address" points to place suitable for a breakpoint. - B32 basic_block; // NOTE(nick): Indicates that the "address" is inside a basic block. + B32 is_stmt; // Indicates that "address" points to place suitable for a breakpoint. + B32 basic_block; // Indicates that the "address" is inside a basic block. - // NOTE(nick): Indicates that "address" points to place where function starts. + // Indicates that "address" points to place where function starts. // Usually prologue is the place where compiler emits instructions to // prepare stack for a function. B32 prologue_end; @@ -421,16 +417,23 @@ struct DW_PubStringsTable //////////////////////////////// //~ rjf: Basic Helpers -internal U64 dw_hash_from_string(String8 string); -internal DW_AttribClass dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, DW_AttribKind attrib, DW_FormKind form_kind); +internal U64 dw_hash_from_string(String8 string); //////////////////////////////// //~ Specific Based Range Helpers -internal U64 dw_based_range_read_length(void *base, Rng1U64 range, U64 offset, U64 *out_value); -internal U64 dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev); -internal U64 dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev); -internal U64 dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_Mode mode, U64 address_size, DW_FormKind form_kind, U64 implicit_const, DW_AttribValue *form_value_out); +#define dw_based_range_read_struct(base, range, offset, out) dw_based_range_read(base, range, offset, sizeof(*out), out) + +internal U64 dw_based_range_read(void *base, Rng1U64 range, U64 offset, U64 size, void *out); +internal String8 dw_based_range_read_string(void *base, Rng1U64 range, U64 offset); +internal void* dw_based_range_ptr(void *base, Rng1U64 range, U64 offset); +internal void* dw_based_range_ptr_size(void *base, Rng1U64 range, U64 offset, U64 size); +internal U64 dw_based_range_read_uleb128(void *base, Rng1U64 range, U64 offset, U64 *out_value); +internal U64 dw_based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_value); +internal U64 dw_based_range_read_length(void *base, Rng1U64 range, U64 offset, U64 *out_value); +internal U64 dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev); +internal U64 dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev); +internal U64 dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_Mode mode, U64 address_size, DW_FormKind form_kind, U64 implicit_const, DW_AttribValue *form_value_out); internal DW_Mode dw_mode_from_sec(DW_SectionArray *sections, DW_SectionKind kind); internal B32 dw_sec_is_present(DW_SectionArray *sections, DW_SectionKind kind); @@ -473,8 +476,8 @@ internal Rng1U64List dw_range_list_from_high_low_pc_and_ranges_a //////////////////////////////// //~ rjf: Tag Parsing -internal DW_AttribListParseResult dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, DW_SectionArray *sections, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_off, U64 abbrev_off); -internal DW_Tag* dw_tag_from_info_offset(Arena *arena, DW_SectionArray *sections, DW_AbbrevTable abbrev_table, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_offset); +internal DW_AttribListParseResult dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, DW_SectionArray *sections, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_off, U64 abbrev_off, B32 relaxed); +internal DW_Tag* dw_tag_from_info_offset(Arena *arena, DW_SectionArray *sections, DW_AbbrevTable abbrev_table, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_offset, B32 relaxed); internal DW_TagStub dw_stub_from_tag(DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, DW_Tag *tag); //- rjf: line info @@ -484,8 +487,8 @@ internal void dw_line_vm_advance(DW_LineVMState *state, U64 advance, U64 min_ins internal DW_LineSeqNode* dw_push_line_seq(Arena* arena, DW_LineTableParseResult *parsed_tbl); internal DW_LineNode* dw_push_line(Arena *arena, DW_LineTableParseResult *tbl, DW_LineVMState *vm_state, B32 start_of_sequence); internal DW_LineTableParseResult dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_CompRoot *root); -internal U64 dw_read_line_file(void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_CompRoot *unit, U8 address_size, U64 format_count, Rng1U64 *formats, DW_LineFile *line_file_out); -internal U64 dw_read_line_vm_header(Arena *arena, void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_CompRoot *unit, DW_LineVMHeader *header_out); +internal U64 dw_read_line_file(void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, U8 address_size, U64 format_count, Rng1U64 *formats, DW_LineFile *line_file_out); +internal U64 dw_read_line_vm_header(Arena *arena, void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, String8 compile_dir, String8 unit_name, DW_LineVMHeader *header_out); #endif // DWARF_PARSE_H diff --git a/src/dwarf/dwarf_unwind.c b/src/dwarf/dwarf_unwind.c index bf86d59f..2731dd9c 100644 --- a/src/dwarf/dwarf_unwind.c +++ b/src/dwarf/dwarf_unwind.c @@ -338,7 +338,7 @@ dw_unwind_parse_pointer_x64(void *frame_base, Rng1U64 frame_range, DW_EhPtrCtx * case DW_EhPtrEnc_UData8: size_param = 8; goto ufixed; ufixed: { - based_range_read(frame_base, frame_range, pointer_off, size_param, &raw_pointer); + dw_based_range_read(frame_base, frame_range, pointer_off, size_param, &raw_pointer); after_pointer_off = pointer_off + size_param; } break; @@ -352,7 +352,7 @@ dw_unwind_parse_pointer_x64(void *frame_base, Rng1U64 frame_range, DW_EhPtrCtx * case DW_EhPtrEnc_SData8:size_param = 8; goto sfixed; sfixed: { - based_range_read(frame_base, frame_range, pointer_off, size_param, &raw_pointer); + dw_based_range_read(frame_base, frame_range, pointer_off, size_param, &raw_pointer); after_pointer_off = pointer_off + size_param; // sign extension U64 sign_bit = size_param*8 - 1; @@ -363,13 +363,13 @@ dw_unwind_parse_pointer_x64(void *frame_base, Rng1U64 frame_range, DW_EhPtrCtx * case DW_EhPtrEnc_ULEB128: { - U64 size = based_range_read_uleb128(frame_base, frame_range, pointer_off, &raw_pointer); + U64 size = dw_based_range_read_uleb128(frame_base, frame_range, pointer_off, &raw_pointer); after_pointer_off = pointer_off + size; } break; case DW_EhPtrEnc_SLEB128: { - U64 size = based_range_read_sleb128(frame_base, frame_range, pointer_off, + U64 size = dw_based_range_read_sleb128(frame_base, frame_range, pointer_off, (S64*)&raw_pointer); after_pointer_off = pointer_off + size; } break; @@ -415,34 +415,34 @@ dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off // get version U64 version_off = off; U8 version = 0; - based_range_read(base, range, version_off, 1, &version); + dw_based_range_read(base, range, version_off, 1, &version); // check version if (version == 1 || version == 3) { // read augmentation U64 augmentation_off = version_off + 1; - String8 augmentation = based_range_read_string(base, range, augmentation_off); + String8 augmentation = dw_based_range_read_string(base, range, augmentation_off); // read code align U64 code_align_factor_off = augmentation_off + augmentation.size + 1; U64 code_align_factor = 0; - U64 code_align_factor_size = based_range_read_uleb128(base, range, code_align_factor_off, &code_align_factor); + U64 code_align_factor_size = dw_based_range_read_uleb128(base, range, code_align_factor_off, &code_align_factor); // read data align U64 data_align_factor_off = code_align_factor_off + code_align_factor_size; S64 data_align_factor = 0; - U64 data_align_factor_size = based_range_read_sleb128(base, range, data_align_factor_off, &data_align_factor); + U64 data_align_factor_size = dw_based_range_read_sleb128(base, range, data_align_factor_off, &data_align_factor); // return address register U64 ret_addr_reg_off = data_align_factor_off + data_align_factor_size; U64 after_ret_addr_reg_off = 0; U64 ret_addr_reg = 0; if (version == 1) { - based_range_read(base, range, ret_addr_reg_off, 1, &ret_addr_reg); + dw_based_range_read(base, range, ret_addr_reg_off, 1, &ret_addr_reg); after_ret_addr_reg_off = ret_addr_reg_off + 1; } else { - U64 ret_addr_reg_size = based_range_read_uleb128(base, range, ret_addr_reg_off, &ret_addr_reg); + U64 ret_addr_reg_size = dw_based_range_read_uleb128(base, range, ret_addr_reg_off, &ret_addr_reg); after_ret_addr_reg_off = ret_addr_reg_off + ret_addr_reg_size; } @@ -459,7 +459,7 @@ dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off U64 augmentation_size = 0; if (augmentation.size > 0 && augmentation.str[0] == 'z') { has_augmentation_size = 1; - U64 aug_size_size = based_range_read_uleb128(base, range, aug_size_off, &augmentation_size); + U64 aug_size_size = dw_based_range_read_uleb128(base, range, aug_size_off, &augmentation_size); after_aug_size_off += aug_size_size; } @@ -476,19 +476,19 @@ dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off for (U8 *ptr = augmentation.str + 1, *opl = augmentation.str + augmentation.size; ptr < opl; ++ptr) { switch (*ptr) { case 'L': { - based_range_read_struct(base, range, aug_data_cursor, &lsda_encoding); + dw_based_range_read_struct(base, range, aug_data_cursor, &lsda_encoding); aug_data_cursor += sizeof(lsda_encoding); } break; case 'P': { DW_EhPtrEnc handler_encoding = DW_EhPtrEnc_Omit; - based_range_read_struct(base, range, aug_data_cursor, &handler_encoding); + dw_based_range_read_struct(base, range, aug_data_cursor, &handler_encoding); U64 ptr_off = aug_data_cursor + sizeof(handler_encoding); U64 ptr_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, handler_encoding, ptr_off, &handler_ip); aug_data_cursor = ptr_off + ptr_size; } break; case 'R': { - based_range_read_struct(base, range, aug_data_cursor, &addr_encoding); + dw_based_range_read_struct(base, range, aug_data_cursor, &addr_encoding); aug_data_cursor += sizeof(addr_encoding); } break; default: { @@ -547,7 +547,7 @@ dw_unwind_parse_fde_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, DW_CIEU if (cie->has_augmentation_size) { // augmentation size U64 augmentation_size = 0; - U64 aug_size_size = based_range_read_uleb128(base, range, aug_data_off, &augmentation_size); + U64 aug_size_size = dw_based_range_read_uleb128(base, range, aug_data_off, &augmentation_size); U64 after_aug_size_off = aug_data_off + aug_size_size; // extract lsda (only thing that can actually be in FDE's augmentation data as far as we know) @@ -863,7 +863,7 @@ dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machin DW_CFAControlBits control_bits = 0; // decode opcode/operand0 - if (!based_range_read(base, range, cfi_off, 1, &opcode)) { + if (!dw_based_range_read(base, range, cfi_off, 1, &opcode)) { result = 1; goto done; } @@ -897,7 +897,7 @@ dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machin } break; default: { if (d <= 8) { - based_range_read(base, range, decode_cursor, d, out); + dw_based_range_read(base, range, decode_cursor, d, out); o_size = d; } } break; @@ -905,10 +905,10 @@ dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machin o_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, cie->addr_encoding, decode_cursor, out); } break; case DW_CFADecode_ULEB128: { - o_size = based_range_read_uleb128(base, range, decode_cursor, out); + o_size = dw_based_range_read_uleb128(base, range, decode_cursor, out); } break; case DW_CFADecode_SLEB128: { - o_size = based_range_read_sleb128(base, range, decode_cursor, (S64*)out); + o_size = dw_based_range_read_sleb128(base, range, decode_cursor, (S64*)out); } break; } decode_cursor += o_size; diff --git a/src/linker/codeview_ext/codeview.c b/src/linker/codeview_ext/codeview.c index e1f1f90a..fa555c62 100644 --- a/src/linker/codeview_ext/codeview.c +++ b/src/linker/codeview_ext/codeview.c @@ -1677,7 +1677,7 @@ cv_c13_line_array_from_data(Arena *arena, String8 c13_data, U64 sec_base, CV_C13 { CV_C13Line line = raw_lines[line_idx]; result.voffs[line_idx] = sec_base + parsed_lines.sec_off_lo + line.off; - result.line_nums[line_idx] = CV_C13LineFlags_ExtractLineNumber(line.flags); + result.line_nums[line_idx] = CV_C13LineFlags_Extract_LineNumber(line.flags); } // emit voff ender diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 0e2e5c82..03e4e2bc 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -3699,9 +3699,9 @@ THREAD_POOL_TASK_FUNC(lnk_convert_types_to_rdi_task) } break; case CV_LeafKind_POINTER: { CV_LeafPointer *ptr = (CV_LeafPointer *) src.data.str; - CV_PointerKind ptr_kind = CV_PointerAttribs_ExtractKind(ptr->attribs); - CV_PointerMode ptr_mode = CV_PointerAttribs_ExtractMode(ptr->attribs); - U32 ptr_size = CV_PointerAttribs_ExtractSize(ptr->attribs); + CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(ptr->attribs); + CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(ptr->attribs); + U32 ptr_size = CV_PointerAttribs_Extract_Size(ptr->attribs); (void)ptr_kind; // parse ahead type chain and squash modifiers @@ -4010,7 +4010,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_types_to_rdi_task) for (U64 cursor = 0; cursor + sizeof(CV_LeafMethodListMember) <= method_list_leaf.data.size; ) { // parse CodeView method overload info CV_LeafMethodListMember *list_member = (CV_LeafMethodListMember *) (method_list_leaf.data.str + cursor); - CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(list_member->attribs); + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(list_member->attribs); cursor += sizeof(CV_LeafMethodListMember); U32 vftable_offset = 0; if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) { @@ -4037,7 +4037,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_types_to_rdi_task) case CV_LeafKind_ONEMETHOD: { // parse CodeView method CV_LeafOneMethod *one_method = (CV_LeafOneMethod *) (src.data.str + cursor); - CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(one_method->attribs); + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(one_method->attribs); cursor += sizeof(CV_LeafOneMethod); U32 vftable_offset = 0; if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) { @@ -4493,21 +4493,21 @@ THREAD_POOL_TASK_FUNC(lnk_find_obj_compiler_info_task) AssertAlways(sizeof(CV_SymCompile) <= symbol.data.size); CV_SymCompile *compile = (CV_SymCompile *)symbol.data.str; comp_info->arch = compile->machine; - comp_info->language = CV_CompileFlags_ExtractLanguage(compile->flags); + comp_info->language = CV_CompileFlags_Extract_Language(compile->flags); comp_info->compiler_name = str8_cstring_capped(compile + 1, symbol.data.str + symbol.data.size); goto exit; } else if (symbol.kind == CV_SymKind_COMPILE2) { AssertAlways(sizeof(CV_SymCompile2) <= symbol.data.size); CV_SymCompile2 *compile2 = (CV_SymCompile2 *)symbol.data.str; comp_info->arch = compile2->machine; - comp_info->language = CV_Compile2Flags_ExtractLanguage(compile2->flags); + comp_info->language = CV_Compile2Flags_Extract_Language(compile2->flags); comp_info->compiler_name = str8_cstring_capped(compile2 + 1, symbol.data.str + symbol.data.size); goto exit; } else if (symbol.kind == CV_SymKind_COMPILE3) { AssertAlways(sizeof(CV_SymCompile3) <= symbol.data.size); CV_SymCompile3 *compile3 = (CV_SymCompile3 *)symbol.data.str; comp_info->arch = compile3->machine; - comp_info->language = CV_Compile3Flags_ExtractLanguage(compile3->flags); + comp_info->language = CV_Compile3Flags_Extract_Language(compile3->flags); comp_info->compiler_name = str8_cstring_capped(compile3 + 1, symbol.data.str + symbol.data.size); goto exit; } @@ -5104,7 +5104,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_symbols_to_rdi_task) CV_LvarAddrGap *gaps = (CV_LvarAddrGap *) (defrange_subfield_register + 1); U64 gap_count = (symbol.data.size - sizeof(*defrange_subfield_register)) / sizeof(gaps[0]); RDI_RegCode reg_rdi = rdi_reg_code_from_cv(comp_info.arch, defrange_subfield_register->reg); - U32 value_pos = CV_DefrangeSubfieldRegister_ExtractParentOffset(defrange_subfield_register->field_offset); + U32 value_pos = CV_DefrangeSubfieldRegister_Extract_ParentOffset(defrange_subfield_register->field_offset); U32 value_size = cv_size_from_reg(comp_info.arch, defrange_subfield_register->reg) - value_pos; Rng1U64 defrange = lnk_virt_range_from_sect_off_size(defrange_subfield_register->range.sec, defrange_subfield_register->range.off, defrange_subfield_register->range.len, task->image_sects, obj, symbol.kind, symbol.offset); Rng1U64List ranges = cv_make_defined_range_list_from_gaps(arena, defrange, gaps, gap_count); diff --git a/src/msvc_crt/msvc_crt.c b/src/msvc_crt/msvc_crt.c index 4927b3c4..a735341d 100644 --- a/src/msvc_crt/msvc_crt.c +++ b/src/msvc_crt/msvc_crt.c @@ -86,6 +86,50 @@ mscrt_parse_func_info(Arena *arena, //////////////////////////////// +internal U64 +mscrt_v4_parse_u32(String8 raw_data, U64 offset, U32 *uint_out) +{ + U64 cursor = offset; + + U8 one = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &one); + + if ((one & 0xF) == 15) { + U8 two = 0, three = 0, four = 0, five = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &two); + cursor += str8_deserial_read_struct(raw_data, cursor, &three); + cursor += str8_deserial_read_struct(raw_data, cursor, &four); + cursor += str8_deserial_read_struct(raw_data, cursor, &five); + *uint_out = (U32)two | ((U32)three << 8) | ((U32)four << 16) | ((U32)five << 24); + } else if ((one & 0xF) == 7) { + U8 two = 0, three = 0, four = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &two); + cursor += str8_deserial_read_struct(raw_data, cursor, &three); + cursor += str8_deserial_read_struct(raw_data, cursor, &four); + *uint_out = ((U32)one >> 4) | ((U32)two << 4) | ((U32)three << 12) | ((U32)four << 20); + } else if ((one & 0x7) == 3) { + U8 two = 0, three = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &two); + cursor += str8_deserial_read_struct(raw_data, cursor, &three); + *uint_out = ((U32)one >> 3) | ((U32)two << 5) | ((U32)three << 13); + } else if ((one & 0x3) == 1) { + U8 two = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &two); + *uint_out = ((U32)one >> 2) | ((U32)two << 6); + } else { + *uint_out = one >> 1; + } + + U64 read_size = cursor - offset; + return read_size; +} + +internal U64 +mscrt_v4_parse_s32(String8 raw_data, U64 offset, S32 *int_out) +{ + return str8_deserial_read_struct(raw_data, offset, int_out); +} + internal U64 mscrt_parse_handler_type_v4(String8 raw_data, U64 offset, U64 func_voff, MSCRT_EhHandlerTypeV4 *handler) { @@ -93,15 +137,15 @@ mscrt_parse_handler_type_v4(String8 raw_data, U64 offset, U64 func_voff, MSCRT_E cursor += str8_deserial_read_struct(raw_data, cursor, &handler->flags); if (handler->flags & MSCRT_EhHandlerV4Flag_Adjectives) { - cursor += str8_deserial_read_struct(raw_data, cursor, &handler->adjectives); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &handler->adjectives); } if (handler->flags & MSCRT_EhHandlerV4Flag_DispType) { - cursor += str8_deserial_read_struct(raw_data, cursor, &handler->type_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &handler->type_voff); } if (handler->flags & MSCRT_EhHandlerV4Flag_DispCatchObj) { - cursor += str8_deserial_read_struct(raw_data, cursor, &handler->catch_obj_voff); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &handler->catch_obj_voff); } - cursor += str8_deserial_read_struct(raw_data, cursor, &handler->catch_code_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &handler->catch_code_voff); U32 cont_type = (handler->flags & MSCRT_EhHandlerV4Flag_ContVOffMask) >> MSCRT_EhHandlerV4Flag_ContVOffShift; if (handler->flags & MSCRT_EhHandlerV4Flag_ContIsVOff) { @@ -109,14 +153,14 @@ mscrt_parse_handler_type_v4(String8 raw_data, U64 offset, U64 func_voff, MSCRT_E case MSCRT_ContV4Type_NoMetadata: break; case MSCRT_ContV4Type_OneFuncRelAddr: { S32 v = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &v); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &v); handler->catch_funclet_cont_addr[0] = (U64)v; handler->catch_funclet_cont_addr_count = 1; } break; case MSCRT_ContV4Type_TwoFuncRelAddr: { S32 v1 = 0, v2 = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &v1); - cursor += str8_deserial_read_struct(raw_data, cursor, &v2); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &v1); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &v2); handler->catch_funclet_cont_addr[0] = (U64)v1; handler->catch_funclet_cont_addr[1] = (U64)v2; handler->catch_funclet_cont_addr_count = 2; @@ -128,14 +172,14 @@ mscrt_parse_handler_type_v4(String8 raw_data, U64 offset, U64 func_voff, MSCRT_E } break; case MSCRT_ContV4Type_OneFuncRelAddr: { U32 v = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &v); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &v); handler->catch_funclet_cont_addr[0] = func_voff + (U64)v; handler->catch_funclet_cont_addr_count = 1; } break; case MSCRT_ContV4Type_TwoFuncRelAddr: { U32 v1 = 0, v2 = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &v1); - cursor += str8_deserial_read_struct(raw_data, cursor, &v2); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &v1); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &v2); handler->catch_funclet_cont_addr[0] = func_voff + (U64)v1; handler->catch_funclet_cont_addr[1] = func_voff + (U64)v2; handler->catch_funclet_cont_addr_count = 2; @@ -156,7 +200,7 @@ mscrt_parse_handler_type_v4_array(Arena *arena, { U64 cursor = offset; U32 count = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &count); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &count); MSCRT_EhHandlerTypeV4 *handlers = 0; if (count) { @@ -179,7 +223,7 @@ mscrt_parse_unwind_v4_entry(String8 raw_data, U64 offset, MSCRT_UnwindEntryV4 *e U64 cursor = offset; U32 type_and_next_off = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &type_and_next_off); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &type_and_next_off); entry_out->type = type_and_next_off & 0x3; entry_out->next_off = type_and_next_off >> 2; @@ -187,11 +231,11 @@ mscrt_parse_unwind_v4_entry(String8 raw_data, U64 offset, MSCRT_UnwindEntryV4 *e switch (entry_out->type) { case MSCRT_UnwindMapV4Type_DtorWithObj: case MSCRT_UnwindMapV4Type_DtorWithPtrToObj: { - cursor += str8_deserial_read_struct(raw_data, cursor, &entry_out->action); - cursor += str8_deserial_read_struct(raw_data, cursor, &entry_out->object); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &entry_out->action); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &entry_out->object); } break; case MSCRT_UnwindMapV4Type_VOFF: { - cursor += str8_deserial_read_struct(raw_data, cursor, &entry_out->action); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &entry_out->action); } break; case MSCRT_UnwindMapV4Type_NoUW: { // no action and/or object is associated with this type @@ -209,7 +253,7 @@ internal U64 mscrt_parse_unwind_map_v4(Arena *arena, String8 raw_data, U64 off, MSCRT_UnwindMapV4 *map_out) { U64 cursor = off; - cursor += str8_deserial_read_struct(raw_data, cursor, &map_out->count); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &map_out->count); map_out->v = push_array(arena, MSCRT_UnwindEntryV4, map_out->count); for (U32 i = 0; i < map_out->count; ++i) { cursor += mscrt_parse_unwind_v4_entry(raw_data, cursor, &map_out->v[i]); @@ -230,17 +274,17 @@ mscrt_parse_try_block_map_array_v4(Arena *arena, U64 cursor = off; U32 try_block_map_count = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &try_block_map_count); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &try_block_map_count); MSCRT_TryBlockMapV4 *try_block_map = push_array(arena, MSCRT_TryBlockMapV4, try_block_map_count); for (U32 itry = 0; itry < try_block_map_count; ++itry) { MSCRT_TryBlockMapV4 *try_block = &try_block_map[itry]; - cursor += str8_deserial_read_struct(raw_data, cursor, &try_block->try_low); - cursor += str8_deserial_read_struct(raw_data, cursor, &try_block->try_high); - cursor += str8_deserial_read_struct(raw_data, cursor, &try_block->catch_high); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &try_block->try_low); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &try_block->try_high); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &try_block->catch_high); S32 handler_array_voff = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &handler_array_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &handler_array_voff); U64 handler_array_foff = coff_foff_from_voff(sections, section_count, (U32)handler_array_voff); mscrt_parse_handler_type_v4_array(arena, raw_data, handler_array_foff, func_voff, &try_block->handlers); @@ -263,7 +307,7 @@ mscrt_parse_ip2state_map_v4(Arena *arena, U64 cursor = off; U32 count = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &count); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &count); U32 *voffs = push_array(arena, U32, count); S32 *states = push_array(arena, S32, count); @@ -271,13 +315,13 @@ mscrt_parse_ip2state_map_v4(Arena *arena, U32 prev_voff = func_voff; for (U32 i = 0; i < count; ++i) { // virtual offsets are encoded as deltas - cursor += str8_deserial_read_struct(raw_data, cursor, &voffs[i]); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &voffs[i]); voffs[i] += prev_voff; prev_voff = voffs[i]; // states are encoded with +1 to avoid encoding negative integers U32 encoded_state = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &encoded_state); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &encoded_state); states[i] = (S32)encoded_state - 1; } @@ -303,22 +347,22 @@ mscrt_parse_func_info_v4(Arena *arena, MSCRT_FuncInfo32V4 func_info = {0}; cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.header); if (func_info.header & MSCRT_FuncInfoV4Flag_IsBBT) { - cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.bbt_flags); + cursor += mscrt_v4_parse_u32(raw_data, cursor, &func_info.bbt_flags); } if (func_info.header & MSCRT_FuncInfoV4Flag_UnwindMap) { - cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.unwind_map_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &func_info.unwind_map_voff); } if (func_info.header & MSCRT_FuncInfoV4Flag_TryBlockMap) { - cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.try_block_map_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &func_info.try_block_map_voff); } if (func_info.header & MSCRT_FuncInfoV4Flag_IsSeparated) { // TODO: separted IP state map NotImplemented; } else { - cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.ip_to_state_map_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &func_info.ip_to_state_map_voff); } if (func_info.header & MSCRT_FuncInfoV4Flag_IsCatch) { - cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.wrt_frame_establisher_voff); + cursor += mscrt_v4_parse_s32(raw_data, cursor, &func_info.wrt_frame_establisher_voff); } MSCRT_UnwindMapV4 unwind_map = {0}; @@ -387,8 +431,8 @@ mscrt_catch_blocks_from_data_x8664(Arena *arena, String8 handler_name = str8_zero(); /* TODO: { - SYMS_UnitID uid = syms_group_uid_from_voff__accelerated(group, handler_voff); - SYMS_UnitAccel *unit = syms_group_unit_from_uid(group, uid); + UnitID uid = syms_group_uid_from_voff__accelerated(group, handler_voff); + UnitAccel *unit = syms_group_unit_from_uid(group, uid); SYMS_SymbolID sid = syms_group_proc_sid_from_uid_voff__accelerated(group, uid, handler_voff); handler_name = syms_group_symbol_name_from_sid(temp.arena, group, unit, sid); } diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index 2554f8f8..35d3e47d 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -1,6 +1,292 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +// TODO: +// +// Code View: +// [x] Test .debug$S +// [x] Test .debug$T +// +// Test dumper on following sections: +// [x] .debug_abbrev +// [ ] .debug_aranges +// [ ] .debug_frame +// [x] .debug_info +// [x] .debug_line +// [ ] .debug_loc +// [ ] .debug_macinfo +// [ ] .debug_pubnames +// [ ] .debug_pubtypes +// [x] .debug_str +// [x] .debug_ranges +// [ ] .debug_addr +// [ ] .debug_loclists +// [ ] .debug_rnglists +// [ ] .debug_stroffsets +// [ ] .debug_linestr +// [ ] .debug_names +// +// [ ] port ELF dumper from internal repo +// [ ] port COFF/PE resource dumper from internal repo +// [x] hook up RDI symbolizer + +internal void +rd_stderr(char *fmt, ...) +{ + Temp scratch = scratch_begin(0,0); + va_list args; + va_start(args, fmt); + String8 f = push_str8fv(scratch.arena, fmt, args); + fprintf(stderr, "%.*s\n", str8_varg(f)); + va_end(args); + scratch_end(scratch); +} + +internal B32 +rd_invoke_rdi_converter(String8 exe_name, String8 exe_data, String8 pdb_path, String8 out_path) +{ + Temp scratch = scratch_begin(0,0); + + P2R_User2Convert user2convert = {0}; + user2convert.input_pdb_name = pdb_path; + user2convert.input_pdb_data = os_data_from_file_path(scratch.arena, pdb_path); + user2convert.input_exe_name = exe_name; + user2convert.input_exe_data = exe_data; + user2convert.output_name = out_path; + user2convert.flags = P2R_ConvertFlag_All; + + P2R_Convert2Bake *convert2bake = p2r_convert(scratch.arena, &user2convert); + P2R_Bake2Serialize *bake2srlz = p2r_bake(scratch.arena, convert2bake); + RDIM_SerializedSectionBundle bundle = rdim_serialized_section_bundle_from_bake_results(&bake2srlz->bake_results); + String8List rdi_blobs = rdim_file_blobs_from_section_bundle(scratch.arena, &bundle); + B32 is_rdi_write_ok = os_write_data_list_to_file_path(user2convert.output_name, rdi_blobs); + + scratch_end(scratch); + return is_rdi_write_ok; +} + +internal RDI_Parsed * +rd_rdi_from_pe(Arena *arena, String8 data_path, String8 raw_data) +{ + Temp scratch = scratch_begin(&arena, 1); + + RDI_Parsed *rdi = 0; + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, raw_data); + + // PDB 2.0 + COFF_TimeStamp pdb20_time_stamp = 0; + U32 pdb20_age = 0; + String8 pdb20_path = str8_zero(); + // PDB 7.0 + U32 pdb70_age = 0; + Guid pdb70_guid = {0}; + String8 pdb70_path = str8_zero(); + // RDI + String8 rdi_path = str8_zero(); + Guid rdi_guid = {0}; + if (PE_DataDirectoryIndex_DEBUG < pe.data_dir_count) { + String8 raw_debug_dir = str8_substr(raw_data, pe.data_dir_franges[PE_DataDirectoryIndex_DEBUG]); + PE_DebugDirectory *debug_entry = str8_deserial_get_raw_ptr(raw_debug_dir, 0, sizeof(*debug_entry)); + PE_DebugDirectory *debug_entry_opl = debug_entry + raw_debug_dir.size/sizeof(*debug_entry_opl); + for (PE_DebugDirectory *debug_entry_ptr = debug_entry; debug_entry_ptr < debug_entry_opl; ++debug_entry_ptr) { + if (debug_entry_ptr->type == PE_DebugDirectoryType_CODEVIEW) { + U32 cv_magic = 0; + str8_deserial_read_struct(raw_data, debug_entry_ptr->foff, &cv_magic); + + switch (cv_magic) { + case PE_CODEVIEW_PDB20_MAGIC: { + PE_CvHeaderPDB20 cv = {0}; + U64 cv_read_size = str8_deserial_read_struct(raw_data, debug_entry_ptr->foff, &cv); + if (cv_read_size == sizeof(cv)) { + pdb20_time_stamp = cv.time_stamp; + pdb20_age = cv.age; + str8_deserial_read_cstr(raw_data, debug_entry_ptr->foff+sizeof(cv), &pdb20_path); + } else { + rd_errorf("unable to read PE_CvHeaderPDB20"); + } + } break; + case PE_CODEVIEW_PDB70_MAGIC: { + PE_CvHeaderPDB70 cv = {0}; + U64 cv_read_size = str8_deserial_read_struct(raw_data, debug_entry_ptr->foff, &cv); + if (cv_read_size == sizeof(cv)) { + pdb70_age = cv.age; + pdb70_guid = cv.guid; + str8_deserial_read_cstr(raw_data, debug_entry_ptr->foff+sizeof(cv), &pdb70_path); + } else { + rd_errorf("unable to read PE_CvHeaderPDB70"); + } + } break; + case PE_CODEVIEW_RDI_MAGIC: { + PE_CvHeaderRDI cv = {0}; + U64 cv_read_size = str8_deserial_read_struct(raw_data, debug_entry_ptr->foff, &cv); + if (cv_read_size == sizeof(cv)) { + rdi_guid = cv.guid; + str8_deserial_read_cstr(raw_data, debug_entry_ptr->foff+sizeof(cv), &rdi_path); + } else { + rd_errorf("unable to read PE_CvHeaderRDI"); + } + } break; + default: break; + } + } + } + } + + // convert debug info to RDI + if (!rdi_path.size && (pdb20_path.size || pdb70_path.size)) { + if (pdb20_path.size && pdb70_path.size) { + rd_warningf("multiple PDB paths defined %S, %S (picking first)", pdb70_path, pdb20_path); + } + String8 pdb_path = pdb70_path.size ? pdb70_path : pdb20_path; + String8 out_path = push_str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(pdb_path)); + B32 is_rdi_ok = rd_invoke_rdi_converter(data_path, raw_data, pdb_path, out_path); + if (is_rdi_ok) { + rdi_path = out_path; + } else { + rd_errorf("unable write RDI to %S", out_path); + } + } + + if (rdi_path.size) { + String8 raw_rdi = os_data_from_file_path(arena, rdi_path); + if (raw_rdi.size > 0) { + rdi = push_array(arena, RDI_Parsed, 1); + + // TODO: check guid + RDI_ParseStatus parse_status = rdi_parse(raw_rdi.str, raw_rdi.size, rdi); + + String8 parse_status_string = str8_zero(); + if (parse_status == RDI_ParseStatus_Good) { + } else if (parse_status == RDI_ParseStatus_HeaderDoesNotMatch) { + parse_status_string = str8_lit("Header does not match"); + } else if (parse_status == RDI_ParseStatus_UnsupportedVersionNumber) { + parse_status_string = str8_lit("Unsupported version number"); + } else if (parse_status == RDI_ParseStatus_InvalidDataSecionLayout) { + parse_status_string = str8_lit("Invalid data section layout"); + } else if (parse_status == RDI_ParseStatus_MissingRequiredSection) { + parse_status_string = str8_lit("Missing required section"); + } else { + parse_status_string = push_str8f(scratch.arena, "unknown parse status code: %u", parse_status); + } + + if (parse_status_string.size) { + rdi = 0; + rd_errorf("RDI parse status(%u): %S", parse_status, parse_status_string); + } + } else { + rd_errorf("unable to open RDI: %S", rdi_path); + } + } + + scratch_end(scratch); + return rdi; +} + +internal String8 +rd_proc_name_from_voff(RDI_Parsed *rdi, U64 voff) +{ + RDI_Scope *scope = rdi_scope_from_voff(rdi, voff); + RDI_Procedure *proc = rdi_procedure_from_scope(rdi, scope); + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, proc->name_string_idx, &name.size); + return name; +} + +internal String8 +rd_format_proc_line(Arena *arena, RDI_Parsed *rdi, U64 voff) +{ + RDI_Scope *scope = rdi_scope_from_voff(rdi, voff); + RDI_Procedure *proc = rdi_procedure_from_scope(rdi, scope); + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, proc->name_string_idx, &name.size); + U64 rel = voff - scope->voff_range_first; + String8 result = str8_zero(); + if (name.size) { + if (rel) { + result = push_str8f(arena, "%S+%llx", name, rel); + } else { + result = push_str8f(arena, "%S", name); + } + } + return result; +} + +internal String8 +rd_path_from_file_path_node_idx(Arena *arena, RDI_Parsed *rdi, U32 file_path_node_idx, PathStyle style) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List parts = {0}; + for(RDI_FilePathNode *fpn = rdi_element_from_name_idx(rdi, FilePathNodes, file_path_node_idx); + fpn != rdi_element_from_name_idx(rdi, FilePathNodes, 0); + fpn = rdi_element_from_name_idx(rdi, FilePathNodes, fpn->parent_path_node)) { + String8 p; + p.str = rdi_string_from_idx(rdi, fpn->name_string_idx, &p.size); + str8_list_push_front(scratch.arena, &parts, p); + } + String8 path = str8_path_list_join_by_style(arena, &parts, style); + scratch_end(scratch); + return path; +} + +internal RD_Line +rd_line_from_voff(Arena *arena, RDI_Parsed *rdi, U64 voff, PathStyle path_style) +{ + RDI_Line line = rdi_line_from_voff(rdi, voff); + RDI_SourceFile *src_file = rdi_source_file_from_line(rdi, &line); + String8 file_path = rd_path_from_file_path_node_idx(arena, rdi, src_file->file_path_node_idx, path_style); + + RD_Line result = {0}; + result.file_path = file_path; + result.line_num = line.line_num; + + return result; +} + +internal String8 +rd_format_line_from_voff(Arena *arena, RDI_Parsed *rdi, U64 voff, PathStyle path_style) +{ + Temp scratch = scratch_begin(&arena, 1); + RD_Line line = rd_line_from_voff(scratch.arena, rdi, voff, path_style); + String8 result = push_str8f(arena, "%S:%u", line.file_path, line.line_num); + scratch_end(scratch); + return result; +} + +internal B32 +rd_is_pe(String8 raw_data) +{ + PE_DosHeader header = {0}; + str8_deserial_read_struct(raw_data, 0, &header); + return header.magic == PE_DOS_MAGIC; +} + +internal void +rd_format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data) +{ + Temp scratch = scratch_begin(&arena, 1); + + char *input_type_string = "???"; + if (coff_is_archive(raw_data)) { + input_type_string = "Archive"; + } else if (coff_is_thin_archive(raw_data)) { + input_type_string = "Thin Archive"; + } else if (coff_is_big_obj(raw_data)) { + input_type_string = "Big Obj"; + } else if (coff_is_obj(raw_data)) { + input_type_string = "Obj"; + } else if (rd_is_pe(raw_data)) { + input_type_string = "COFF/PE"; + } + + DateTime universal_dt = os_now_universal_time(); + DateTime local_dt = os_local_time_from_universal(&universal_dt); + String8 time = push_date_time_string(scratch.arena, &local_dt); + String8 full_path = os_full_path_from_path(scratch.arena, input_path); + rd_printf("# %S, [%s] %S", time, input_type_string, full_path); + + scratch_end(scratch); +} + internal int rd_marker_is_before(void *a, void *b) { @@ -56,8 +342,46 @@ rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 st return result; } -//////////////////////////////// -//~ Disasm +internal DW_SectionArray +rd_dw_sections_from_coff_section_table(Arena *arena, + String8 raw_image, + U64 string_table_off, + U64 section_count, + COFF_SectionHeader *sections) +{ + DW_SectionArray result = {0}; + B32 sect_status[ArrayCount(result.v)] = {0}; + + for (U64 i = 0; i < section_count; ++i) { + COFF_SectionHeader *header = §ions[i]; + Rng1U64 raw_data_range = rng_1u64(header->foff, header->foff + header->fsize); + String8 name = coff_name_from_section_header(header, raw_image, string_table_off); + + DW_SectionKind s = DW_Section_Null; + B32 is_dwo = 0; + #define X(_K,_L,_M,_W) \ + if (str8_match(name, str8_lit(_L), 0)) { s = DW_Section_##_K; } \ + if (str8_match(name, str8_lit(_M), 0)) { s = DW_Section_##_K; } \ + if (str8_match(name, str8_lit(_W), 0)) { s = DW_Section_##_K; is_dwo = 1; } + DW_SectionKind_XList(X) + #undef X + + if (s != DW_Section_Null) { + if (sect_status[s]) { + rd_warningf("file contains multiple %S sections, picking first", name); + } else { + sect_status[s] = 1; + DW_Section *d = &result.v[s]; + d->name = push_str8_copy(arena, name); + d->data = str8_substr(raw_image, raw_data_range); + d->mode = dim_1u64(raw_data_range) > max_U32 ? DW_Mode_64Bit : DW_Mode_32Bit; + d->is_dwo = is_dwo; + } + } + } + + return result; +} internal RD_DisasmResult rd_disasm_next_instruction(Arena *arena, Arch arch, U64 addr, String8 raw_code) @@ -85,7 +409,7 @@ rd_disasm_next_instruction(Arena *arena, Arch arch, U64 addr, String8 raw_code) } internal void -rd_format_disasm(Arena *arena, +rd_print_disasm(Arena *arena, String8List *out, String8 indent, Arch arch, @@ -97,8 +421,8 @@ rd_format_disasm(Arena *arena, { Temp scratch = scratch_begin(&arena, 1); - U64 bytes_buffer_max = 256; - U8 *bytes_buffer = push_array(scratch.arena, U8, bytes_buffer_max); + U64 bytes_buffer_max = 256; + char *bytes_buffer = push_array(scratch.arena, char, bytes_buffer_max); U64 decode_off = 0; U64 marker_cursor = 0; @@ -118,7 +442,7 @@ rd_format_disasm(Arena *arena, for (U64 i = 0; i < disasm_result.size; ++i) { bytes_size += raddbg_snprintf(bytes_buffer + bytes_size, bytes_buffer_max-bytes_size, "%s%02x", i > 0 ? " " : "", to_decode.str[i]); } - bytes = str8(bytes_buffer, bytes_size); + bytes = str8((U8*)bytes_buffer, bytes_size); } // print address marker @@ -149,28 +473,27 @@ rd_format_disasm(Arena *arena, scratch_end(scratch); } -//////////////////////////////// -//~ Raw Data - internal String8 rd_format_hex_array(Arena *arena, U8 *ptr, U64 size) { - U64 buf_max = size * 3; - U8 *buf = push_array(arena, U8, buf_max); - U64 buf_size = 0; + U64 buf_max = size * 8; + char *buf = push_array(arena, char, buf_max); + U64 buf_size = 0; + buf_size += raddbg_snprintf(buf+buf_size, buf_max-buf_size, "{ "); for (U64 i = 0; i < size; ++i) { - buf_size += raddbg_snprintf(buf+buf_size, buf_max-buf_size, "%s%02x", i>0 ? " " : "", ptr[i]); + buf_size += raddbg_snprintf(buf+buf_size, buf_max-buf_size, "%s0x%02x", i>0 ? ", " : "", ptr[i]); } + buf_size += raddbg_snprintf(buf+buf_size, buf_max-buf_size, " }"); buf[buf_size] = '\0'; - String8 result = str8(buf, buf_size); + String8 result = str8((U8*)buf, buf_size); return result; } internal void -rd_format_raw_data(Arena *arena, +rd_print_raw_data(Arena *arena, String8List *out, String8 indent, U64 bytes_per_row, @@ -180,7 +503,7 @@ rd_format_raw_data(Arena *arena, { AssertAlways(bytes_per_row > 0); - U8 temp_buffer[1024]; + char temp_buffer[1024]; String8 to_format = raw_data; for (; to_format.size > 0; ) { @@ -190,7 +513,7 @@ rd_format_raw_data(Arena *arena, // offset U64 offset = (U64)(raw_row.str-raw_data.str); - temp_cursor += raddbg_snprintf(temp_buffer+temp_cursor, sizeof(temp_buffer)-temp_cursor, "%#08x: ", offset); + temp_cursor += raddbg_snprintf(temp_buffer+temp_cursor, sizeof(temp_buffer)-temp_cursor, "%#08llx: ", offset); // hex for (U64 i = 0; i < raw_row.size; ++i) { @@ -220,10 +543,2053 @@ rd_format_raw_data(Arena *arena, } } -//- CodeView +internal String8List +dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List result = {0}; + for (U64 cursor = 0; cursor < raw_data.size; ) { + U8 op = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &op); + + String8 op_value = str8_zero(); + U64 size_param = 0; + B32 is_signed = 0; + switch (op) { + case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: + case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: + case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8: + case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11: + case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: + case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: + case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20: + case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23: + case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: + case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: + case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: { + U64 x = op - DW_ExprOp_Lit0; + op_value = push_str8f(scratch.arena, "%llu", x); + } break; + + case DW_ExprOp_Const1U:size_param = 1; goto const_n; + case DW_ExprOp_Const2U:size_param = 2; goto const_n; + case DW_ExprOp_Const4U:size_param = 4; goto const_n; + case DW_ExprOp_Const8U:size_param = 8; goto const_n; + case DW_ExprOp_Const1S:size_param = 1; is_signed = 1; goto const_n; + case DW_ExprOp_Const2S:size_param = 2; is_signed = 1; goto const_n; + case DW_ExprOp_Const4S:size_param = 4; is_signed = 1; goto const_n; + case DW_ExprOp_Const8S:size_param = 8; is_signed = 1; goto const_n; + const_n: + { + U64 x = 0; + cursor += str8_deserial_read(raw_data, cursor, &x, size_param, 1); + if (is_signed){ + U64 bit_shift = (size_param << 3) - 1; + if ((x >> bit_shift) != 0){ + x |= ~((1 << bit_shift) - 1); + } + } + op_value = push_str8f(scratch.arena, "%llu", x); + } break; + + case DW_ExprOp_Addr: { + U64 addr = 0; + cursor += str8_deserial_read(raw_data, cursor, &addr, address_size, 1); + op_value = push_str8f(scratch.arena, "%#llx", addr); + } break; + + case DW_ExprOp_ConstU: { + U64 x = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &x); + op_value = push_str8f(scratch.arena, "%llu", x); + } break; + + case DW_ExprOp_ConstS: { + S64 x = 0; + cursor += str8_deserial_read_sleb128(raw_data, cursor, &x); + op_value = push_str8f(scratch.arena, "%lld", x); + } break; + + case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: + case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: + case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8: + case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11: + case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: + case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: + case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20: + case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23: + case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: + case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: + case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: { + U64 reg_idx = op - DW_ExprOp_Reg0; + op_value = push_str8f(scratch.arena, "%S", dw_string_from_register(scratch.arena, arch, reg_idx)); + } break; + + case DW_ExprOp_RegX: { + U64 reg_idx = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); + op_value = push_str8f(scratch.arena, "register %llu (%S)", reg_idx, dw_string_from_register(scratch.arena, arch, reg_idx)); + } break; + + case DW_ExprOp_ImplicitValue: { + U64 size = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &size); + op_value = push_str8f(scratch.arena, "block @ %#llx with size %u", cursor, size); + } break; + + case DW_ExprOp_Piece: { + U64 size = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &size); + op_value = push_str8f(scratch.arena, "%u", size); + } break; + + case DW_ExprOp_BitPiece: { + U64 bit_size = 0, bit_off = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &bit_size); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &bit_off); + op_value = push_str8f(scratch.arena, "bit size %llu, bit offset %llu", bit_size, bit_off); + } break; + + case DW_ExprOp_Pick: { + U8 stack_idx = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &stack_idx); + op_value = push_str8f(scratch.arena, "stack index %u", stack_idx); + } break; + + case DW_ExprOp_PlusUConst: { + U64 addend = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &addend); + op_value = push_str8f(arena, "addend %llu", addend); + } break; + + case DW_ExprOp_Skip: { + S16 x = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &x); + + S64 new_offset = (S64)cursor + x; + if (new_offset >= 0) { + cursor = (U64)new_offset; + op_value = push_str8f(scratch.arena, "constant %lld", x); + } else { + op_value = push_str8f(scratch.arena, "ERROR: negative read offset %lld", new_offset); + } + } break; + + case DW_ExprOp_Bra: { + S16 x = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &x); + op_value = push_str8f(scratch.arena, "%d", x); + } break; + + case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: + case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5: + case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8: + case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11: + case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14: + case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17: + case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20: + case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23: + case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26: + case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29: + case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: { + U64 reg_idx = op - DW_ExprOp_BReg0; + S64 reg_off = 0; + cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off); + op_value = push_str8f(scratch.arena, "%S offset %lld", dw_string_from_register(scratch.arena, arch, reg_idx), reg_off); + } break; + + case DW_ExprOp_FBReg: { + S64 reg_off = 0; + cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off); + op_value = push_str8f(scratch.arena, "offset %lld", reg_off); + } break; + + case DW_ExprOp_BRegX: { + U64 reg_idx = 0; + S64 reg_off = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); + cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off); + op_value = push_str8f(scratch.arena, "register %u (%S) offset %lld", reg_idx, dw_string_from_register(scratch.arena, arch, reg_idx), reg_off); + } break; + + case DW_ExprOp_XDerefSize: + case DW_ExprOp_DerefSize: { + U8 x = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &x); + op_value = push_str8f(scratch.arena, "%u", x); + } break; + + case DW_ExprOp_Call2: { + U16 x = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &x); + op_value = push_str8f(scratch.arena, "%u", x); + } break; + case DW_ExprOp_Call4: { + U32 x = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &x); + op_value = push_str8f(arena, "%u", x); + } break; + case DW_ExprOp_CallRef: { + U64 x = 0; + if (is_dwarf64) { + cursor += str8_deserial_read(raw_data, cursor, &x, 8, 1); + } else { + cursor += str8_deserial_read(raw_data, cursor, &x, 4, 1); + } + op_value = push_str8f(scratch.arena, "%llu", x); + } break; + + case DW_ExprOp_CallFrameCfa: + case DW_ExprOp_FormTlsAddress: + case DW_ExprOp_PushObjectAddress: + case DW_ExprOp_Nop: + case DW_ExprOp_Eq: + case DW_ExprOp_Ge: + case DW_ExprOp_Gt: + case DW_ExprOp_Le: + case DW_ExprOp_Lt: + case DW_ExprOp_Ne: + case DW_ExprOp_Shl: + case DW_ExprOp_Shr: + case DW_ExprOp_Shra: + case DW_ExprOp_Xor: + case DW_ExprOp_XDeref: + case DW_ExprOp_Abs: + case DW_ExprOp_And: + case DW_ExprOp_Div: + case DW_ExprOp_Minus: + case DW_ExprOp_Mod: + case DW_ExprOp_Mul: + case DW_ExprOp_Neg: + case DW_ExprOp_Not: + case DW_ExprOp_Or: + case DW_ExprOp_Plus: + case DW_ExprOp_Rot: + case DW_ExprOp_Swap: + case DW_ExprOp_Deref: + case DW_ExprOp_Dup: + case DW_ExprOp_Drop: + case DW_ExprOp_Over: + case DW_ExprOp_StackValue: { + // no operands + } break; + } + + String8 opcode_str = dw_string_from_expr_op(scratch.arena, ver, ext, op); + if (op_value.size == 0) { + str8_list_pushf(arena, &result, "DW_OP_%S", opcode_str); + } else { + str8_list_pushf(arena, &result, "DW_OP_%S = %S", opcode_str, op_value); + } + } + scratch_end(scratch); + return result; +} + +internal String8 +dw_format_expression_single_line(Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = dw_string_list_from_expression(scratch.arena, raw_data, address_size, arch, ver, ext, is_dwarf64); + String8 expression = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return expression; +} internal void -cv_format_binary_annots(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data) +dw_print_cfi_program(Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64) +{ + Temp scratch = scratch_begin(&arena, 1); + + U64 address_bit_size = bit_size_from_arch(arch); + U64 address_size = address_bit_size / 8; + + for (U64 cursor = 0; cursor < raw_data.size; /* empty */) { + DW_CFA opcode = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &opcode); + + U64 operand = 0; + if ((opcode & DW_CFAMask_OpcodeHi) != 0) { + operand = opcode & DW_CFAMask_Operand; + opcode = opcode & DW_CFAMask_OpcodeHi; + } + + switch (opcode) { + case DW_CFA_Nop: { + rd_printf("DW_CFA_nop"); + } break; + case DW_CFA_SetLoc: { + U64 address = 0; + switch (arch) { + case Arch_x64: cursor += dw_unwind_parse_pointer_x64(raw_data.str, rng_1u64(0,raw_data.size), ptr_ctx, cie->addr_encoding, cursor, &address); break; + + default: NotImplemented; break; + } + rd_printf("DW_CFA_set_loc: %#llx", address); + } break; + case DW_CFA_AdvanceLoc1: { + U8 delta = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &delta); + + rd_printf("DW_CFA_advance_loc1: %+u", delta * cie->code_align_factor); + } break; + case DW_CFA_AdvanceLoc2: { + U16 delta = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &delta); + + rd_printf("DW_CFA_advance_loc2: %+u", delta * cie->code_align_factor); + } break; + case DW_CFA_AdvanceLoc4: { + U32 delta = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &delta); + + rd_printf("DW_CFA_advance_loc4: %+u", delta * cie->code_align_factor); + } break; + case DW_CFA_OffsetExt: { + U64 reg = 0, offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_offset_extended: register %llu (%S), offset %+llu", + reg, + dw_string_from_register(arena, arch, reg), + (S64)offset * cie->data_align_factor); + } break; + case DW_CFA_RestoreExt: { + rd_printf("DW_CFA_restore_extended"); + } break; + case DW_CFA_Undefined: { + U64 reg = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + + rd_printf("DW_CFA_undefined: %llu", reg); + } break; + case DW_CFA_SameValue: { + U64 reg = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + + rd_printf("DW_CFA_same_value: register %llu (%S)", + reg, + dw_string_from_register(scratch.arena, arch, reg)); + } break; + case DW_CFA_Register: { + U64 reg = 0, offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_register: register %llu (%S), offset %+llu", + reg, + dw_string_from_register(scratch.arena, arch, reg), + offset); + } break; + case DW_CFA_RememberState: { + rd_printf("DW_CFA_remember_state"); + } break; + case DW_CFA_RestoreState: { + rd_printf("DW_CFA_restore_state"); + } break; + case DW_CFA_DefCfa: { + U64 reg = 0, offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_def_cfa: register %llu (%S), offset %llu", + reg, + dw_string_from_register(scratch.arena, arch, reg), + offset); + } break; + case DW_CFA_DefCfaRegister: { + U64 reg = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + + rd_printf("DW_CFA_register: %llu (%S)", + reg, + dw_string_from_register(arena, arch, reg)); + } break; + case DW_CFA_DefCfaOffset: { + U64 offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_def_cfa_offset: %llu", offset); + } break; + case DW_CFA_DefCfaExpr: { + U64 block_size = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size); + String8 raw_expr = str8_substr(raw_data, rng_1u64(cursor, cursor + block_size)); + cursor += block_size; + + rd_printf("DW_CFA_def_cfa_expression: %S", + dw_format_expression_single_line(scratch.arena, raw_expr, address_size, arch, ver, ext, is_dwarf64)); + } break; + case DW_CFA_Expr: { + U64 reg = 0, block_size = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size); + String8 raw_expr = str8_substr(raw_data, rng_1u64(cursor, cursor + block_size)); + cursor += block_size; + + rd_printf("DW_CFA_expression: register %llu (%S), expression %S", + reg, + dw_string_from_register(scratch.arena, arch, reg), + dw_format_expression_single_line(scratch.arena, raw_expr, address_size, arch, ver, ext, is_dwarf64)); + } break; + case DW_CFA_OffsetExtSf: { + U64 reg = 0; + S64 offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + cursor += str8_deserial_read_sleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_offset_ext_sf: register %llu (%S), offset %+lld", + reg, dw_string_from_register(scratch.arena, arch, reg), offset * cie->data_align_factor); + } break; + case DW_CFA_DefCfaSf: { + U64 reg = 0; + S64 offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); + cursor += str8_deserial_read_sleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_def_cfa_sf: register %llu (%S), offset %+lld", + reg, dw_string_from_register(scratch.arena, arch, reg), offset * cie->data_align_factor); + } break; + case DW_CFA_ValOffset: { + U64 val = 0, offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &val); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_val_offset: value %llu, offset %+llu", val, offset); + } break; + case DW_CFA_ValOffsetSf: { + U64 val = 0; + S64 offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &val); + cursor += str8_deserial_read_sleb128(raw_data, cursor, &offset); + + rd_printf("DW_CFA_val_offset_sf: value %llu, offset %+lld", val, offset); + } break; + case DW_CFA_ValExpr: { + U64 val = 0; + U64 block_size = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &val); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size); + String8 raw_expr = str8_substr(raw_data, rng_1u64(cursor, cursor + block_size)); + cursor += block_size; + + rd_printf("DW_CFA_val_expr: value %+llu, expression %S", + val, + dw_format_expression_single_line(scratch.arena, raw_expr, address_size, arch, ver, ext, is_dwarf64)); + } break; + case DW_CFA_AdvanceLoc: { + rd_printf("DW_CFA_advance_loc: %+llu", operand); + } break; + case DW_CFA_Offset: { + U64 offset = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + S64 v = (S64)offset * cie->data_align_factor; + + rd_printf("DW_CFA_offset: register %llu (%S), offset %lld", operand, dw_string_from_register(arena, arch, operand), v); + } break; + case DW_CFA_Restore: { + rd_printf("DW_CFA_restore: register %llu (%S)", operand, dw_string_from_register(scratch.arena, arch, operand)); + } break; + default: { + rd_errorf("unknown CFI opcode %u", opcode); + } break; + } + } + + scratch_end(scratch); +} + +internal String8 +dw_format_eh_ptr_enc(Arena *arena, DW_EhPtrEnc enc) +{ + U8 type = enc & DW_EhPtrEnc_TypeMask; + String8 type_str = str8_lit("NULL"); + switch (type) { + case DW_EhPtrEnc_Ptr: type_str = str8_lit("PTR"); break; + case DW_EhPtrEnc_ULEB128: type_str = str8_lit("ULEB128"); break; + case DW_EhPtrEnc_UData2: type_str = str8_lit("UDATA2"); break; + case DW_EhPtrEnc_UData4: type_str = str8_lit("UDATA4"); break; + case DW_EhPtrEnc_UData8: type_str = str8_lit("UDATA8"); break; + case DW_EhPtrEnc_Signed: type_str = str8_lit("SIGNED"); break; + case DW_EhPtrEnc_SLEB128: type_str = str8_lit("SLEB128"); break; + case DW_EhPtrEnc_SData2: type_str = str8_lit("SDATA2"); break; + case DW_EhPtrEnc_SData4: type_str = str8_lit("SDATA4"); break; + case DW_EhPtrEnc_SData8: type_str = str8_lit("SDATA8"); break; + } + U8 modifier = enc & DW_EhPtrEnc_ModifyMask; + String8 modifier_str = str8_lit("NULL"); + switch (modifier) { + case DW_EhPtrEnc_PcRel: modifier_str = str8_lit("PCREL"); break; + case DW_EhPtrEnc_TextRel: modifier_str = str8_lit("TEXTREL"); break; + case DW_EhPtrEnc_DataRel: modifier_str = str8_lit("DATAREL"); break; + case DW_EhPtrEnc_FuncRel: modifier_str = str8_lit("FUNCREL"); break; + } + String8 indir_str = str8_lit(""); + if (enc & DW_EhPtrEnc_Indirect) { + indir_str = str8_lit("(INDIRECT)"); + } + return push_str8f(arena, "Type: %S, Modifier: %S %S", type_str, modifier_str, indir_str); +} + +internal void +dw_print_eh_frame(Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, DW_EhPtrCtx *ptr_ctx) +{ + Temp scratch = scratch_begin(&arena, 1); + DW_CIEUnpacked cie = {0}; + + for (U64 cursor = 0; cursor < raw_eh_frame.size; ) { + U64 header_offset = cursor; + + U64 length = 0; // doesn't include bytes for size + cursor += dw_based_range_read_length(raw_eh_frame.str, rng_1u64(0,raw_eh_frame.size), cursor, &length); + + if (length == 0) { + break; // encountered exit marker + } + + U64 entry_start = cursor; + U64 entry_end = cursor + length; + + U32 entry_id = 0; // always 4-bytes, even when length is encoded as 64-bit integer + cursor += str8_deserial_read_struct(raw_eh_frame, cursor, &entry_id); + + // TODO: fix the freaking DW_EhPtrEnc_PCREL encoding. + // it assumes "frame_base" points to the first byte of .eh_frame + // but here base is start of ELF and we use range to select .eh_frame + // bytes to read, which breaks parsing. + String8 raw_frame = str8_substr(raw_eh_frame, rng_1u64(cursor, cursor + length - sizeof(entry_id))); + Rng1U64 cfi_range = rng_1u64(0,0); + + // CIE + if (entry_id == 0) { + dw_unwind_parse_cie_x64(raw_frame.str, rng_1u64(0,raw_frame.size), ptr_ctx, 0, &cie); + cfi_range = cie.cfi_range; + + rd_printf("CIE @ 0x%X, Length %u", header_offset, length); + rd_indent(); + rd_printf("LSDA Encoding: %S", dw_format_eh_ptr_enc(scratch.arena, cie.lsda_encoding)); + rd_printf("Address Encoding: %S", dw_format_eh_ptr_enc(scratch.arena, cie.addr_encoding)); + rd_printf("Augmentation: %S", cie.augmentation); + rd_printf("Code Align Factor: %llu", cie.code_align_factor); + rd_printf("Data Align Factor: %lld", cie.data_align_factor); + rd_printf("Return Address Register: %u", cie.ret_addr_reg); + rd_printf("Handler IP: %#llx", cie.handler_ip); + rd_unindent(); + } + // FDE + else { + DW_FDEUnpacked fde = {0}; + dw_unwind_parse_fde_x64(raw_eh_frame.str, rng_1u64(0,raw_eh_frame.size), ptr_ctx, &cie, 0, &fde); + cfi_range = fde.cfi_range; + + // calc parent CIE offset + AssertAlways(entry_start >= entry_id); + U64 cie_offset = entry_start - entry_id; NotImplemented; // TODO: syms_safe_sub_u64(range.min + entry_start, entry_id); + + rd_printf("FDE @ %#llx, Length %u, Parent CIE @ %#llx", header_offset, length, cie_offset); + rd_indent(); + rd_printf("IP Range: %#llx-%#llx", fde.ip_voff_range.min, fde.ip_voff_range.max); + rd_printf("LSDA IP: %#llx", fde.lsda_ip); + rd_unindent(); + } + + // print CFI program + rd_printf("CFI Program:"); + rd_indent(); + + B32 is_dwarf64 = length > max_U32; + String8 raw_cfi = str8_substr(raw_eh_frame, cfi_range); + dw_print_cfi_program(scratch.arena, out, indent, raw_cfi, &cie, ptr_ctx, arch, ver, ext, is_dwarf64); + + rd_unindent(); + rd_newline(); + + // advance to next entry + cursor = entry_end; + } + + scratch_end(scratch); +} + +internal DW_AttribValueResolveParams +rd_dw_resolve_params_from_comp_root(DW_CompRoot comp_root) +{ + DW_AttribValueResolveParams resolve_params = {0}; + resolve_params.version = comp_root.version; + resolve_params.addr_size = comp_root.address_size; + resolve_params.containing_unit_info_off = comp_root.info_off; + resolve_params.debug_addrs_base = comp_root.addrs_base; + resolve_params.debug_rnglists_base = comp_root.rnglist_base; + resolve_params.debug_str_offs_base = comp_root.stroffs_base; + resolve_params.debug_loclists_base = comp_root.loclist_base; + return resolve_params; +} + +internal void +dw_print_debug_info(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed) +{ + Temp scratch = scratch_begin(&arena, 1); + + Rng1U64List comp_unit_ranges = dw_comp_unit_ranges_from_info(scratch.arena, sections->v[DW_Section_Info]); + + if (comp_unit_ranges.count > 0) { + rd_printf("# %S", sections->v[DW_Section_Info].name); + rd_indent(); + } + + U64 comp_idx = 0; + for (Rng1U64Node *comp_unit_range_n = comp_unit_ranges.first; comp_unit_range_n != 0; comp_unit_range_n = comp_unit_range_n->next, ++comp_idx) { + Temp comp_temp = temp_begin(scratch.arena); + + Rng1U64 comp_unit_range = comp_unit_range_n->v; + DW_CompRoot comp_root = dw_comp_root_from_range(comp_temp.arena, sections, comp_unit_range, relaxed); + DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(&comp_root); + DW_Ext ext = dw_ext_from_params(comp_root.producer, arch, image_type); + + // print comp info + rd_printf("Compilation Unit #%u", comp_idx); + rd_indent(); + rd_printf("Version: %u", comp_root.version); + rd_printf("Address Size: %llu", comp_root.address_size); + rd_printf("Abbrev Offset: %#llx", comp_root.abbrev_off); + rd_printf("Tags Range: %#llx-%#llx (Size %#llx)", comp_root.tags_info_range.min, comp_root.tags_info_range.max, dim_1u64(comp_root.tags_info_range)); + rd_newline(); + + // prase tags + U32 tag_depth = 0; + for (U64 info_off = comp_root.tags_info_range.min; info_off < comp_root.tags_info_range.max; /* empty */) { + Temp tag_temp = temp_begin(scratch.arena); + + U64 tag_info_off = info_off; + DW_Tag *tag = dw_tag_from_info_offset(tag_temp.arena, sections, comp_root.abbrev_table, comp_root.version, ext, comp_root.language, comp_root.address_size, info_off, relaxed); + + // advance parse + info_off = tag->info_range.max; + + String8 tag_str = dw_string_from_tag_kind(tag_temp.arena, tag->kind); + rd_printf("<%x><%llx> DW_Tag_%S (Abbrev Number: %llu)", tag_depth, tag_info_off, tag_str, tag->abbrev_id); + rd_indent(); + + // parse attributes + for (DW_AttribNode *attrib_node = tag->attribs.first; attrib_node != 0; attrib_node = attrib_node->next) { + Temp attrib_temp = temp_begin(tag_temp.arena); + + DW_Attrib *attrib = &attrib_node->attrib; + DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, attrib->form_kind, attrib->value_class, attrib->form_value); + + String8List attrib_list = {0}; + + // attribute .debug_info offset + str8_list_pushf(attrib_temp.arena, &attrib_list, "<%llx> ", attrib->info_off); + + // attribute kind + String8 attrib_kind_str = dw_string_from_attrib_kind(attrib_temp.arena, comp_root.version, ext, attrib->attrib_kind); + if (attrib_kind_str.size == 0) { + if (relaxed) { + attrib_kind_str = dw_string_from_attrib_kind(attrib_temp.arena, DW_Version_Last, ext, attrib->attrib_kind); + } + } + if (attrib_kind_str.size == 0) { + str8_list_pushf(attrib_temp.arena, &attrib_list, "Unknown(%#x) ", attrib->attrib_kind); + } else { + str8_list_pushf(attrib_temp.arena, &attrib_list, "DW_Attrib_%-20S ", attrib_kind_str); + } + + // form kind + String8 form_kind_str = dw_string_from_form_kind(scratch.arena, comp_root.version, attrib->form_kind); + str8_list_pushf(attrib_temp.arena, &attrib_list, "DW_Form_%-15S", form_kind_str); + + switch (attrib->value_class) { + default: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "ERROR: Unknown value class"); + } break; + case DW_AttribClass_Undefined: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "ERROR: Undefined value class"); + } break; + case DW_AttribClass_Address: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_Block: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx %#llx", attrib_value.v[0], attrib_value.v[1]); + } break; + case DW_AttribClass_Const: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + switch (attrib->attrib_kind) { + case DW_Attrib_Language: { + String8 lang_str = dw_string_from_language(attrib_temp.arena, attrib_value.v[0]); + str8_list_pushf(attrib_temp.arena, &attrib_list, " (%S)", lang_str); + } break; + } + } break; + case DW_AttribClass_ExprLoc: { + DW_Mode mode = dw_mode_from_sec(sections, DW_Section_Info); + Rng1U64 sect_range = rng_1u64(0, sections->v[DW_Section_Info].data.size); + Rng1U64 expr_range = rng_1u64(sect_range.min+attrib_value.v[0], sect_range.min+attrib_value.v[0]+attrib_value.v[1]); + String8 raw_expr = str8_substr(sections->v[DW_Section_Info].data, expr_range); + B32 is_dwarf64 = mode == DW_Mode_32Bit ? 1 : 0; + String8 expression = dw_format_expression_single_line(attrib_temp.arena, raw_expr, comp_root.address_size, arch, comp_root.version, ext, is_dwarf64); + str8_list_push(attrib_temp.arena, &attrib_list, expression); + } break; + case DW_AttribClass_Flag: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_LinePtr: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_LocListPtr: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_MacPtr: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_RngListPtr: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_RngList: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_Reference: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "<%llx>", attrib_value.v[0]); + } break; + case DW_AttribClass_String: { + String8 string = dw_string_from_attrib_value(sections, attrib_value); + str8_list_pushf(attrib_temp.arena, &attrib_list, "\"%S\"", string); + } break; + case DW_AttribClass_StrOffsetsPtr: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + case DW_AttribClass_AddrPtr: { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + } break; + } + + String8 print = str8_list_join(attrib_temp.arena, &attrib_list, 0); + rd_printf("%S", print); + + temp_end(attrib_temp); + } + + B32 is_ender_tag = tag->abbrev_id == 0; + + if (tag->has_children) { + if (is_ender_tag) { + rd_errorf("null-tag cannot have children"); + } + rd_indent(); + tag_depth += 1; + } + + if (is_ender_tag) { + if (tag_depth == 0) { + rd_errorf("malformed data detected, too many null tags"); + } else { + rd_unindent(); + tag_depth -= 1; + } + } + + rd_unindent(); + + temp_end(tag_temp); + } + temp_end(comp_temp); + + rd_unindent(); + rd_newline(); + } + + if (comp_unit_ranges.count > 0) { + rd_unindent(); + } + + scratch_end(scratch); +} + +internal void +dw_print_debug_abbrev(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + Temp scratch = scratch_begin(&arena, 1); + + DW_Section abbrev = sections->v[DW_Section_Abbrev]; + String8 raw_abbrev = abbrev.data; + + if (raw_abbrev.size) { + rd_printf("# %S", sections->v[DW_Section_Abbrev].name); + rd_indent(); + } + + for (U64 cursor = 0; cursor < raw_abbrev.size; ) { + U64 id = 0; + cursor += str8_deserial_read_uleb128(raw_abbrev, cursor, &id); + + if (id == 0) { + continue; // end of abbrev data for CU + } + + Temp temp = temp_begin(scratch.arena); + + U64 tag = 0; + U8 has_children = 0; + cursor += str8_deserial_read_uleb128(raw_abbrev, cursor, &tag); + cursor += str8_deserial_read_struct(raw_abbrev, cursor, &has_children); + + rd_printf("%llu DW_Tag_%S %s", id, dw_string_from_tag_kind(temp.arena, tag), has_children ? "[has children]" : "[no children]"); + rd_indent(); + for (;;) { + U64 attrib_id = 0, form_id = 0; + cursor += str8_deserial_read_uleb128(raw_abbrev, cursor, &attrib_id); + cursor += str8_deserial_read_uleb128(raw_abbrev, cursor, &form_id); + if (attrib_id == 0) { + break; + } + String8 attrib_str = dw_string_from_attrib_kind(temp.arena, DW_Version_Last, DW_Ext_All, attrib_id); + String8 form_str = dw_string_from_form_kind(temp.arena, DW_Version_Last, form_id); + rd_printf("DW_Attrib_%-20S DW_Form_%S", attrib_str, form_str); + } + rd_unindent(); + + temp_end(temp); + } + + if (raw_abbrev.size) { + rd_unindent(); + } + + scratch_end(scratch); +} + +internal void +dw_print_debug_line(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, B32 relaxed) +{ + Temp scratch = scratch_begin(&arena, 1); + + DW_Mode mode = dw_mode_from_sec(sections, DW_Section_Line); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_Line); + void *base = dw_base_from_sec(sections, DW_Section_Line); + Rng1U64List comp_unit_range_list = dw_comp_unit_ranges_from_info(scratch.arena, sections->v[DW_Section_Info]); + + if (dim_1u64(range)) { + rd_printf("# %S", sections->v[DW_Section_Line].name); + rd_indent(); + } + + U64 cursor = 0; + for (Rng1U64Node *comp_unit_range_n = comp_unit_range_list.first; comp_unit_range_n != 0; comp_unit_range_n = comp_unit_range_n->next) { + Temp comp_temp = temp_begin(scratch.arena); + + Rng1U64 comp_unit_range = comp_unit_range_n->v; + U64 line_table_offset = cursor; + DW_CompRoot comp_root = dw_comp_root_from_range(comp_temp.arena, sections, comp_unit_range, relaxed); + DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(&comp_root); + + DW_LineVMHeader vm_header = {0}; + cursor += dw_read_line_vm_header(arena, base, range, cursor, mode, sections, resolve_params, comp_root.compile_dir, comp_root.name, &vm_header); + + if (vm_header.unit_length == 0) { + continue; + } + + rd_printf("Line table offset: %#llx", line_table_offset); + rd_printf("Line table length: %llu", vm_header.unit_length); + rd_printf("Version: %u", vm_header.version); + rd_printf("Address size: %u", vm_header.address_size); + rd_printf("Segment selector size: %u", vm_header.segment_selector_size); + rd_printf("Header length: %llu", vm_header.header_length); + rd_printf("Program offset: %#llx", vm_header.program_off); + rd_printf("Min instruction length: %u", vm_header.min_inst_len); + rd_printf("Max ops for instruction: %u", vm_header.max_ops_for_inst); + rd_printf("Default Is Stmt: %u", vm_header.default_is_stmt); + rd_printf("Line base: %d", vm_header.line_base); + rd_printf("Line range: %u", vm_header.line_range); + rd_printf("Opcode base: %u", vm_header.opcode_base); + rd_printf("Opcode lengths: %S", rd_format_hex_array(comp_temp.arena, vm_header.opcode_lens, vm_header.num_opcode_lens)); + rd_newline(); + + rd_printf("Directory Table:"); + rd_indent(); + rd_printf("%-4s %-8s", "No.", "String"); + for (U64 dir_idx = 0; dir_idx < vm_header.dir_table.count; ++dir_idx) { + rd_printf("%-4llu %S", dir_idx, vm_header.dir_table.v[dir_idx]); + } + rd_unindent(); + rd_newline(); + + rd_printf("File Table:"); + rd_indent(); + rd_printf("%-4s %-8s %-8s %-17s %-8s %-8s", "No.", "DirIdx", "Time", "MD5", "Size", "Name"); + for (U64 file_idx = 0; file_idx < vm_header.file_table.count; ++file_idx) { + DW_LineFile *file = &vm_header.file_table.v[file_idx]; + rd_printf("%-4llu %-8llu %-8llu %08llx-%08llx %-8llu %S", + file_idx, + file->dir_idx, + file->modify_time, + file->md5_digest[0], + file->md5_digest[1], + file->file_size, + file->file_name); + } + rd_unindent(); + rd_newline(); + + B32 end_of_seq = 0; + DW_LineVMState vm_state = {0}; + dw_line_vm_reset(&vm_state, vm_header.default_is_stmt); + + rd_printf("Opcodes:"); + for (; cursor < vm_header.unit_opl; ) { + U64 opcode_offset = cursor; + + Temp opcode_temp = temp_begin(scratch.arena); + + String8List list = {0}; + + // parse opcode + U8 opcode = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &opcode); + + // push opcode id + String8 opcode_str = dw_string_from_std_opcode(opcode_temp.arena, opcode); + str8_list_push(arena, &list, opcode_str); + + // format operands + switch (opcode) { + default: { + if (opcode >= vm_header.opcode_base) { + U32 adjusted_opcode = 0; + U32 op_advance = 0; + S32 line_advance = 0; + U64 addr_advance = 0; + if (vm_header.line_range > 0 && vm_header.max_ops_for_inst > 0) { + adjusted_opcode = (U32)(opcode - vm_header.opcode_base); + op_advance = adjusted_opcode / vm_header.line_range; + line_advance = (S32)vm_header.line_base + ((S32)adjusted_opcode) % (S32)vm_header.line_range; + addr_advance = vm_header.min_inst_len * ((vm_state.op_index+op_advance) / vm_header.max_ops_for_inst); + } + + vm_state.address += addr_advance; + vm_state.op_index = (vm_state.op_index + op_advance) % vm_header.max_ops_for_inst; + vm_state.line = (U32)((S32)vm_state.line + line_advance); + vm_state.basic_block = 0; + vm_state.prologue_end = 0; + vm_state.epilogue_begin = 0; + vm_state.discriminator = 0; + + end_of_seq = 0; + + str8_list_pushf(opcode_temp.arena, &list, "advance line by %d, advance address by %lld", line_advance, addr_advance); + } else { + if (opcode > 0 && opcode <= vm_header.num_opcode_lens) { + str8_list_pushf(opcode_temp.arena, &list, "skip operands:"); + U64 num_operands = vm_header.opcode_lens[opcode - 1]; + for (U8 i = 0; i < num_operands; i += 1){ + U64 operand = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &operand); + str8_list_pushf(opcode_temp.arena, &list, " %llx", operand); + } + } + } + }break; + + case DW_StdOpcode_Copy: { + str8_list_pushf(opcode_temp.arena, &list, "Line = %u, Column = %u, Address = %#llx", vm_state.line, vm_state.column, vm_state.address); + end_of_seq = 0; + vm_state.discriminator = 0; + vm_state.basic_block = 0; + vm_state.prologue_end = 0; + vm_state.epilogue_begin = 0; + } break; + case DW_StdOpcode_AdvancePc: { + U64 advance = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &advance); + dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); + str8_list_pushf(opcode_temp.arena, &list, "advance %#llx ; current address %#llx", advance, vm_state.address); + } break; + + case DW_StdOpcode_AdvanceLine: { + S64 advance = 0; + cursor += dw_based_range_read_sleb128(base, range, cursor, &advance); + vm_state.line += advance; + str8_list_pushf(opcode_temp.arena, &list, "advance %lld ; current line %u", advance, vm_state.line); + } break; + + case DW_StdOpcode_SetFile: { + U64 file_idx = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &file_idx); + vm_state.file_index = file_idx; + + String8 path = dw_path_from_file_idx(opcode_temp.arena, &vm_header, file_idx); + str8_list_pushf(opcode_temp.arena, &list, "%llu \"%S\"", file_idx, path); + } break; + + case DW_StdOpcode_SetColumn: { + U64 column = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &column); + vm_state.column = column; + str8_list_pushf(opcode_temp.arena, &list, "%llu", column); + } break; + + case DW_StdOpcode_NegateStmt: { + vm_state.is_stmt = !vm_state.is_stmt; + str8_list_pushf(opcode_temp.arena, &list, "is_stmt = %u", vm_state.is_stmt); + } break; + + case DW_StdOpcode_SetBasicBlock: { + vm_state.basic_block = 1; + } break; + + case DW_StdOpcode_ConstAddPc: { + U64 advance = (0xffu - vm_header.opcode_base)/vm_header.line_range; + dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); + str8_list_pushf(opcode_temp.arena, &list, "%lld ; address %#llx", advance, vm_state.address); + }break; + + case DW_StdOpcode_FixedAdvancePc: { + U64 operand = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &operand); + vm_state.address += operand; + vm_state.op_index = 0; + str8_list_pushf(opcode_temp.arena, &list, "%llu", operand); + } break; + + case DW_StdOpcode_SetPrologueEnd: { + vm_state.prologue_end = 1; + } break; + + case DW_StdOpcode_SetEpilogueBegin: { + vm_state.epilogue_begin = 1; + } break; + + case DW_StdOpcode_SetIsa: { + U64 v = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &v); + vm_state.isa = v; + str8_list_pushf(opcode_temp.arena, &list, "%llu", v); + } break; + + case DW_StdOpcode_ExtendedOpcode: { + U64 length = 0; + U8 ext_opcode = 0; + + cursor += dw_based_range_read_uleb128(base, range, cursor, &length); + U64 opcode_end = cursor + length; + + cursor += dw_based_range_read_struct(base, range, cursor, &ext_opcode); + + String8 ext_opcode_str = dw_string_from_ext_opcode(opcode_temp.arena, ext_opcode); + //str8_list_pushf(opcode_temp.arena, &list, "length: %u", length); + str8_list_push(opcode_temp.arena, &list, ext_opcode_str); + switch (ext_opcode) { + case DW_ExtOpcode_EndSequence: { + vm_state.end_sequence = 1; + dw_line_vm_reset(&vm_state, vm_header.default_is_stmt); + end_of_seq = 1; + } break; + case DW_ExtOpcode_SetAddress: { + U64 address = 0; + cursor += dw_based_range_read(base, range, cursor, comp_root.address_size, &address); + vm_state.address = address; + vm_state.op_index = 0; + vm_state.busted_seq = address != 0; + str8_list_pushf(opcode_temp.arena, &list, "%#llx", address); + } break; + case DW_ExtOpcode_DefineFile: { + String8 file_name = dw_based_range_read_string(base, range, cursor); + cursor += file_name.size + 1; + U64 dir_idx = 0, modify_time = 0, file_size = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &dir_idx); + cursor += dw_based_range_read_uleb128(base, range, cursor, &modify_time); + cursor += dw_based_range_read_uleb128(base, range, cursor, &file_size); + str8_list_pushf(opcode_temp.arena, &list, "%S Dir: %llu, Time: %llu, Size: %llu", file_name, dir_idx, modify_time, file_size); + } break; + case DW_ExtOpcode_SetDiscriminator: { + U64 v = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &v); + vm_state.discriminator = v; + str8_list_pushf(arena, &list, "%llu", v); + } break; + } + + cursor = opcode_end; + } break; + } + + String8 string = str8_list_join(opcode_temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("[%08llx] %S", opcode_offset, string); + + temp_end(opcode_temp); + } + temp_end(comp_temp); + + rd_newline(); + } + + if (dim_1u64(range)) { + rd_unindent(); + } + + scratch_end(scratch); +} + +internal void +dw_print_debug_str(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + String8 data = sections->v[DW_Section_Str].data; + rd_printf("# %S", sections->v[DW_Section_Str].name); + rd_indent(); + for (U64 cursor = 0, read_size = 0; cursor < data.size; cursor += read_size) { + String8 string = {0}; + read_size = str8_deserial_read_cstr(data, cursor, &string); + rd_printf("[%08llx] { %llu, \"%S\" }", cursor, string.size, string); + } + rd_unindent(); +} + +internal void +dw_print_debug_loc(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed) +{ + DW_Section info = sections->v[DW_Section_Info]; + DW_Section loc = sections->v[DW_Section_Loc]; + + if (loc.data.size == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_Loc].name); + rd_indent(); + + // TODO: warn about overlaps in ranges + + Rng1U64List comp_unit_range_list = dw_comp_unit_ranges_from_info(scratch.arena, info); + + // parse debug_info for attributes with LOCLIST and store .debug_loc offsets + U64List *loc_lists = push_array(scratch.arena, U64List, comp_unit_range_list.count); + U64 *address_sizes = push_array(scratch.arena, U64, comp_unit_range_list.count); + U64 *address_bases = push_array(scratch.arena, U64, comp_unit_range_list.count); + DW_Version *ver_arr = push_array(scratch.arena, DW_Version, comp_unit_range_list.count); + DW_Ext *ext_arr = push_array(scratch.arena, DW_Ext, comp_unit_range_list.count); + + U64 comp_idx = 0; + for (Rng1U64Node *comp_unit_range_n = comp_unit_range_list.first; comp_unit_range_n != 0; comp_unit_range_n = comp_unit_range_n->next, ++comp_idx) { + Temp comp_temp = temp_begin(arena); + + Rng1U64 comp_unit_range = comp_unit_range_n->v; + DW_CompRoot comp_root = dw_comp_root_from_range(comp_temp.arena, sections, comp_unit_range, relaxed); + DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(&comp_root); + + // store info about comp unit + address_sizes[comp_idx] = comp_root.address_size; + address_bases[comp_idx] = comp_root.base_addr; + ver_arr[comp_idx] = comp_root.version; + ext_arr[comp_idx] = dw_ext_from_params(comp_root.producer, arch, image_type); + + // parse tags + for (U64 info_off = comp_root.tags_info_range.min; info_off < comp_root.tags_info_range.max; /* empty */) { + Temp tag_temp = temp_begin(scratch.arena); + + DW_Tag *tag = dw_tag_from_info_offset(tag_temp.arena, sections, comp_root.abbrev_table, ver_arr[comp_idx], ext_arr[comp_idx], comp_root.language, comp_root.address_size, info_off, relaxed); + + // parse attribs + for (DW_AttribNode *attrib_node = tag->attribs.first; attrib_node != 0; attrib_node = attrib_node->next) { + DW_Attrib *attrib = &attrib_node->attrib; + B32 is_sect_offset = attrib->value_class == DW_AttribClass_LocListPtr || (attrib->value_class == DW_AttribClass_LocList && attrib->form_kind == DW_Form_SecOffset); + B32 is_sect_index = attrib->value_class == DW_AttribClass_LocList && attrib->form_kind == DW_Form_LocListx; + if (is_sect_offset) { + DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, attrib->form_kind, attrib->value_class, attrib->form_value); + u64_list_push(scratch.arena, &loc_lists[comp_idx], attrib_value.v[0]); + } else if (is_sect_index) { + // TODO: support for section indexing + } + } + + // advance to next tag + info_off = tag->info_range.max; + + temp_end(tag_temp); + } + + temp_end(comp_temp); + } + + void *base = dw_base_from_sec(sections, DW_Section_Loc); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_Loc); + + rd_printf("%S:", dw_string_from_section_kind(scratch.arena, DW_Section_Loc)); + rd_indent(); + rd_printf("%-8s %-8s %-8s %s", "Offset", "Min", "Max", "Expression"); + for (U32 comp_idx = 0; comp_idx < comp_unit_range_list.count; ++comp_idx) { + Temp locs_temp = temp_begin(scratch.arena); + + DW_Version ver = ver_arr[comp_idx]; + DW_Ext ext = ext_arr[comp_idx]; + + U64Array locs = u64_array_from_list(locs_temp.arena, &loc_lists[comp_idx]); + u64_array_sort(locs.count, locs.v); + + U64Array locs_set = remove_duplicates_u64_array(locs_temp.arena, locs); + U64 address_size = address_sizes[comp_idx]; + U64 base_selector = (address_size == 8) ? max_U64 : max_U32; + + for (U64 loc_idx = 0; loc_idx < locs_set.count; ++loc_idx) { + U64 base_address = address_bases[comp_idx]; + for (U64 cursor = locs_set.v[loc_idx]; cursor < dim_1u64(range); /* empty */) { + Temp range_temp = temp_begin(arena); + + String8List list = {0}; + + // offset + str8_list_pushf(range_temp.arena, &list, "%08llx", cursor); + + // parse entry + U64 v0 = 0, v1 = 0; + cursor += dw_based_range_read(base, range, cursor, address_size, &v0); + cursor += dw_based_range_read(base, range, cursor, address_size, &v1); + + B32 is_list_end = v0 == 0 && v1 == 0; + if (is_list_end) { + str8_list_pushf(range_temp.arena, &list, ""); + } else if (v0 == base_selector) { + base_address = v1; + } else { + // this is not mentioned in the spec (june 10, 2010) + // found reference in gdb/binutils/dwarf.c => display_loc_list + U16 expr_size = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &expr_size); + Rng1U64 expr_range = rng_1u64(range.min+cursor, range.min+cursor+expr_size); + cursor += expr_size; + + // format dwarf expression + B32 is_dwarf64 = (address_size == 8); + String8 raw_expr = str8((U8*)base+expr_range.min, dim_1u64(expr_range)); + String8 expression = dw_format_expression_single_line(range_temp.arena, raw_expr, address_size, arch, ver, ext, is_dwarf64); + + // push entry + U64 min = base_address + v0; + U64 max = base_address + v1; + str8_list_pushf(range_temp.arena, &list, "%08llx %08llx %S", min, max, expression); + } + + // print entry + String8 print = str8_list_join(range_temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", print); + + // cleanup temp + temp_end(range_temp); + + // exit check + if (is_list_end) { + break; + } + } + } + + temp_end(locs_temp); + } + rd_unindent(); + + rd_unindent(); + scratch_end(scratch); +} + +internal void +dw_print_debug_ranges(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed) +{ + DW_Section ranges = sections->v[DW_Section_Ranges]; + void *base = dw_base_from_sec(sections, DW_Section_Ranges); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_Ranges); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + Rng1U64List comp_unit_range_list = dw_comp_unit_ranges_from_info(scratch.arena, sections->v[DW_Section_Info]); + + // parse debug_info for attributes with LOCLIST and store .debug_loc offsets + U64List *loc_lists = push_array(scratch.arena, U64List, comp_unit_range_list.count); + U64 *address_sizes = push_array(scratch.arena, U64, comp_unit_range_list.count); + U64 *address_bases = push_array(scratch.arena, U64, comp_unit_range_list.count); + + { + U64 comp_idx = 0; + for (Rng1U64Node *comp_unit_range_n = comp_unit_range_list.first; comp_unit_range_n != 0; comp_unit_range_n = comp_unit_range_n->next, ++comp_idx) { + Rng1U64 comp_unit_range = comp_unit_range_n->v; + DW_CompRoot comp_root = dw_comp_root_from_range(scratch.arena, sections, comp_unit_range, relaxed); + DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(&comp_root); + DW_Ext ext = dw_ext_from_params(comp_root.producer, arch, image_type); + + // store info about comp unit + address_sizes[comp_idx] = comp_root.address_size; + address_bases[comp_idx] = comp_root.base_addr; + + // parse tags + for (U64 info_off = comp_root.tags_info_range.min; info_off < comp_root.tags_info_range.max; /* empty */) { + DW_Tag *tag = dw_tag_from_info_offset(scratch.arena, sections, comp_root.abbrev_table, comp_root.version, ext, comp_root.language, comp_root.address_size, info_off, relaxed); + + // parse attribs + for (DW_AttribNode *attrib_node = tag->attribs.first; attrib_node != 0; attrib_node = attrib_node->next) { + DW_Attrib *attrib = &attrib_node->attrib; + B32 is_sect_offset = attrib->value_class == DW_AttribClass_RngListPtr || (attrib->value_class == DW_AttribClass_RngList && attrib->form_kind == DW_Form_SecOffset); + B32 is_sect_index = attrib->value_class == DW_AttribClass_RngList && attrib->form_kind == DW_Form_RngListx; + if (is_sect_offset) { + DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, attrib->form_kind, attrib->value_class, attrib->form_value); + u64_list_push(scratch.arena, &loc_lists[comp_idx], attrib_value.v[0]); + } else if (is_sect_index) { + // TODO: support for section indexing + } + } + info_off = tag->info_range.max; + } + } + } + + rd_printf("# %S", sections->v[DW_Section_Ranges].name); + rd_indent(); + rd_printf("%-8s %-8s %-8s", "Offset", "Min", "Max"); + for (U32 comp_idx = 0; comp_idx < comp_unit_range_list.count; ++comp_idx) { + U64Array locs = u64_array_from_list(scratch.arena, &loc_lists[comp_idx]); + u64_array_sort(locs.count, locs.v); + U64Array locs_set = remove_duplicates_u64_array(scratch.arena, locs); + U64 address_size = address_sizes[comp_idx]; + U64 base_selector = (address_size == 8) ? max_U64 : max_U32; + + for (U64 loc_idx = 0; loc_idx < locs_set.count; ++loc_idx) { + U64 base_address = address_bases[comp_idx]; + for (U64 cursor = locs_set.v[loc_idx]; cursor < dim_1u64(range); /* empty */) { + Temp range_temp = temp_begin(scratch.arena); + + String8List list = {0}; + + // offset + str8_list_pushf(range_temp.arena, &list, "%08llx", cursor); + + // parse entry + U64 v0 = 0, v1 = 0; + cursor += dw_based_range_read(base, range, cursor, address_size, &v0); + cursor += dw_based_range_read(base, range, cursor, address_size, &v1); + + B32 is_list_end = v0 == 0 && v1 == 0; + if (is_list_end) { + str8_list_pushf(range_temp.arena, &list, ""); + } else if (v0 == base_selector) { + base_address = v1; + } else { + // push entry + U64 min = base_address + v0; + U64 max = base_address + v1; + str8_list_pushf(range_temp.arena, &list, "%08llx %08llx", min, max); + } + + // print entry + String8 print = str8_list_join(range_temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", print); + + temp_end(range_temp); + + // exit check + if (is_list_end) { + break; + } + } + } + } +} + +internal void +dw_print_debug_aranges(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + void *base = dw_base_from_sec(sections, DW_Section_ARanges); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_ARanges); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_ARanges].name); + rd_indent(); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 unit_length = 0; + DW_Version version = 0; + U64 debug_info_offset = 0; + U8 address_size = 0; + U8 segment_selector_size = 0; + + cursor += dw_based_range_read_length(base, range, cursor, &unit_length); + U64 unit_opl = cursor + unit_length; + cursor += dw_based_range_read_struct(base, range, cursor, &version); + + B32 is_dwarf64 = unit_length >= max_U32; + U64 int_size = is_dwarf64 ? sizeof(U64) : sizeof(U32); + cursor += dw_based_range_read(base, range, cursor, int_size, &debug_info_offset); + + cursor += dw_based_range_read_struct(base, range, cursor, &address_size); + cursor += dw_based_range_read_struct(base, range, cursor, &segment_selector_size); + + U64 tuple_size = address_size * 2 + segment_selector_size; + U64 bytes_too_far_past_boundary = cursor % tuple_size; + if (bytes_too_far_past_boundary > 0) { + cursor += tuple_size - bytes_too_far_past_boundary; + } + + rd_printf("Unit length: %llu", unit_length); + rd_printf("Version: %u", version); + rd_printf("Debug info offset: %#llx", debug_info_offset); + rd_printf("Address size: %u", address_size); + rd_printf("Segment selector size: %u", segment_selector_size); + + if (version != DW_Version_2) { + rd_warningf("Version value must be 2 (DWARF5 sepc, Feb 13, 2017)"); + } + + rd_indent(); + rd_printf("%-8s %-8s", "Offset", "Range"); + for (; cursor < unit_opl; ) { + Temp temp = temp_begin(arena); + + String8List list = {0}; + + str8_list_pushf(temp.arena, &list, "%08llx", cursor); + + U64 segment_selector = 0; + U64 address = 0; + U64 length = 0; + cursor += dw_based_range_read(base, range, cursor, segment_selector_size, &segment_selector); + cursor += dw_based_range_read(base, range, cursor, address_size, &address); + cursor += dw_based_range_read(base, range, cursor, address_size, &length); + + if (segment_selector == 0 && address == 0 && length == 0) { + str8_list_pushf(temp.arena, &list, ""); + } else { + if (segment_selector != 0) { + str8_list_pushf(temp.arena, &list, "%02llu:", segment_selector); + } + str8_list_pushf(temp.arena, &list, "%llx-%llx", address, address+length); + } + + String8 print = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(" ") }); + rd_printf("%S", print); + + temp_end(temp); + } + rd_unindent(); + rd_newline(); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal void +dw_print_debug_addr(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + void *base = dw_base_from_sec(sections, DW_Section_Addr); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_Addr); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_Addr].name); + rd_indent(); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 unit_length = 0; + DW_Version version = 0; + U8 address_size = 0; + U8 segment_selector_size = 0; + + U64 unit_offset = cursor; + cursor += dw_based_range_read_length(base, range, cursor, &unit_length); + + U64 unit_opl = cursor + unit_length; + cursor += dw_based_range_read_struct(base, range, cursor, &version); + cursor += dw_based_range_read_struct(base, range, cursor, &address_size); + cursor += dw_based_range_read_struct(base, range, cursor, &segment_selector_size); + + U64 tuple_size = address_size * 2 + segment_selector_size; + U64 bytes_too_far_past_boundary = cursor % tuple_size; + if (bytes_too_far_past_boundary > 0) { + cursor += tuple_size - bytes_too_far_past_boundary; + } + + rd_printf("Unit @ %#llx, length %llu", unit_offset, unit_length); + rd_printf("Version: %u", version); + rd_printf("Address size: %u", address_size); + rd_printf("Segment selector size: %u", segment_selector_size); + + if (version != DW_Version_2) { + rd_warningf("Version value must be 5 (DWARF5 sepc, Feb 13, 2017)"); + } + + rd_indent(); + rd_printf("%-8s %-8s", "Offset", "Address"); + for (; cursor < unit_opl; ) { + Temp temp = temp_begin(arena); + + String8List list = {0}; + + str8_list_pushf(temp.arena, &list, "%08X", cursor); + + U64 segment_selector = 0; + U64 address = 0; + cursor += dw_based_range_read(base, range, cursor, segment_selector_size, &segment_selector); + cursor += dw_based_range_read(base, range, cursor, address_size, &address); + + if (segment_selector == 0 && address == 0) { + str8_list_pushf(temp.arena, &list, ""); + } else { + if (segment_selector != 0) { + str8_list_pushf(temp.arena, &list, "%02u:", segment_selector); + } + str8_list_pushf(temp.arena, &list, "%llx", address); + } + + String8 print = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", print); + + temp_end(temp); + } + rd_unindent(); + rd_newline(); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal U64 +dw_based_range_read_address(void *base, Rng1U64 range, U64 offset, Rng1U64Array segment_ranges, U8 segment_selector_size, U8 address_size, U64 *address_out) +{ + U64 read_offset = offset; + + // read segment + U64 segment_selector = 0; + read_offset += dw_based_range_read(base, range, read_offset, segment_selector_size, &segment_selector); + + // read address + U64 address = 0; + read_offset += dw_based_range_read(base, range, read_offset, address_size, &address); + + // apply segment offset + B32 is_address_segment_relative = segment_selector_size > 0; + if (is_address_segment_relative) { + if (segment_selector < segment_ranges.count) { + address += segment_ranges.v[segment_selector].min; + } else { + Assert(!"invalid segment selector"); + } + } + + U64 read_size = (read_offset - offset); + return read_size; +} + +internal void +dw_print_debug_loclists(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_virtual_ranges, Arch arch) +{ + void *base = dw_base_from_sec(sections, DW_Section_LocLists); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_LocLists); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_LocLists].name); + rd_indent(); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 unit_offset = cursor; + U64 unit_length = 0; + cursor += dw_based_range_read_length(base, range, cursor, &unit_length); + + U64 unit_opl = cursor + unit_length; + DW_Version version = 0; + U8 address_size = 0; + U8 segment_selector_size = 0; + U32 offset_entry_count = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &version); + cursor += dw_based_range_read_struct(base, range, cursor, &address_size); + cursor += dw_based_range_read_struct(base, range, cursor, &segment_selector_size); + cursor += dw_based_range_read_struct(base, range, cursor, &offset_entry_count); + + U64 past_header_offset = cursor; + B32 is_dwarf64 = unit_length > max_U32; + U64 offset_size = is_dwarf64 ? sizeof(U64) : sizeof(U32); + + rd_printf("Unit @ %#llx, length %llu", unit_offset, unit_length); + rd_printf("Version: %u", version); + rd_printf("Address size: %u", address_size); + rd_printf("Segment selector size: %u", segment_selector_size); + rd_printf("Offset entry count: %u", offset_entry_count); + if (version != DW_Version_5) { + rd_warningf("Version value must be 5 (DWARF5 sepc, Feb 13, 2017)"); + } + + if (offset_entry_count > 0) { + rd_printf("Offsets:"); + rd_indent(); + rd_printf("%-8s %-8s", "Index", "Offset"); + for (U64 offset_idx = 0; offset_idx < offset_entry_count; ++offset_idx) { + U64 offset = 0; + cursor += dw_based_range_read(base, range, cursor, offset_size, &offset); + rd_printf("%-8llu %llx", offset_idx, offset+past_header_offset); + } + rd_unindent(); + } + + rd_printf("Locations:"); + rd_indent(); + rd_printf("%-8s %-8s", "Offset", "Location"); + for (; cursor < unit_opl; ) { + Temp temp = temp_begin(arena); + + String8List list = {0}; + + str8_list_pushf(temp.arena, &list, "%08llx", cursor); + + U8 kind = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &kind); + str8_list_pushf(temp.arena, &list, "DW_LLE_%S", dw_string_from_loc_list_entry_kind(temp.arena, kind)); + + B32 has_loc_desc = 0; + switch (kind) { + case DW_LocListEntryKind_EndOfList: + break; + case DW_LocListEntryKind_DefaultLocation: { + has_loc_desc = 1; + } break; + case DW_LocListEntryKind_BaseAddress: { + U64 base_address = 0; + cursor += dw_based_range_read_address(base, range, cursor, segment_virtual_ranges, segment_selector_size, address_size, &base_address); + str8_list_pushf(temp.arena, &list, "%llx", base_address); + } break; + case DW_LocListEntryKind_StartLength: { + U64 start = 0; + U64 length = 0; + cursor += dw_based_range_read_address(base, range, cursor, segment_virtual_ranges, segment_selector_size, address_size, &start); + cursor += dw_based_range_read_uleb128(base, range, cursor, &length); + str8_list_pushf(temp.arena, &list, "%llx, %llx", start, length); + } break; + case DW_LocListEntryKind_StartEnd: { + U64 start = 0; + U64 end = 0; + cursor += dw_based_range_read_address(base, range, cursor, segment_virtual_ranges, segment_selector_size, address_size, &start); + cursor += dw_based_range_read_address(base, range, cursor, segment_virtual_ranges, segment_selector_size, address_size, &end); + str8_list_pushf(temp.arena, &list, "%llx, %llx", start, end); + } break; + case DW_LocListEntryKind_BaseAddressX: { + U64 base_addressx = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &base_addressx); + str8_list_pushf(temp.arena, &list, "%llx", base_addressx); + } break; + case DW_LocListEntryKind_StartXEndX: { + U64 startx = 0; + U64 endx = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &startx); + cursor += dw_based_range_read_uleb128(base, range, cursor, &endx); + str8_list_pushf(temp.arena, &list, "%llx, %llx", startx, endx); + } break; + case DW_LocListEntryKind_OffsetPair: { + U64 a = 0; + U64 b = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &a); + cursor += dw_based_range_read_uleb128(base, range, cursor, &b); + str8_list_pushf(temp.arena, &list, "%llx, %llx", a, b); + + U8 expr_length = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &expr_length); + + String8 raw_expr = str8((U8*)base+cursor, expr_length); + cursor += expr_length; + + String8 expression = dw_format_expression_single_line(temp.arena, raw_expr, address_size, arch, version, DW_Ext_Null, is_dwarf64); + str8_list_pushf(temp.arena, &list, "(%S)", expression); + } break; + case DW_LocListEntryKind_StartXLength: { + U64 startx = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &startx); + U64 length = 0; + if (version < DW_Version_5) { + // pre-standard length + cursor += dw_based_range_read(base, range, cursor, sizeof(U32), &length); + } else { + cursor += dw_based_range_read_uleb128(base, range, cursor, &length); + } + } break; + } + + String8 print = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", print); + + temp_end(temp); + } + rd_unindent(); + rd_newline(); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal void +dw_print_debug_rnglists(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_ranges) +{ + void *base = dw_base_from_sec(sections, DW_Section_RngLists); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_RngLists); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_RngLists].name); + rd_indent(); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 unit_offset = cursor; + U64 unit_length = 0; + cursor += dw_based_range_read_length(base, range, cursor, &unit_length); + U64 unit_opl = cursor + unit_length; + DW_Version version = 0; + U8 address_size = 0; + U8 segment_selector_size = 0; + U32 offset_entry_count = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &version); + cursor += dw_based_range_read_struct(base, range, cursor, &address_size); + cursor += dw_based_range_read_struct(base, range, cursor, &segment_selector_size); + cursor += dw_based_range_read_struct(base, range, cursor, &offset_entry_count); + + U64 past_header_offset = cursor; + B32 is_dwarf64 = unit_length > max_U32; + U64 offset_size = is_dwarf64 ? sizeof(U64) : sizeof(U32); + + rd_printf("Unit @ %#llx, length %llu", unit_offset, unit_length); + rd_printf("Version: %u", version); + rd_printf("Address size: %u", address_size); + rd_printf("Segment selector size: %u", segment_selector_size); + rd_printf("Offset entry count: %u", offset_entry_count); + + if (version != DW_Version_5) { + rd_warningf("Version value must be 5 (DWARF5 sepc, Feb 13, 2017)"); + } + + if (offset_entry_count > 0) { + rd_printf("Offsets:"); + rd_indent(); + rd_printf("%-8s %-8s", "Index", "Offset"); + for (U64 offset_idx = 0; offset_idx < offset_entry_count; ++offset_idx) { + U64 offset = 0; + cursor += dw_based_range_read(base, range, cursor, offset_size, &offset); + rd_printf("%-8llu %llx", offset_idx, offset+past_header_offset); + } + rd_unindent(); + } + + rd_printf("Ranges:"); + rd_indent(); + rd_printf("%-8s %-8s", "Offset", "Range"); + for (; cursor < unit_opl; ) { + Temp temp = temp_begin(scratch.arena); + + String8List list = {0}; + + // offset + str8_list_pushf(temp.arena, &list, "%08llx", cursor); + + // opcode mnemonic + U8 kind = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &kind); + str8_list_pushf(temp.arena, &list, "DW_RLE_%S", dw_string_from_rng_list_entry_kind(temp.arena, kind)); + + // operand + switch (kind) { + case DW_RngListEntryKind_EndOfList: { + // empty + } break; + case DW_RngListEntryKind_BaseAddressX: { + U64 base_addressx = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &base_addressx); + str8_list_pushf(temp.arena, &list, "%llx", base_addressx); + } break; + case DW_RngListEntryKind_BaseAddress: { + U64 base_address = 0; + cursor += dw_based_range_read_address(base, range, cursor, segment_ranges, segment_selector_size, address_size, &base_address); + str8_list_pushf(temp.arena, &list, "%llx", base_address); + } break; + case DW_RngListEntryKind_OffsetPair: { + U64 min = 0; + U64 max = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &min); + cursor += dw_based_range_read_uleb128(base, range, cursor, &max); + str8_list_pushf(temp.arena, &list, "%llx, %llx", min, max); + } break; + case DW_RngListEntryKind_StartxLength: { + U64 startx = 0; + U64 length = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &startx); + cursor += dw_based_range_read_uleb128(base, range, cursor, &length); + str8_list_pushf(temp.arena, &list, "%llx, %llx", startx, length); + } break; + case DW_RngListEntryKind_StartxEndx: { + U64 startx = 0; + U64 endx = 0; + cursor += dw_based_range_read_uleb128(base, range, cursor, &startx); + cursor += dw_based_range_read_uleb128(base, range, cursor, &endx); + str8_list_pushf(temp.arena, &list, "%llx, %llx", startx, endx); + } break; + case DW_RngListEntryKind_StartEnd: { + U64 start = 0; + U64 end = 0; + cursor += dw_based_range_read_address(base, range, cursor, segment_ranges, segment_selector_size, address_size, &start); + cursor += dw_based_range_read_address(base, range, cursor, segment_ranges, segment_selector_size, address_size, &end); + str8_list_pushf(temp.arena, &list, "%llx, %llx", start, end); + } break; + case DW_RngListEntryKind_StartLength: { + U64 start = 0; + U64 length = 0; + cursor += dw_based_range_read_address(base, range, cursor, segment_ranges, segment_selector_size, address_size, &start); + cursor += dw_based_range_read_uleb128(base, range, cursor, &length); + str8_list_pushf(temp.arena, &list, "%llx, %llx", start, length); + } break; + } + + // output row + String8 print = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", print); + + temp_end(temp); + } + rd_unindent(); + rd_newline(); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal void +dw_format_string_table(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, DW_SectionKind sec) +{ + void *base = dw_base_from_sec(sections, sec); + Rng1U64 range = dw_range_from_sec(sections, sec); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[sec].name); + rd_indent(); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 unit_offset = cursor; + + U64 unit_length = 0; + cursor += dw_based_range_read_length(base, range, cursor, &unit_length); + U64 unit_opl = cursor + unit_length; + + DW_Version version = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &version); + + if (version != DW_Version_2) { + rd_warningf("Version value must be 2"); + } + + B32 is_dwarf64 = unit_length > max_U32; + U32 sec_offset_size = is_dwarf64 ? sizeof(U64) : sizeof(U32); + + U64 debug_info_offset = 0, debug_info_length = 0; + cursor += dw_based_range_read(base, range, cursor, sec_offset_size, &debug_info_offset); + cursor += dw_based_range_read(base, range, cursor, sec_offset_size, &debug_info_length); + + rd_printf("Unit @ %#llx, length %llu", unit_offset, unit_length); + rd_printf("Version: %u", version); + rd_printf("Debug info offset: %#llx", debug_info_offset); + rd_printf("Debug info length: %#llx", debug_info_length); + + rd_printf("Entries:"); + rd_indent(); + rd_printf("%-8s %-8s", "Offset", "String"); + for (; cursor < unit_opl; ) { + U64 info_offset = 0; + cursor += dw_based_range_read(base, range, cursor, sec_offset_size, &info_offset); + String8 string = dw_based_range_read_string(base, range, cursor); + cursor += (string.size + 1); + + rd_printf("%08llx %S", info_offset, string); + } + rd_unindent(); + rd_newline(); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal void +dw_print_debug_pubnames(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + dw_format_string_table(arena, out, indent, sections, DW_Section_PubNames); +} + +internal void +dw_print_debug_pubtypes(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + dw_format_string_table(arena, out, indent, sections, DW_Section_PubTypes); +} + +internal void +dw_print_debug_line_str(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + void *base = dw_base_from_sec(sections, DW_Section_LineStr); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_LineStr); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_LineStr].name); + rd_indent(); + + rd_printf("%-8s %-8s", "Offset", "String"); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 offset = cursor; + String8 string = dw_based_range_read_string(base, range, cursor); + cursor += (string.size + 1); + rd_printf("%08llX %S", offset, string); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal void +dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +{ + void *base = dw_base_from_sec(sections, DW_Section_StrOffsets); + Rng1U64 range = dw_range_from_sec(sections, DW_Section_StrOffsets); + + void *debug_str_base = dw_base_from_sec(sections, DW_Section_Str); + Rng1U64 debug_str_range = dw_range_from_sec(sections, DW_Section_Str); + + if (dim_1u64(range) == 0) { + return; + } + + Temp scratch = scratch_begin(&arena, 1); + + rd_printf("# %S", sections->v[DW_Section_StrOffsets].name); + rd_indent(); + for (U64 cursor = 0; cursor < dim_1u64(range); ) { + U64 unit_offset = cursor; + + U64 unit_length = 0; + cursor += dw_based_range_read_length(base, range, cursor, &unit_length); + U64 unit_opl = cursor + unit_length; + + DW_Version version = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &version); + if (version != DW_Version_5) { + rd_warningf("Version value must be 5 (DWARF5 sepc, Feb 13, 2017)"); + } + + U16 padding = 0; + cursor += dw_based_range_read_struct(base, range, cursor, &padding); + if (padding != 0) { + rd_warningf("unexpected padding byte"); + } + + B32 is_dwarf64 = unit_length > max_U32; + U32 offset_size = is_dwarf64 ? sizeof(U64) : sizeof(U32); + + rd_printf("Unit @ %#llX, length %lld", unit_offset, unit_length); + rd_printf("Version: %d", version); + rd_printf("Padding: %d", padding); + rd_indent(); + rd_printf("%-8s %-8s", "@", "Offset"); + for (; cursor < unit_opl; ) { + U64 read_at = cursor; + U64 offset = 0; + cursor += dw_based_range_read(base, range, cursor, offset_size, &offset); + rd_printf("%08llx %08llx", read_at, offset); + if (dim_1u64(debug_str_range) > 0) { + String8 string = dw_based_range_read_string(debug_str_base, debug_str_range, offset); + rd_printf(" %S", string); + } + rd_newline(); + } + rd_unindent(); + rd_newline(); + } + rd_unindent(); + + scratch_end(scratch); +} + +internal void +dw_format(Arena *arena, String8List *out, String8 indent, RD_Option opts, DW_SectionArray *sections, Arch arch, ImageType image_type) +{ + Rng1U64Array segment_vranges = {0}; + + B32 relaxed = !!(opts & RD_Option_RelaxDwarfParser); + + if (opts & RD_Option_DebugInfo) { + dw_print_debug_info(arena, out, indent, sections, arch, image_type, relaxed); + } + if (opts & RD_Option_DebugAbbrev) { + dw_print_debug_abbrev(arena, out, indent, sections); + } + if (opts & RD_Option_DebugLine) { + dw_print_debug_line(arena, out, indent, sections, relaxed); + } + if (opts & RD_Option_DebugStr) { + dw_print_debug_str(arena, out, indent, sections); + } + if (opts & RD_Option_DebugLoc) { + dw_print_debug_loc(arena, out, indent, sections, arch, image_type, relaxed); + } + if (opts & RD_Option_DebugRanges) { + dw_print_debug_ranges(arena, out, indent, sections, arch, image_type, relaxed); + } + if (opts & RD_Option_DebugARanges) { + dw_print_debug_aranges(arena, out, indent, sections); + } + if (opts & RD_Option_DebugAddr) { + dw_print_debug_addr(arena, out, indent, sections); + } + if (opts & RD_Option_DebugLocLists) { + dw_print_debug_loclists(arena, out, indent, sections, segment_vranges, arch); + } + if (opts & RD_Option_DebugRngLists) { + dw_print_debug_rnglists(arena, out, indent, sections, segment_vranges); + } + if (opts & RD_Option_DebugPubNames) { + dw_print_debug_pubnames(arena, out, indent, sections); + } + if (opts & RD_Option_DebugPubTypes) { + dw_print_debug_pubtypes(arena, out, indent, sections); + } + if (opts & RD_Option_DebugLineStr) { + dw_print_debug_line_str(arena, out, indent, sections); + } + if (opts & RD_Option_DebugStrOffsets) { + dw_print_debug_str_offsets(arena, out, indent, sections); + } +} + +// CodeView + +internal void +cv_print_binary_annots(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data) { if (raw_data.size) { Temp scratch = scratch_begin(&arena, 1); @@ -263,13 +2629,13 @@ cv_format_binary_annots(Arena *arena, String8List *out, String8 indent, CV_Arch } internal void -cv_format_lvar_addr_range(Arena *arena, String8List *out, String8 indent, CV_LvarAddrRange range) +cv_print_lvar_addr_range(Arena *arena, String8List *out, String8 indent, CV_LvarAddrRange range) { rd_printf("Address Range: %04x:%08x Size: %#x", range.sec, range.off, range.len); } internal void -cv_format_lvar_addr_gap(Arena *arena, String8List *out, String8 indent, String8 raw_data) +cv_print_lvar_addr_gap(Arena *arena, String8List *out, String8 indent, String8 raw_data) { U64 count = raw_data.size / sizeof(CV_LvarAddrGap); if (count > 0) { @@ -286,7 +2652,7 @@ cv_format_lvar_addr_gap(Arena *arena, String8List *out, String8 indent, String8 } internal void -cv_format_lvar_attr(Arena *arena, String8List *out, String8 indent, CV_LocalVarAttr attr) +cv_print_lvar_attr(Arena *arena, String8List *out, String8 indent, CV_LocalVarAttr attr) { Temp scratch = scratch_begin(&arena,1); rd_printf("Address: %S", cv_string_sec_off(scratch.arena, attr.seg, attr.off)); @@ -295,7 +2661,7 @@ cv_format_lvar_attr(Arena *arena, String8List *out, String8 indent, CV_LocalVarA } internal void -cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U32 type, String8 raw_symbol) +cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV_TypeIndex min_itype, CV_SymKind type, String8 raw_symbol) { Temp scratch = scratch_begin(&arena, 1); U64 cursor = 0; @@ -307,13 +2673,13 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Parent: %x", sym.parent); - rd_printf("End: %x", sym.end); - rd_printf("Next: %x", sym.next); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Length: %u (bytes)", sym.len); - rd_printf("Ordinal: %S", cv_string_from_thunk_ordinal(sym.ord)); + rd_printf("Name: %S", name); + rd_printf("Parent: %x", sym.parent); + rd_printf("End: %x", sym.end); + rd_printf("Next: %x", sym.next); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Length: %u", sym.len); + rd_printf("Ordinal: %S", cv_string_from_thunk_ordinal(sym.ord)); } break; case CV_SymKind_FILESTATIC: { CV_SymFileStatic sym = {0}; @@ -321,7 +2687,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Flags: %S", cv_string_from_local_flags(scratch.arena, sym.flags)); } break; case CV_SymKind_CALLERS: @@ -351,7 +2717,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U for (U32 i = 0; i < sym.count; ++i) { U32 itype; cursor += str8_deserial_read_struct(raw_symbol, cursor, &itype); - rd_printf("%S", cv_string_from_itype(arena, itype)); + rd_printf("%S", cv_string_from_itype(arena, min_itype, itype)); } rd_unindent(); } break; @@ -364,7 +2730,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Parent: %#x", sym.parent); rd_printf("End: %#x", sym.end); rd_printf("Inlinee: %S", cv_string_from_itemid(arena, sym.inlinee)); - cv_format_binary_annots(arena, out, indent, arch, raw_annots); + cv_print_binary_annots(arena, out, indent, arch, raw_annots); } break; case CV_SymKind_INLINESITE2: { CV_SymInlineSite2 sym = {0}; @@ -376,7 +2742,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("End: %#x", sym.end_off); rd_printf("Inlinee: %S", cv_string_from_itemid(arena, sym.inlinee)); rd_printf("Invocations: %u", sym.invocations); - cv_format_binary_annots(arena, out, indent, arch, raw_annots); + cv_print_binary_annots(arena, out, indent, arch, raw_annots); } break; case CV_SymKind_INLINESITE_END: { // nothing to report @@ -392,7 +2758,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Name: %S", name); rd_printf("TSL Address: %S", cv_string_sec_off(scratch.arena, sym.tls_seg, sym.tls_off)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_OBJNAME: { CV_SymObjName sym = {0}; @@ -410,23 +2776,22 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); rd_printf("Parent: %x", sym.parent); rd_printf("End: %x", sym.end); rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Length: %u (bytes)", sym.len); + rd_printf("Length: %u", sym.len); + if (name.size) { + rd_printf("Name: %S", name); + } } break; case CV_SymKind_LABEL32_ST: case CV_SymKind_LABEL32: { - CV_SymLabel32 sym = {0}; - String8 name = str8_zero(); + CV_SymLabel32 sym = {0}; + String8 name = str8_zero(); cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Flags: %S", cv_string_from_proc_flags(scratch.arena, sym.flags)); + rd_printf("Address: %S, Flags: %S, Name: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off), cv_string_from_proc_flags(scratch.arena, sym.flags), name); } break; case CV_SymKind_COMPILE: { Assert(!"TODO: test"); @@ -436,10 +2801,10 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &version_string); U32 language = CV_CompileFlags_Extract_Language(sym.flags); - U32 float_prec = CV_CompileFlags_ExtractFloatPrec(sym.flags); - U32 float_pkg = CV_CompileFlags_ExtractFloatPkg(sym.flags); - U32 ambient_data = CV_CompileFlags_ExtractAmbientData(sym.flags); - U32 mode = CV_CompileFlags_ExtractMode(sym.flags); + U32 float_prec = CV_CompileFlags_Extract_FloatPrec(sym.flags); + U32 float_pkg = CV_CompileFlags_Extract_FloatPkg(sym.flags); + U32 ambient_data = CV_CompileFlags_Extract_AmbientData(sym.flags); + U32 mode = CV_CompileFlags_Extract_Mode(sym.flags); rd_printf("Arch: %S", cv_string_from_arch(sym.machine)); rd_printf("Language: %S", cv_string_from_language(language)); rd_printf("FloatPrec: %x", float_prec); @@ -495,16 +2860,16 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U String8 name = str8_zero(); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Parent: %#x", sym.parent); - rd_printf("End: %#x", sym.end); - rd_printf("Next: %#x", sym.next); - rd_printf("Length: %u (bytes)", sym.len); - rd_printf("Debug Start: %#x", sym.dbg_start); - rd_printf("Debug End: %#x", sym.dbg_end); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Flags: %S", cv_string_from_proc_flags(scratch.arena, sym.flags)); + rd_printf("Name: %S", name); + rd_printf("Parent: %#x", sym.parent); + rd_printf("End: %#x", sym.end); + rd_printf("Next: %#x", sym.next); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Length: %u", sym.len); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Flags: %S", cv_string_from_proc_flags(scratch.arena, sym.flags)); + rd_printf("Debug Start: %#x", sym.dbg_start); + rd_printf("Debug End: %#x", sym.dbg_end); } break; case CV_SymKind_LDATA32_ST: case CV_SymKind_GDATA32_ST: @@ -516,7 +2881,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); } break; case CV_SymKind_CONSTANT_ST: @@ -529,7 +2894,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Size: %S", cv_string_from_numeric(scratch.arena, size)); } break; case CV_SymKind_FRAMEPROC: { @@ -539,14 +2904,14 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U String8 flags = cv_string_from_frame_proc_flags(scratch.arena, sym.flags); U32 local_ptr = CV_FrameprocFlags_Extract_LocalBasePointer(sym.flags); U32 param_ptr = CV_FrameprocFlags_Extract_ParamBasePointer(sym.flags); - rd_printf("Frame Size: %x", sym.frame_size); - rd_printf("Pad Size: %x", sym.pad_size); - rd_printf("Pad Offset: %x", sym.pad_off); - rd_printf("Save Registers Area: %u (bytes)", sym.save_reg_size); - rd_printf("Exception Handler: %S", cv_string_sec_off(arena, sym.eh_sec, sym.eh_off)); - rd_printf("Flags: %S", flags); - rd_printf("Local pointer: %S", cv_string_from_reg_id(arch, cv_map_encoded_base_pointer(arch, local_ptr))); - rd_printf("Param pointer: %S", cv_string_from_reg_id(arch, cv_map_encoded_base_pointer(arch, param_ptr))); + rd_printf("Frame Size: %x", sym.frame_size); + rd_printf("Pad Size: %x", sym.pad_size); + rd_printf("Pad Offset: %x", sym.pad_off); + rd_printf("Save Registers Area: %u", sym.save_reg_size); + rd_printf("Exception Handler: %S", cv_string_sec_off(arena, sym.eh_sec, sym.eh_off)); + rd_printf("Flags: %S", flags); + rd_printf("Local pointer: %S", cv_string_from_reg_id(scratch.arena, arch, cv_map_encoded_base_pointer(arch, local_ptr))); + rd_printf("Param pointer: %S", cv_string_from_reg_id(scratch.arena, arch, cv_map_encoded_base_pointer(arch, param_ptr))); } break; case CV_SymKind_LOCAL: { CV_SymLocal sym = {0}; @@ -555,7 +2920,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Flags: %S", cv_string_from_local_flags(scratch.arena, sym.flags)); } break; case CV_SymKind_DEFRANGE: { @@ -565,8 +2930,8 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += raw_gaps.size; rd_printf("Program: %#x", sym.program); - cv_format_lvar_addr_range(arena, out, indent, sym.range); - cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + cv_print_lvar_addr_range(arena, out, indent, sym.range); + cv_print_lvar_addr_gap(arena, out, indent, raw_gaps); } break; case CV_SymKind_DEFRANGE_REGISTER: { CV_SymDefrangeRegister sym = {0}; @@ -574,10 +2939,10 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += raw_gaps.size; - rd_printf("Register: %S", cv_string_from_reg_id(arch, sym.reg)); + rd_printf("Register: %S", cv_string_from_reg_id(scratch.arena, arch, sym.reg)); rd_printf("Attributes: %S", cv_string_from_range_attribs(scratch.arena, sym.attribs)); - cv_format_lvar_addr_range(arena, out, indent, sym.range); - cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + cv_print_lvar_addr_range(arena, out, indent, sym.range); + cv_print_lvar_addr_gap(arena, out, indent, raw_gaps); } break; case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: { CV_SymDefrangeFramepointerRel sym = {0}; @@ -585,8 +2950,8 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); rd_printf("Offset: %#x", sym.off); - cv_format_lvar_addr_range(arena, out, indent, sym.range); - cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + cv_print_lvar_addr_range(arena, out, indent, sym.range); + cv_print_lvar_addr_gap(arena, out, indent, raw_gaps); } break; case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: { CV_SymDefrangeSubfieldRegister sym = {0}; @@ -594,11 +2959,11 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += raw_gaps.size; - rd_printf("Register: %S", cv_string_from_reg_id(arch, sym.reg)); + rd_printf("Register: %S", cv_string_from_reg_id(scratch.arena, arch, sym.reg)); rd_printf("Attributes: %S", cv_string_from_range_attribs(scratch.arena, sym.attribs)); rd_printf("Parent Offset: %#x", sym.field_offset); - cv_format_lvar_addr_range(arena, out, indent, sym.range); - cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + cv_print_lvar_addr_range(arena, out, indent, sym.range); + cv_print_lvar_addr_gap(arena, out, indent, raw_gaps); } break; case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: { CV_SymDefrangeFramepointerRelFullScope sym = {0}; @@ -613,7 +2978,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Flags: %S", cv_string_from_defrange_register_rel_flags(scratch.arena, sym.flags)); rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.reg_off)); - cv_format_lvar_addr_gap(arena, out, indent, raw_gaps); + cv_print_lvar_addr_gap(arena, out, indent, raw_gaps); } break; case CV_SymKind_END: case CV_SymKind_PROC_ID_END: { @@ -627,7 +2992,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_BUILDINFO: { CV_SymBuildInfo sym = {0}; @@ -648,17 +3013,18 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.reg_off)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Address: %S, Type: %S, Name: %S", + cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.reg_off), + cv_string_from_itype(scratch.arena, min_itype, sym.itype), + name); } break; case CV_SymKind_CALLSITEINFO: { CV_SymCallSiteInfo sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Pad: %u (bytes)", sym.pad); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Pad: %u", sym.pad); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_FRAMECOOKIE: { CV_SymFrameCookie sym = {0}; @@ -673,10 +3039,10 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); String8 addr = cv_string_sec_off(arena, sym.sec, sym.off); - String8 itype = cv_string_from_itype(arena, sym.itype); + String8 itype = cv_string_from_itype(arena, min_itype, sym.itype); rd_printf("Address: %S", addr); rd_printf("Type: %S", itype); - rd_printf("Call instruction length: %x (bytes)", sym.call_inst_len); + rd_printf("Call instruction length: %x", sym.call_inst_len); } break; case CV_SymKind_ALIGN: { // spec: @@ -716,21 +3082,15 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U CV_SymReturn sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Flags: S", cv_string_from_generic_flags(scratch.arena, sym.flags)); - rd_printf("Style: S", cv_string_from_generic_style(sym.style)); + rd_printf("Flags: %S", cv_string_from_generic_flags(scratch.arena, sym.flags)); + rd_printf("Style: %S", cv_string_from_generic_style(sym.style)); if (sym.style == CV_GenericStyle_REG) { U8 count = 0; cursor += str8_deserial_read_struct(raw_symbol, cursor, &count); + String8 data = rd_format_hex_array(scratch.arena, raw_symbol.str, raw_symbol.size); rd_printf("Byte Count: %u", count); - rd_printf("Data:"); - rd_indent(); - for (U8 i = 0; i < count; ++i) { - U8 v; - cursor += str8_deserial_read_struct(raw_symbol, cursor, &v); - rd_printf(" %02x", v); - } - rd_unindent(); + rd_printf("Data: %S", data); } } break; case CV_SymKind_ENTRYTHIS: { @@ -741,7 +3101,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &symbol_type); String8 raw_subsym = str8_skip(raw_symbol, cursor); - cv_format_symbol(arena, out, indent, arch, type, raw_subsym); + cv_print_symbol(arena, out, indent, arch, min_itype, type, raw_subsym); } break; case CV_SymKind_SLINK32: { Assert(!"ret"); @@ -762,7 +3122,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U // rest of the range is it? // // CV-spec doesn't even mention S_OEM just LF_OEM and cvdump.exe prints out type with guid... - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("ID: %S", string_from_guid(scratch.arena, sym.id)); } break; case CV_SymKind_VFTABLE32:{ @@ -771,8 +3131,8 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U CV_SymVPath32 sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Root: %S", cv_string_from_itype(scratch.arena, sym.root)); - rd_printf("Path: %S", cv_string_from_itype(scratch.arena, sym.path)); + rd_printf("Root: %S", cv_string_from_itype(scratch.arena, min_itype, sym.root)); + rd_printf("Path: %S", cv_string_from_itype(scratch.arena, min_itype, sym.path)); rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.seg, sym.off)); } break; case CV_SymKind_PUB32_ST: @@ -797,7 +3157,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Name: %S", name); rd_printf("Offset: %#x", sym.off); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_REGISTER: { Assert(!"TODO: test"); @@ -808,8 +3168,8 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Register: %S", cv_string_from_reg_id(arch, sym.reg)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Register: %S", cv_string_from_reg_id(scratch.arena, arch, sym.reg)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_PROCREF_ST: case CV_SymKind_DATAREF_ST: @@ -836,12 +3196,12 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U CV_SymSepcode sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Parent: %#x", sym.parent); - rd_printf("End: %#x", sym.end); - rd_printf("Length: %u (bytes)", sym.len); - rd_printf("Flags: %S", cv_string_from_sepcode(scratch.arena, sym.flags)); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.sec_off)); - rd_printf("Parent Address: %S", cv_string_sec_off(scratch.arena, sym.sec_parent, sym.sec_parent_off)); + rd_printf("Parent: %#x", sym.parent); + rd_printf("End: %#x", sym.end); + rd_printf("Length: %u", sym.len); + rd_printf("Flags: %S", cv_string_from_sepcode(scratch.arena, sym.flags)); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.sec_off)); + rd_printf("Parent Address: %S", cv_string_sec_off(scratch.arena, sym.sec_parent, sym.sec_parent_off)); } break; case CV_SymKind_PARAMSLOT_ST: case CV_SymKind_LOCALSLOT_ST: @@ -855,7 +3215,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Name: %S", name); rd_printf("Slot: %u", sym.slot_index); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_TRAMPOLINE: { Assert(!"TODO: test"); @@ -863,10 +3223,10 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U CV_SymTrampoline sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Type: %S", cv_string_from_trampoline_kind(sym.kind)); - rd_printf("Thunk Size: %u (bytes)", sym.thunk_size); - rd_printf("Thunk: %.*s", cv_string_sec_off(scratch.arena, sym.thunk_sec, sym.thunk_sec_off)); - rd_printf("Target: %.*s", cv_string_sec_off(scratch.arena, sym.target_sec, sym.target_sec_off)); + rd_printf("Type: %S", cv_string_from_trampoline_kind(sym.kind)); + rd_printf("Thunk Size: %u", sym.thunk_size); + rd_printf("Thunk: %.*s", cv_string_sec_off(scratch.arena, sym.thunk_sec, sym.thunk_sec_off)); + rd_printf("Target: %.*s", cv_string_sec_off(scratch.arena, sym.target_sec, sym.target_sec_off)); } break; case CV_SymKind_POGODATA: { Assert(!"TODO: test"); @@ -885,14 +3245,14 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U CV_SymManyreg sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Type: %S", cv_string_from_itype(arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(arena, min_itype, sym.itype)); rd_printf("Reg Count: %u", sym.count); rd_printf("Regs:"); rd_indent(); for (U8 i = 0; i < sym.count; ++i) { U8 v = 0; cursor += str8_deserial_read_struct(raw_symbol, cursor, &v); - rd_printf("%S", cv_string_from_reg_id(arch, v)); + rd_printf("%S", cv_string_from_reg_id(scratch.arena, arch, v)); } rd_unindent(); } break; @@ -903,14 +3263,14 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U CV_SymManyreg sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Type: %S", cv_string_from_itype(arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(arena, min_itype, sym.itype)); rd_printf("Reg Count: %u", sym.count); rd_printf("Regs:"); rd_indent(); for (U16 i = 0; i < sym.count; ++i) { U16 v = 0; cursor += str8_deserial_read_struct(raw_symbol, cursor, &v); - rd_printf("%S", cv_string_from_reg_id(arch, v)); + rd_printf("%S", cv_string_from_reg_id(scratch.arena, arch, v)); } rd_unindent(); } break; @@ -922,12 +3282,12 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Index: %u", sym.sec_index); - rd_printf("Align: %u", sym.align); - rd_printf("Virtual Offset: %#x", sym.rva); - rd_printf("Size: %u (bytes)", sym.size); - rd_printf("Characteristics: %S", coff_string_from_section_flags(scratch.arena, sym.characteristics)); + rd_printf("Name: %S", name); + rd_printf("Index: %u", sym.sec_index); + rd_printf("Align: %u", sym.align); + rd_printf("Virtual Offset: %#x", sym.rva); + rd_printf("Size: %u", sym.size); + rd_printf("Characteristics: %S", coff_string_from_section_flags(scratch.arena, sym.characteristics)); } break; case CV_SymKind_ENVBLOCK: { CV_SymEnvBlock sym = {0}; @@ -952,10 +3312,10 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Size: %u (bytes)", sym.size); - rd_printf("Characteristics: %S", coff_string_from_section_flags(scratch.arena, sym.characteristics)); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Name: %S", name); + rd_printf("Size: %u", sym.size); + rd_printf("Characteristics: %S", coff_string_from_section_flags(scratch.arena, sym.characteristics)); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); } break; case CV_SymKind_EXPORT: { Assert(!"TODO: test"); @@ -997,8 +3357,8 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Name: %S", name); rd_printf("Offset: %#x", sym.off); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); - cv_format_lvar_attr(arena, out, indent, sym.attr); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + cv_print_lvar_attr(arena, out, indent, sym.attr); } break; case CV_SymKind_MANREGISTER: case CV_SymKind_ATTR_REGISTER: { @@ -1010,9 +3370,9 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); - rd_printf("Register: %S", cv_string_from_reg_id(arch, sym.reg)); - cv_format_lvar_attr(arena, out, indent, sym.attr); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Register: %S", cv_string_from_reg_id(scratch.arena, arch, sym.reg)); + cv_print_lvar_attr(arena, out, indent, sym.attr); } break; case CV_SymKind_ATTR_REGREL: { Assert(!"TODO: test"); @@ -1023,9 +3383,9 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.off)); - cv_format_lvar_attr(arena, out, indent, sym.attr); + cv_print_lvar_attr(arena, out, indent, sym.attr); } break; case CV_SymKind_MANYREG_ST: case CV_SymKind_MANMANYREG: @@ -1040,13 +3400,13 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, sym.itype)); - cv_format_lvar_attr(arena, out, indent, sym.attr); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + cv_print_lvar_attr(arena, out, indent, sym.attr); rd_printf("Reg Count: %u", sym.count); rd_printf("Regs:"); rd_indent(); for (U8 i = 0; i < sym.count; ++i) { - rd_printf("%S", cv_string_from_reg_id(arch, regs[i])); + rd_printf("%S", cv_string_from_reg_id(scratch.arena, arch, regs[i])); } rd_unindent(); } break; @@ -1094,7 +3454,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("File ID: %x", sym.file_id); rd_printf("File Line Number: %u", sym.file_ln); rd_printf("# Discarded Symbol"); - cv_format_symbol(arena, out, indent, arch, symbol_type, raw_subsym); + cv_print_symbol(arena, out, indent, arch, min_itype, symbol_type, raw_subsym); } break; case CV_SymKind_PDBMAP: { Assert(!"TODO: test"); @@ -1117,7 +3477,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Name: %S", name); rd_printf("Flags: %x", sym.flags); - rd_printf("Type: %S", cv_string_from_itype(arena, sym.itype)); + rd_printf("Type: %S", cv_string_from_itype(arena, min_itype, sym.itype)); } break; case CV_SymKind_ARMSWITCHTABLE: { Assert(!"TODO: test"); @@ -1143,7 +3503,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U rd_printf("Flags: %x", sym.flags); rd_printf("IMod: %04x", sym.imod); if (sym.flags & CV_RefMiniPdbFlag_UDT) { - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, (CV_TypeIndex)sym.data)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, (CV_TypeIndex)sym.data)); } else { rd_printf("Coff ISect: %#x", sym.data); } @@ -1248,7 +3608,7 @@ cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U } internal U64 -cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, String8 raw_leaf) +cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_itype, CV_LeafKind kind, String8 raw_leaf) { Temp scratch = scratch_begin(&arena, 1); U64 cursor = 0; @@ -1260,7 +3620,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, CV_LeafBitField lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); rd_printf("Length: %u", lf.len); rd_printf("Position: %u", lf.pos); } break; @@ -1274,10 +3634,10 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Fields: %S", cv_string_from_itype(scratch.arena, lf.field_itype)); + rd_printf("Fields: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); - rd_printf("Derived: %S", cv_string_from_itype(scratch.arena, lf.derived_itype)); - rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, lf.vshape_itype)); + rd_printf("Derived: %S", cv_string_from_itype(scratch.arena, min_itype, lf.derived_itype)); + rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, min_itype, lf.vshape_itype)); rd_printf("Unknown1: %x", lf.unknown1); rd_printf("Unknown2: %x", lf.unknown2); if (lf.props & CV_TypeProp_HasUniqueName) { @@ -1327,27 +3687,27 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Owner Type: %S", cv_string_from_itype(scratch.arena, lf.owner_itype)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Owner Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.owner_itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_VFUNCTAB: { CV_LeafVFuncTab lf = {0}; - cursor += syms_based_range_read_struct(raw_leaf, cursor, &lf); + cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_METHODLIST: { for (; cursor < raw_leaf.size; ) { CV_LeafMethodListMember ml = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &ml); - U32 mprop = CV_FieldAttribs_Extract_MPROP(ml.attribs); + U32 mprop = CV_FieldAttribs_Extract_MethodProp(ml.attribs); B32 has_vbase = (mprop == CV_MethodProp_PureIntro) || (mprop == CV_MethodProp_Intro); U32 vbase = 0; if (has_vbase) { cursor += str8_deserial_read_struct(raw_leaf, cursor, &vbase); } rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, ml.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, ml.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, ml.itype)); if (has_vbase) { rd_printf("Virtual Base: %x", vbase); } @@ -1357,7 +3717,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, case CV_LeafKind_ONEMETHOD: { CV_LeafOneMethod lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - U32 mprop = CV_FieldAttribs_Extract_MPROP(lf.attribs); + U32 mprop = CV_FieldAttribs_Extract_MethodProp(lf.attribs); B32 has_vbase = (mprop == CV_MethodProp_PureIntro) || (mprop == CV_MethodProp_Intro); U32 vbase = 0; if (has_vbase) { @@ -1367,7 +3727,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); rd_printf("Name: %S", name); rd_printf("Field Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); if (has_vbase) { rd_printf("Virtual Base: %#x", vbase); } @@ -1381,7 +3741,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, rd_printf("Name: %S", name); rd_printf("Count: %u", lf.count); - rd_printf("Type List: %S", cv_string_from_itype(scratch.arena, lf.list_itype)); + rd_printf("Type List: %S", cv_string_from_itype(scratch.arena, min_itype, lf.list_itype)); } break; case CV_LeafKind_VBCLASS: case CV_LeafKind_IVBCLASS: { @@ -1393,8 +3753,8 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += cv_read_numeric(raw_leaf, cursor, &vbtable_off); rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Direct Base Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); - rd_printf("Virtual Base Ptr: %S", cv_string_from_itype(scratch.arena, lf.vbptr_itype)); + rd_printf("Direct Base Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); + rd_printf("Virtual Base Ptr: %S", cv_string_from_itype(scratch.arena, min_itype, lf.vbptr_itype)); rd_printf("vbpoff: %S", cv_string_from_numeric(scratch.arena, vbptr_off)); rd_printf("vbind: %S", cv_string_from_numeric(scratch.arena, vbtable_off)); } break; @@ -1405,7 +3765,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += cv_read_numeric(raw_leaf, cursor, &offset); rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); rd_printf("Offset: %S", cv_string_from_numeric(scratch.arena, offset)); } break; case CV_LeafKind_VTSHAPE: { @@ -1432,26 +3792,26 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, rd_printf("Name: %S", name); rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_MFUNCTION: { CV_LeafMFunction lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Return Type: %S", cv_string_from_itype(scratch.arena, lf.ret_itype)); - rd_printf("Class Type: %S", cv_string_from_itype(scratch.arena, lf.class_itype)); - rd_printf("This Type: %S", cv_string_from_itype(scratch.arena, lf.this_itype)); + rd_printf("Return Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.ret_itype)); + rd_printf("Class Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.class_itype)); + rd_printf("This Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.this_itype)); rd_printf("Call Kind: %S", cv_string_from_call_kind(lf.call_kind)); rd_printf("Function Attribs: %S", cv_string_from_function_attribs(scratch.arena, lf.attribs)); rd_printf("Argument Count: %u", lf.arg_count); - rd_printf("Argument Type: %S", cv_string_from_itype(scratch.arena, lf.arg_itype)); + rd_printf("Argument Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.arg_itype)); } break; #if 0 case CV_LeafKind_SKIP_16t: { CV_LeafSkip_16t lf = {0}; cursor += str8_deserial_read_struct(base, range, cursor, &lf); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.type)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.type)); } break; #endif case CV_LeafKind_SKIP: { @@ -1459,7 +3819,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, // This is used by incremental compilers to reserve space for indices. CV_LeafSkip lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_ENUM_ST: case CV_LeafKind_ENUM: { @@ -1471,8 +3831,8 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, rd_printf("Name: %S", name); rd_printf("Field Count: %u", lf.count); rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.base_itype)); - rd_printf("Field: %S", cv_string_from_itype(scratch.arena, lf.field_itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.base_itype)); + rd_printf("Field: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); if (lf.props & CV_TypeProp_HasUniqueName) { String8 unique_name = {0}; cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); @@ -1498,7 +3858,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Index: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Index: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_NOTTRAN: { // ms-symbol-pdf: @@ -1508,7 +3868,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, CV_LeafUDTSrcLine lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Type = %S, Source File = %x, Line = %u", cv_string_from_itype(scratch.arena, lf.udt_itype), lf.src_string_id, lf.line); + rd_printf("Type = %S, Source File = %x, Line = %u", cv_string_from_itype(scratch.arena, min_itype, lf.udt_itype), lf.src_string_id, lf.line); } break; case CV_LeafKind_STRING_ID: { CV_LeafStringId lf = {0}; @@ -1517,19 +3877,17 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_cstr(raw_leaf, cursor, &string); rd_printf("string: %S", string); - rd_printf("Substrings: %x", cv_string_from_itemid(arena, lf.substr_list_id)); // TODO: print actual strings instead + rd_printf("Substrings: %S", cv_string_from_itemid(arena, lf.substr_list_id)); // TODO: print actual strings instead } break; case CV_LeafKind_POINTER: { CV_LeafPointer lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - CV_PointerKind kind = CV_PointerAttribs_Extract_KIND(lf.attribs); - CV_PointerMode mode = CV_PointerAttribs_Extract_MODE(lf.attribs); + CV_PointerKind kind = CV_PointerAttribs_Extract_Kind(lf.attribs); + CV_PointerMode mode = CV_PointerAttribs_Extract_Mode(lf.attribs); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); rd_printf("Attribs: %S", cv_string_from_pointer_attribs(arena, lf.attribs)); - rd_printf("Kind: %S", cv_string_from_pointer_kind(kind)); - rd_printf("Mode: %S", cv_string_from_pointer_mode(mode)); rd_indent(); if (mode == CV_PointerMode_PtrMem) { CV_TypeIndex itype = 0; @@ -1537,7 +3895,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_struct(raw_leaf, cursor, &itype); cursor += str8_deserial_read_struct(raw_leaf, cursor, &pm); - rd_printf("Class Type: %S", cv_string_from_itype(scratch.arena, itype)); + rd_printf("Class Type: %S", cv_string_from_itype(scratch.arena, min_itype, itype)); rd_printf("Format: %S", cv_string_from_member_pointer_kind(pm)); } else { if (kind == CV_PointerKind_BaseSeg) { @@ -1551,7 +3909,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_struct(raw_leaf, cursor, &base_itype); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Base Type: %S", cv_string_from_itype(scratch.arena, base_itype)); + rd_printf("Base Type: %S", cv_string_from_itype(scratch.arena, min_itype, base_itype)); rd_printf("Name: %S", name); } } @@ -1566,11 +3924,16 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += cv_read_numeric(raw_leaf, cursor, &num); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Field Count: %u", lf.count); - rd_printf("Properties: %s", cv_string_from_type_props(scratch.arena, lf.props)); - rd_printf("Field: %S", cv_string_from_itype(scratch.arena, lf.field_itype)); - rd_printf("Size: %S (bytes)", cv_string_from_numeric(scratch.arena, num)); + rd_printf("Name: %S", name); + rd_printf("Field Count: %u", lf.count); + rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); + rd_printf("Field: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); + rd_printf("Size: %S", cv_string_from_numeric(scratch.arena, num)); + if (lf.props & CV_TypeProp_HasUniqueName) { + String8 unique_name = {0}; + cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); + rd_printf("Unique Name: %S", unique_name); + } } break; case CV_LeafKind_CLASS_ST: case CV_LeafKind_STRUCTURE_ST: @@ -1583,13 +3946,13 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += cv_read_numeric(raw_leaf, cursor, &num); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Field Count: %u", lf.count); - rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); - rd_printf("Field List Type: %S", cv_string_from_itype(scratch.arena, lf.field_itype)); - rd_printf("Derived Type: %S", cv_string_from_itype(scratch.arena, lf.derived_itype)); - rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, lf.vshape_itype)); - rd_printf("Size: %S (bytes)", cv_string_from_numeric(scratch.arena, num)); + rd_printf("Name: %S", name); + rd_printf("Field Count: %u", lf.count); + rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); + rd_printf("Field List Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); + rd_printf("Derived Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.derived_itype)); + rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, min_itype, lf.vshape_itype)); + rd_printf("Size: %S", cv_string_from_numeric(scratch.arena, num)); if (lf.props & CV_TypeProp_HasUniqueName) { String8 unique_name = {0}; cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); @@ -1606,7 +3969,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, for (U32 i = 0; i < lf.count; ++i) { U32 itype = 0; cursor += str8_deserial_read_struct(raw_leaf, cursor, &itype); - rd_printf("%S", cv_string_from_itype(scratch.arena, itype)); + rd_printf("%S", cv_string_from_itype(scratch.arena, min_itype, itype)); } rd_unindent(); } break; @@ -1617,11 +3980,11 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, String8 call_kind = cv_string_from_call_kind(lf.call_kind); String8 func_attribs = cv_string_from_function_attribs(scratch.arena, lf.attribs); - rd_printf("Return type: %S", cv_string_from_itype(scratch.arena, lf.ret_itype)); + rd_printf("Return type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.ret_itype)); rd_printf("Call Convention: %S", call_kind); rd_printf("Function Attribs: %S", func_attribs); rd_printf("Argumnet Count: %u", lf.arg_count); - rd_printf("Argument List Type: %S", cv_string_from_itype(scratch.arena, lf.arg_itype)); + rd_printf("Argument List Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.arg_itype)); } break; case CV_LeafKind_FUNC_ID: { CV_LeafFuncId lf = {0}; @@ -1630,29 +3993,26 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); rd_printf("Name: %S", name); - rd_printf("Scope Type: %S", cv_string_from_itype(scratch.arena, lf.scope_string_id)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Scope Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.scope_string_id)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_MODIFIER: { CV_LeafModifier lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); rd_printf("Flags: %S", cv_string_from_modifier_flags(scratch.arena, lf.flags)); } break; case CV_LeafKind_ARRAY_ST: case CV_LeafKind_ARRAY: { CV_LeafArray lf = {0}; CV_NumericParsed num = {0}; - String8 name = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += cv_read_numeric(raw_leaf, cursor, &num); - cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Entry type: %S", cv_string_from_itype(scratch.arena, lf.entry_itype)); - rd_printf("Index type: %S", cv_string_from_itype(scratch.arena, lf.index_itype)); + rd_printf("Entry type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.entry_itype)); + rd_printf("Index type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.index_itype)); rd_printf("Length: %S", cv_string_from_numeric(scratch.arena, num)); - rd_printf("Name: %S", name); } break; case CV_LeafKind_FIELDLIST: { for (U64 idx = 0; cursor < raw_leaf.size;) { @@ -1662,7 +4022,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, rd_printf("list[%u] = %S", idx++, cv_string_from_leaf_name(arena, member_type)); rd_indent(); - cursor += cv_format_leaf(arena, out, indent, member_type, raw_member); + cursor += cv_print_leaf(arena, out, indent, min_itype, member_type, raw_member); cursor = AlignPow2(cursor, 4); rd_unindent(); } @@ -1678,7 +4038,7 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, rd_printf("Name: %S", name); rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, lf.itype)); + rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); rd_printf("Offset: %S", cv_string_from_numeric(scratch.arena, num)); } break; // 16bit @@ -1776,70 +4136,70 @@ cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, } internal void -cv_format_debug_t(Arena *arena, String8List *out, String8 indent, CV_DebugT debug_t) +cv_print_debug_t(Arena *arena, String8List *out, String8 indent, CV_DebugT debug_t) { Temp scratch = scratch_begin(&arena, 1); for (U64 lf_idx = 0; lf_idx < debug_t.count; ++lf_idx) { - CV_Leaf lf = cv_debug_t_get_leaf(debug_t, lf_idx); - U64 offset = (U64)(lf.data.str-debug_t.v[0]); - rd_printf("%S (%#x) [%04x-%04x)", cv_string_from_leaf_kind(lf.kind), offset, offset+lf.data.size); + CV_Leaf lf = cv_debug_t_get_leaf(debug_t, lf_idx); + U64 offset = (U64)(lf.data.str-debug_t.v[0]); + CV_TypeIndex itype = CV_MinComplexTypeIndex + lf_idx; + rd_printf("LF_%S (%x) [%04llx-%04llx)", cv_string_from_leaf_kind(lf.kind), itype, offset, offset+lf.data.size); rd_indent(); - coff_format_leaf(arena, out, indent, lf.kind, lf.data); + cv_print_leaf(arena, out, indent, CV_MinComplexTypeIndex, lf.kind, lf.data); rd_unindent(); } scratch_end(scratch); } internal void -cv_format_symbols_c13(Arena *arena, String8List *out, String8 indent, String8 raw_data) +cv_print_symbols_c13(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data) { - CV_Arch arch = ~0u; + Temp scratch = scratch_begin(&arena, 1); + + B32 scope_depth = 0; for (U64 cursor = 0; cursor < raw_data.size; ) { CV_SymbolHeader header = {0}; cursor += str8_deserial_read_struct(raw_data, cursor, &header); - if (header.kind == CV_SymKind_COMPILE) { - if (header.size >= sizeof(CV_SymCompile)) { - CV_SymCompile *comp = str8_deserial_get_raw_ptr(raw_data, cursor, sizeof(*comp)); - arch = comp->machine; - } else { - rd_printf("not enough bytes to read S_COMPILE"); - } - } else if (header.kind == CV_SymKind_COMPILE2) { - if (header.size >= sizeof(CV_SymCompile2)) { - CV_SymCompile2 *comp = str8_deserial_get_raw_ptr(raw_data, cursor, sizeof(*comp)); - arch = comp->machine; - } else { - rd_printf("not enough bytes to read S_COMPILE2"); - } - } else if (header.kind == CV_SymKind_COMPILE3) { - if (header.size >= sizeof(CV_SymCompile3)) { - CV_SymCompile3 *comp = str8_deserial_get_raw_ptr(raw_data, cursor, sizeof(*comp)); - arch = comp->machine; - } else { - rd_printf("not enough bytes to read S_COMPILE3"); - } - } - if (header.size >= sizeof(header.kind)) { + Temp temp = temp_begin(scratch.arena); + U64 symbol_end = cursor + (header.size - sizeof(header.kind)); String8 raw_symbol = str8_substr(raw_data, rng_1u64(cursor, symbol_end)); - rd_printf("%S [%04x-%04x)", cv_string_from_sym_kinds(header.kind), cursor, header.size-sizeof(header.size)); + if (header.kind == CV_SymKind_END || header.kind == CV_SymKind_INLINESITE_END) { + if (scope_depth > 0) { + rd_unindent(); + --scope_depth; + } else { + rd_errorf("unbalanced scopes"); + } + } + + rd_printf("%S [%04llx-%04llx)", cv_string_from_symbol_type(temp.arena, header.kind), cursor, header.size-sizeof(header.size)); rd_indent(); - cv_format_symbol(arena, out, indent, arch, header.kind, raw_symbol); + cv_print_symbol(arena, out, indent, arch, CV_MinComplexTypeIndex, header.kind, raw_symbol); rd_unindent(); + if (header.kind == CV_SymKind_BLOCK32 || header.kind == CV_SymKind_INLINESITE) { + rd_indent(); + ++scope_depth; + } + cursor = symbol_end; + + temp_end(temp); } else { rd_errorf("symbol must be at least two bytes long"); } } + + scratch_end(scratch); } internal void -cv_format_lines_c13(Arena *arena, String8List *out, String8 indent, String8 raw_lines) +cv_print_lines_c13(Arena *arena, String8List *out, String8 indent, String8 raw_lines) { Temp scratch = scratch_begin(&arena, 1); @@ -1870,9 +4230,9 @@ cv_format_lines_c13(Arena *arena, String8List *out, String8 indent, String8 raw_ B32 always_step_in_line_number = line.off == 0xFEEFEE; B32 never_step_in_line_number = line.off == 0xF00F00; - U32 ln = CV_C13LineFlags_ExtractLineNumber(line.flags); - //U32 delta = CV_C13LineFlags_ExtractDeltaToEnd(line.flags); - //B32 is_stmt = CV_C13LineFlags_ExtractStatement(line.flags); + U32 ln = CV_C13LineFlags_Extract_LineNumber(line.flags); + //U32 delta = CV_C13LineFlags_Extract_DeltaToEnd(line.flags); + //B32 is_stmt = CV_C13LineFlags_Extract_Statement(line.flags); if (always_step_in_line_number || never_step_in_line_number) { str8_list_pushf(temp.arena, &columns, "%x %08X", ln, line.off); @@ -1900,15 +4260,14 @@ cv_format_lines_c13(Arena *arena, String8List *out, String8 indent, String8 raw_ } internal void -cv_format_file_checksums(Arena *arena, String8List *out, String8 indent, String8 raw_chksums) +cv_print_file_checksums(Arena *arena, String8List *out, String8 indent, String8 raw_chksums) { Temp scratch = scratch_begin(&arena, 1); - rd_printf("%8s %8s %8s %16s", "File", "Size", "Type", "Chksum"); + rd_printf("%-8s %-8s %-8s %-16s", "File", "Size", "Type", "Checksum"); for (U64 cursor = 0; cursor < raw_chksums.size; ) { CV_C13Checksum chksum = {0}; cursor += str8_deserial_read_struct(raw_chksums, cursor, &chksum); - cursor = AlignPow2(cursor, CV_FileCheckSumsAlign); Temp temp = temp_begin(scratch.arena); String8 chksum_str = str8_lit("???"); @@ -1917,20 +4276,23 @@ cv_format_file_checksums(Arena *arena, String8List *out, String8 indent, String8 chksum_str = rd_format_hex_array(temp.arena, chksum_ptr, chksum.len); } - rd_printf("%08x %08x %8S %S", + rd_printf("%08x %08x %-8S %S", chksum.name_off, chksum.len, cv_string_from_c13_checksum_kind(chksum.kind), chksum_str); temp_end(temp); + + cursor += chksum.len; + cursor = AlignPow2(cursor, CV_FileCheckSumsAlign); } scratch_end(scratch); } internal void -cv_format_string_table(Arena *arena, String8List *out, String8 indent, String8 raw_strtab) +cv_print_string_table(Arena *arena, String8List *out, String8 indent, String8 raw_strtab) { for (U64 cursor = 0; cursor < raw_strtab.size; ) { String8 str = {0}; @@ -1940,7 +4302,7 @@ cv_format_string_table(Arena *arena, String8List *out, String8 indent, String8 r } internal void -cv_format_inlinee_lines(Arena *arena, String8List *out, String8 indent, String8 raw_data) +cv_print_inlinee_lines(Arena *arena, String8List *out, String8 indent, String8 raw_data) { Temp scratch = scratch_begin(&arena, 1); @@ -1988,7 +4350,11 @@ cv_format_inlinee_lines(Arena *arena, String8List *out, String8 indent, String8 } internal void -cv_format_symbols_section(Arena *arena, String8List *out, String8 indent, String8 raw_ss) +cv_print_symbols_section(Arena *arena, + String8List *out, + String8 indent, + CV_Arch arch, + String8 raw_ss) { Temp scratch = scratch_begin(&arena, 1); @@ -1999,28 +4365,23 @@ cv_format_symbols_section(Arena *arena, String8List *out, String8 indent, String for (; cursor < raw_ss.size; ) { U64 sst_offset = 0; CV_C13SubSectionHeader ss_header = {0}; + char *ss_ver = "???"; switch (cv_sig) { case CV_Signature_C6: { rd_printf("TODO: C6"); } break; - case CV_Signature_C7: { rd_printf("TODO: C7"); } break; - case CV_Signature_C11: { ss_header.kind = CV_C13SubSectionKind_Symbols; ss_header.size = raw_ss.size - sizeof(cv_sig); - - rd_printf("# CodeView C11"); - rd_newline(); + ss_ver = "C11"; } break; case CV_Signature_C13: { sst_offset = cursor; cursor += str8_deserial_read_struct(raw_ss, cursor, &ss_header); - - coff_pritnf("# CodeView C13"); - rd_newline(); + ss_ver = "C13"; } break; } @@ -2028,23 +4389,28 @@ cv_format_symbols_section(Arena *arena, String8List *out, String8 indent, String String8 raw_sst = str8_substr(raw_ss, rng_1u64(cursor, sst_end)); cursor = AlignPow2(sst_end, CV_C13SubSectionAlign); - rd_printf("# %S [%llx-%llx)", cv_string_from_c13_subsection_kind(ss_header.kind), sst_offset, sst_end); + rd_printf("# %S %s [%llx-%llx)", cv_string_from_c13_subsection_kind(ss_header.kind), ss_ver, sst_offset, sst_end); rd_indent(); switch (ss_header.kind) { case CV_C13SubSectionKind_Symbols: { - cv_format_symbols_c13(arena, out, indent, raw_sst); + cv_print_symbols_c13(arena, out, indent, arch, raw_sst); + rd_newline(); } break; case CV_C13SubSectionKind_Lines: { - cv_format_lines_c13(arena, out, indent, raw_sst); + cv_print_lines_c13(arena, out, indent, raw_sst); + rd_newline(); } break; case CV_C13SubSectionKind_FileChksms: { - cv_format_file_checksums(arena, out, indent, raw_sst); + cv_print_file_checksums(arena, out, indent, raw_sst); + rd_newline(); } break; case CV_C13SubSectionKind_StringTable: { - cv_format_string_table(arena, out, indent, raw_sst); + cv_print_string_table(arena, out, indent, raw_sst); + rd_newline(); } break; case CV_C13SubSectionKind_InlineeLines: { - cv_format_inlinee_lines(arena, out, indent, raw_sst); + cv_print_inlinee_lines(arena, out, indent, raw_sst); + rd_newline(); } break; case CV_C13SubSectionKind_FrameData: case CV_C13SubSectionKind_CrossScopeImports: @@ -2066,10 +4432,96 @@ cv_format_symbols_section(Arena *arena, String8List *out, String8 indent, String scratch_end(scratch); } -//- COFF +internal void +cv_format_debug_sections(Arena *arena, String8List *out, String8 indent, String8 raw_image, U64 string_table_off, U64 section_count, COFF_SectionHeader *sections) +{ + CV_Arch arch = ~0; + { + B32 keep_parsing = 1; + for (U64 i = 0; i < section_count && keep_parsing; ++i) { + COFF_SectionHeader *header = §ions[i]; + String8 sect_name = coff_name_from_section_header(header, raw_image, string_table_off); + Rng1U64 sect_frange = rng_1u64(header->foff, header->foff+header->fsize); + String8 raw_sect = str8_substr(raw_image, sect_frange); + if (str8_match(sect_name, str8_lit(".debug$S"), 0)) { + Temp scratch = scratch_begin(&arena, 1); + CV_DebugS debug_s = cv_parse_debug_s(scratch.arena, raw_sect); + for (String8Node *string_n = debug_s.data_list[CV_C13SubSectionIdxKind_Symbols].first; + string_n != 0 && keep_parsing; string_n = string_n->next) { + Temp temp = temp_begin(scratch.arena); + CV_SymbolList symbol_list = {0}; + cv_parse_symbol_sub_section(temp.arena, &symbol_list, 0, string_n->string, CV_SymbolAlign); + for (CV_SymbolNode *symbol_n = symbol_list.first; symbol_n != 0 && keep_parsing; symbol_n = symbol_n->next) { + CV_Symbol symbol = symbol_n->data; + if (symbol.kind == CV_SymKind_COMPILE) { + if (symbol.data.size >= sizeof(CV_SymCompile)) { + CV_SymCompile *comp = str8_deserial_get_raw_ptr(symbol.data, 0, sizeof(*comp)); + arch = comp->machine; + } else { + rd_printf("not enough bytes to read S_COMPILE"); + } + keep_parsing = 0; + } else if (symbol.kind == CV_SymKind_COMPILE2) { + if (symbol.data.size >= sizeof(CV_SymCompile2)) { + CV_SymCompile2 *comp = str8_deserial_get_raw_ptr(symbol.data, 0, sizeof(*comp)); + arch = comp->machine; + } else { + rd_printf("not enough bytes to read S_COMPILE2"); + } + keep_parsing = 0; + } else if (symbol.kind == CV_SymKind_COMPILE3) { + if (symbol.data.size >= sizeof(CV_SymCompile3)) { + CV_SymCompile3 *comp = str8_deserial_get_raw_ptr(symbol.data, 0, sizeof(*comp)); + arch = comp->machine; + } else { + rd_printf("not enough bytes to read S_COMPILE3"); + } + keep_parsing = 0; + } + } + temp_end(temp); + } + scratch_end(scratch); + } + } + } + + for (U64 i = 0; i < section_count; ++i) { + COFF_SectionHeader *header = §ions[i]; + String8 sect_name = coff_name_from_section_header(header, raw_image, string_table_off); + Rng1U64 sect_frange = rng_1u64(header->foff, header->foff+header->fsize); + String8 raw_sect = str8_substr(raw_image, sect_frange); + if (str8_match(sect_name, str8_lit(".debug$S"), 0)) { + rd_printf("# .debug$S No. %llx", i+1); + rd_indent(); + cv_print_symbols_section(arena, out, indent, arch, raw_sect); + rd_unindent(); + } else if (str8_match(sect_name, str8_lit(".debug$T"), 0)) { + Temp scratch = scratch_begin(&arena, 1); + CV_Signature sig = 0; + str8_deserial_read_struct(raw_sect, 0, &sig); + + String8 raw_types = str8_skip(raw_sect, sizeof(sig)); + CV_DebugT debug_t = {0}; + if (sig == CV_Signature_C13) { + debug_t = cv_debug_t_from_data(scratch.arena, raw_types, CV_LeafAlign); + } else { + NotImplemented; + } + + rd_printf("# .debug$T No. %llx", i+1); + rd_indent(); + cv_print_debug_t(arena, out, indent, debug_t); + rd_unindent(); + scratch_end(scratch); + } + } +} + +// COFF internal void -coff_format_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ArchiveMemberHeader header, String8 long_names) +coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ArchiveMemberHeader header, String8 long_names) { Temp scratch = scratch_begin(&arena, 1); String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header.time_stamp); @@ -2085,7 +4537,7 @@ coff_format_archive_member_header(Arena *arena, String8List *out, String8 indent } internal void -coff_format_section_table(Arena *arena, +coff_print_seciton_table(Arena *arena, String8List *out, String8 indent, String8 raw_data, @@ -2287,7 +4739,7 @@ coff_disasm_sections(Arena *arena, COFF_MachineType machine, U64 image_base, B32 is_obj, - RD_MarkerArray *section_markers, + RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections) { @@ -2302,7 +4754,7 @@ coff_disasm_sections(Arena *arena, rd_printf("# Disassembly [Section No. %#llx]", (sect_idx+1)); rd_indent(); - rd_format_disasm(arena, out, indent, machine, image_base, sect_off, markers.count, markers.v, raw_code); + rd_print_disasm(arena, out, indent, machine, image_base, sect_off, markers.count, markers.v, raw_code); rd_unindent(); } } @@ -2329,7 +4781,7 @@ coff_raw_data_sections(Arena *arena, rd_printf("# Raw Data [Section No. %#llx]", (sect_idx+1)); rd_indent(); - rd_format_raw_data(arena, out, indent, 32, markers.count, markers.v, raw_sect); + rd_print_raw_data(arena, out, indent, 32, markers.count, markers.v, raw_sect); rd_unindent(); rd_newline(); } @@ -2338,7 +4790,7 @@ coff_raw_data_sections(Arena *arena, } internal void -coff_format_relocs(Arena *arena, +coff_print_relocs(Arena *arena, String8List *out, String8 indent, String8 raw_data, @@ -2416,7 +4868,7 @@ coff_format_relocs(Arena *arena, } internal void -coff_format_symbol_table(Arena *arena, +coff_print_symbol_table(Arena *arena, String8List *out, String8 indent, String8 raw_data, @@ -2516,7 +4968,7 @@ coff_format_symbol_table(Arena *arena, } internal void -coff_format_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_HeaderBigObj *header) +coff_print_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_HeaderBigObj *header) { Temp scratch = scratch_begin(&arena, 1); @@ -2538,7 +4990,7 @@ coff_format_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_ } internal void -coff_format_header(Arena *arena, String8List *out, String8 indent, COFF_Header *header) +coff_print_header(Arena *arena, String8List *out, String8 indent, COFF_Header *header) { Temp scratch = scratch_begin(&arena, 1); @@ -2561,7 +5013,7 @@ coff_format_header(Arena *arena, String8List *out, String8 indent, COFF_Header * } internal void -coff_format_import(Arena *arena, String8List *out, String8 indent, COFF_ImportHeader *header) +coff_print_import(Arena *arena, String8List *out, String8 indent, COFF_ImportHeader *header) { Temp scratch = scratch_begin(&arena, 1); @@ -2585,7 +5037,7 @@ coff_format_import(Arena *arena, String8List *out, String8 indent, COFF_ImportHe } internal void -coff_format_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts) +coff_print_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts) { Temp scratch = scratch_begin(&arena, 1); @@ -2595,7 +5047,7 @@ coff_format_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_ COFF_Symbol32Array symbols = coff_symbol_array_from_data_32(scratch.arena, raw_data, big_obj->symbol_table_foff, big_obj->symbol_count); if (opts & RD_Option_Headers) { - coff_format_big_obj_header(arena, out, indent, big_obj); + coff_print_big_obj_header(arena, out, indent, big_obj); rd_newline(); } @@ -2619,17 +5071,17 @@ coff_format_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_ } } - coff_format_section_table(arena, out, indent, raw_data, string_table_off, symbols, big_obj->section_count, sections); + coff_print_seciton_table(arena, out, indent, raw_data, string_table_off, symbols, big_obj->section_count, sections); rd_newline(); } if (opts & RD_Option_Relocs) { - coff_format_relocs(arena, out, indent, raw_data, string_table_off, big_obj->machine, big_obj->section_count, sections, symbols); + coff_print_relocs(arena, out, indent, raw_data, string_table_off, big_obj->machine, big_obj->section_count, sections, symbols); rd_newline(); } if (opts & RD_Option_Symbols) { - coff_format_symbol_table(arena, out, indent, raw_data, string_table_off, 1, symbols); + coff_print_symbol_table(arena, out, indent, raw_data, string_table_off, 1, symbols); rd_newline(); } @@ -2638,7 +5090,7 @@ exit:; } internal void -coff_format_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts) +coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts) { Temp scratch = scratch_begin(&arena, 1); @@ -2646,9 +5098,10 @@ coff_format_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data COFF_SectionHeader *sections = (COFF_SectionHeader *)(header+1); U64 string_table_off = header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count; COFF_Symbol32Array symbols = coff_symbol_array_from_data_16(scratch.arena, raw_data, header->symbol_table_foff, header->symbol_count); + Arch arch = arch_from_coff_machine(header->machine); if (opts & RD_Option_Headers) { - coff_format_header(arena, out, indent, header); + coff_print_header(arena, out, indent, header); rd_newline(); } @@ -2672,17 +5125,17 @@ coff_format_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data } } - coff_format_section_table(arena, out, indent, raw_data, string_table_off, symbols, header->section_count, sections); + coff_print_seciton_table(arena, out, indent, raw_data, string_table_off, symbols, header->section_count, sections); rd_newline(); } if (opts & RD_Option_Relocs) { - coff_format_relocs(arena, out, indent, raw_data, string_table_off, header->machine, header->section_count, sections, symbols); + coff_print_relocs(arena, out, indent, raw_data, string_table_off, header->machine, header->section_count, sections, symbols); rd_newline(); } if (opts & RD_Option_Symbols) { - coff_format_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); + coff_print_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); rd_newline(); } @@ -2700,12 +5153,21 @@ coff_format_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data rd_newline(); } + if (opts & RD_Option_Codeview) { + cv_format_debug_sections(arena, out, indent, raw_data, string_table_off, header->section_count, sections); + } + + if (opts & RD_Option_Dwarf) { + DW_SectionArray dwarf_sections = rd_dw_sections_from_coff_section_table(scratch.arena, raw_data, string_table_off, header->section_count, sections); + dw_format(arena, out, indent, opts, &dwarf_sections, arch, Image_COFF_PE); + } + exit:; scratch_end(scratch); } internal void -coff_format_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts) +coff_print_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts) { Temp scratch = scratch_begin(&arena, 1); @@ -2829,23 +5291,23 @@ coff_format_archive(Arena *arena, String8List *out, String8 indent, String8 raw_ rd_indent(); if (opts & RD_Option_Headers) { - coff_format_archive_member_header(arena, out, indent, member.header, archive_parse.long_names); + coff_print_archive_member_header(arena, out, indent, member.header, archive_parse.long_names); rd_newline(); } switch (member_type) { case COFF_DataType_BIG_OBJ: { - coff_format_big_obj(arena, out, indent, member.data, opts); + coff_print_big_obj(arena, out, indent, member.data, opts); } break; case COFF_DataType_OBJ: { - coff_format_obj(arena, out, indent, member.data, opts); + coff_print_obj(arena, out, indent, member.data, opts); } break; case COFF_DataType_IMPORT: { if (opts & RD_Option_Headers) { COFF_ImportHeader header = {0}; U64 parse_size = coff_parse_archive_import(member.data, 0, &header); if (parse_size) { - coff_format_import(arena, out, indent, &header); + coff_print_import(arena, out, indent, &header); } else { rd_errorf("not enough bytes to parse import header"); } @@ -2865,25 +5327,27 @@ coff_format_archive(Arena *arena, String8List *out, String8 indent, String8 raw_ scratch_end(scratch); } -//- MSVC CRT +// MSVC CRT internal void -mscrt_format_eh_handler_type32(Arena *arena, String8List *out, String8 indent, MSCRT_EhHandlerType32 *handler) +mscrt_print_eh_handler_type32(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, MSCRT_EhHandlerType32 *handler) { - String8 catch_line = str8_zero(); // TODO: syms_line_for_voff(scratch.arena, group, handler->catch_handler_voff); - String8 adjectives_str = mscrt_string_from_eh_adjectives(arena, handler->adjectives); - rd_printf("Adjectives: %S", adjectives_str, handler->adjectives); - rd_printf("Descriptor: %#x", handler->descriptor_voff); - rd_printf("Catch Object Frame Offset: %#x", handler->catch_obj_frame_offset); - rd_printf("Catch Handler: %#x %S", handler->catch_handler_voff, catch_line); - rd_printf("Delta to FP Handler: %#x", handler->fp_distance); + Temp scratch = scratch_begin(&arena, 1); + String8 catch_line = rd_format_line_from_voff(scratch.arena, rdi, handler->catch_handler_voff, PathStyle_WindowsAbsolute); + String8 adjectives_str = mscrt_string_from_eh_adjectives(scratch.arena, handler->adjectives); + rd_printf("Adjectives: %S", adjectives_str, handler->adjectives); + rd_printf("Descriptor: %#x", handler->descriptor_voff); + rd_printf("Catch Object Frame Offset: %#x", handler->catch_obj_frame_offset); + rd_printf("Catch Handler: %#x%s%S", handler->catch_handler_voff, catch_line.size ? " " : "", catch_line); + rd_printf("Delta to FP Handler: %#x", handler->fp_distance); + scratch_end(scratch); } //////////////////////////////// //~ PE internal void -pe_format_data_directory_ranges(Arena *arena, String8List *out, String8 indent, U64 count, PE_DataDirectory *dirs) +pe_print_data_directory_ranges(Arena *arena, String8List *out, String8 indent, U64 count, PE_DataDirectory *dirs) { Temp scratch = scratch_begin(&arena, 1); rd_printf("# Data Directories"); @@ -2895,14 +5359,14 @@ pe_format_data_directory_ranges(Arena *arena, String8List *out, String8 indent, } else { dir_name = push_str8f(scratch.arena, "%#x", i); } - rd_printf("%-16S [%08x-%08x)", dir_name, dirs[i].virt_off, dirs[i].virt_off+dirs[i].virt_size); + rd_printf("%-16S [%08x-%08x) %m", dir_name, dirs[i].virt_off, dirs[i].virt_off+dirs[i].virt_size, dirs[i].virt_size); } rd_unindent(); scratch_end(scratch); } internal void -pe_format_optional_header32(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32 *opt_header, PE_DataDirectory *dirs) +pe_print_optional_header32(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32 *opt_header, PE_DataDirectory *dirs) { Temp scratch = scratch_begin(&arena, 1); String8 subsystem = pe_string_from_subsystem(opt_header->subsystem); @@ -2938,7 +5402,7 @@ pe_format_optional_header32(Arena *arena, String8List *out, String8 indent, PE_O rd_printf("RVA and offset count: %u", opt_header->data_dir_count); rd_newline(); - pe_format_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); + pe_print_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); rd_newline(); rd_unindent(); @@ -2946,7 +5410,7 @@ pe_format_optional_header32(Arena *arena, String8List *out, String8 indent, PE_O } internal void -pe_format_optional_header32plus(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32Plus *opt_header, PE_DataDirectory *dirs) +pe_print_optional_header32plus(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32Plus *opt_header, PE_DataDirectory *dirs) { Temp scratch = scratch_begin(&arena, 1); String8 subsystem = pe_string_from_subsystem(opt_header->subsystem); @@ -2981,7 +5445,7 @@ pe_format_optional_header32plus(Arena *arena, String8List *out, String8 indent, rd_printf("RVA and offset count: %u", opt_header->data_dir_count); rd_newline(); - pe_format_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); + pe_print_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); rd_newline(); rd_unindent(); @@ -2989,7 +5453,7 @@ pe_format_optional_header32plus(Arena *arena, String8List *out, String8 indent, } internal void -pe_format_load_config32(Arena *arena, String8List *out, String8 indent, PE_LoadConfig32 *lc) +pe_print_load_config32(Arena *arena, String8List *out, String8 indent, PE_LoadConfig32 *lc) { Temp scratch = scratch_begin(&arena, 1); @@ -3073,7 +5537,7 @@ exit:; } internal void -pe_format_load_config64(Arena *arena, String8List *out, String8 indent, PE_LoadConfig64 *lc) +pe_print_load_config64(Arena *arena, String8List *out, String8 indent, PE_LoadConfig64 *lc) { Temp scratch = scratch_begin(&arena, 1); @@ -3157,7 +5621,7 @@ exit:; } internal void -pe_format_tls(Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls) +pe_print_tls(Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls) { Temp scratch = scratch_begin(&arena, 1); @@ -3189,7 +5653,7 @@ pe_format_tls(Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls) } internal void -pe_format_debug_directory(Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir) +pe_print_debug_diretory(Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir) { Temp scratch = scratch_begin(&arena, 1); @@ -3364,7 +5828,7 @@ pe_format_debug_directory(Arena *arena, String8List *out, String8 indent, String } internal void -pe_format_export_table(Arena *arena, String8List *out, String8 indent, PE_ParsedExportTable exptab) +pe_print_export_table(Arena *arena, String8List *out, String8 indent, PE_ParsedExportTable exptab) { Temp scratch = scratch_begin(&arena, 1); @@ -3395,7 +5859,7 @@ pe_format_export_table(Arena *arena, String8List *out, String8 indent, PE_Parsed } internal void -pe_format_static_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedStaticImportTable imptab) +pe_print_static_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedStaticImportTable imptab) { Temp scratch = scratch_begin(&arena, 1); @@ -3432,7 +5896,7 @@ pe_format_static_import_table(Arena *arena, String8List *out, String8 indent, U6 } internal void -pe_format_delay_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedDelayImportTable imptab) +pe_print_delay_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedDelayImportTable imptab) { if (imptab.count) { Temp scratch = scratch_begin(&arena, 1); @@ -3485,7 +5949,7 @@ pe_format_delay_import_table(Arena *arena, String8List *out, String8 indent, U64 } internal void -pe_format_resources(Arena *arena, String8List *out, String8 indent, PE_ResourceDir *root) +pe_print_resources(Arena *arena, String8List *out, String8 indent, PE_ResourceDir *root) { Temp scratch = scratch_begin(&arena, 1); @@ -3618,13 +6082,14 @@ pe_format_resources(Arena *arena, String8List *out, String8 indent, PE_ResourceD } internal void -pe_format_exceptions_x8664(Arena *arena, +pe_print_exceptions_x8664(Arena *arena, String8List *out, String8 indent, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, - Rng1U64 except_frange) + Rng1U64 except_frange, + RDI_Parsed *rdi) { Temp scratch = scratch_begin(&arena, 1); @@ -3635,9 +6100,11 @@ pe_format_exceptions_x8664(Arena *arena, U64 pdata_offset = i * sizeof(PE_IntelPdata); PE_IntelPdata *pdata = str8_deserial_get_raw_ptr(raw_except, pdata_offset, sizeof(*pdata)); + String8 pdata_name = rd_proc_name_from_voff(rdi, pdata->voff_first); - String8 pdata_name = str8_zero(); // TODO: syms_name_for_voff(arena, group, thunk_accel, thunk_table_set, pdata.voff_first); - + if (pdata->voff_first == 0x0020cf44) { + int x = 0; + } U64 unwind_info_offset = coff_foff_from_voff(sections, section_count, pdata->voff_unwind_info); PE_UnwindInfo *uwinfo = str8_deserial_get_raw_ptr(raw_data, unwind_info_offset, sizeof(*uwinfo)); @@ -3801,8 +6268,7 @@ pe_format_exceptions_x8664(Arena *arena, U32 handler = 0; read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &handler); - String8 handler_name = str8_zero(); // TODO: syms_name_for_voff(scratch.arena, group, thunk_accel, thunk_table_set, handler); - + String8 handler_name = rd_proc_name_from_voff(rdi, handler); rd_printf("Handler: %#llx%s%S", handler, handler_name.size ? " " : "", handler_name); U32 handler_data_flags = 0; @@ -3842,7 +6308,7 @@ pe_format_exceptions_x8664(Arena *arena, rd_printf("%8s %8s", "State", "IP"); for (U32 i = 0; i < func_info.ip_map_count; ++i) { MSCRT_IPState32 state = func_info.ip_map[i]; - String8 line = str8_zero(); // TODO: syms_line_for_voff(temp.arena, group, state.ip); + String8 line = rd_format_line_from_voff(scratch.arena, rdi, state.ip, PathStyle_WindowsAbsolute); rd_printf("%8d %08x %S", state.state, state.ip, line); } rd_unindent(); @@ -3854,7 +6320,7 @@ pe_format_exceptions_x8664(Arena *arena, rd_printf("%13s %10s %8s", "Current State", "Next State", "Action @"); for (U32 i = 0; i < func_info.max_state; ++i) { MSCRT_UnwindMap32 map = func_info.unwind_map[i]; - String8 line = str8_zero(); // TODO: syms_line_for_voff(temp.arena, group, map.action_virt_off); + String8 line = rd_format_line_from_voff(scratch.arena, rdi, map.action_virt_off, PathStyle_WindowsAbsolute); rd_printf("%13u %10d %8x %S", i, map.next_state, map.action_virt_off, line); } rd_unindent(); @@ -3873,7 +6339,7 @@ pe_format_exceptions_x8664(Arena *arena, for (U32 ihandler = 0; ihandler < try_block.catch_handlers_count; ++ihandler) { rd_printf("Catch #%u", ihandler); rd_indent(); - mscrt_format_eh_handler_type32(arena, out, indent, &try_block.catch_handlers[ihandler]); + mscrt_print_eh_handler_type32(arena, out, indent, rdi, &try_block.catch_handlers[ihandler]); rd_unindent(); } rd_unindent(); @@ -3887,19 +6353,17 @@ pe_format_exceptions_x8664(Arena *arena, if (i > 0) { rd_newline(); } - mscrt_format_eh_handler_type32(arena, out, indent, &func_info.es_type_list.handlers[i]); + mscrt_print_eh_handler_type32(arena, out, indent, rdi, &func_info.es_type_list.handlers[i]); } rd_unindent(); } } if (handler_data_flags & ExceptionHandlerDataFlag_FuncInfo4) { - U32 handler_data_voff = 0; - read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &handler_data_voff); - - U32 unknown = 0; + U32 func_info_voff = 0, unknown = 0; + read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &func_info_voff); read_cursor += str8_deserial_read_struct(raw_data, read_cursor, &unknown); - U64 func_info_foff = coff_foff_from_voff(sections, section_count, handler_data_voff); + U64 func_info_foff = coff_foff_from_voff(sections, section_count, func_info_voff); MSCRT_ParsedFuncInfoV4 func_info = {0}; mscrt_parse_func_info_v4(arena, raw_data, section_count, sections, func_info_foff, pdata->voff_first, &func_info); @@ -3907,27 +6371,27 @@ pe_format_exceptions_x8664(Arena *arena, { String8List header_list = {0}; if (func_info.header & MSCRT_FuncInfoV4Flag_IsCatch) { - str8_list_pushf(arena, &header_list, "IsCatch"); + str8_list_pushf(scratch.arena, &header_list, "IsCatch"); } if (func_info.header & MSCRT_FuncInfoV4Flag_IsSeparated) { - str8_list_pushf(arena, &header_list, "IsSeparted"); + str8_list_pushf(scratch.arena, &header_list, "IsSeparted"); } if (func_info.header & MSCRT_FuncInfoV4Flag_IsBBT) { - str8_list_pushf(arena, &header_list, "IsBBT"); + str8_list_pushf(scratch.arena, &header_list, "IsBBT"); } if (func_info.header & MSCRT_FuncInfoV4Flag_UnwindMap) { - str8_list_pushf(arena, &header_list, "UnwindMap"); + str8_list_pushf(scratch.arena, &header_list, "UnwindMap"); } if (func_info.header & MSCRT_FuncInfoV4Flag_TryBlockMap) { - str8_list_pushf(arena, &header_list, "TryBlockMap"); + str8_list_pushf(scratch.arena, &header_list, "TryBlockMap"); } if (func_info.header & MSCRT_FuncInfoV4Flag_EHs) { - str8_list_pushf(arena, &header_list, "EHs"); + str8_list_pushf(scratch.arena, &header_list, "EHs"); } if (func_info.header & MSCRT_FuncInfoV4Flag_NoExcept) { - str8_list_pushf(arena, &header_list, "NoExcept"); + str8_list_pushf(scratch.arena, &header_list, "NoExcept"); } - header_str = str8_list_join(arena, &header_list, &(StringJoin){.sep=str8_lit(", ")}); + header_str = str8_list_join(scratch.arena, &header_list, &(StringJoin){.sep=str8_lit(", ")}); } rd_printf("Function Info V4:"); @@ -3940,7 +6404,7 @@ pe_format_exceptions_x8664(Arena *arena, rd_indent(); rd_printf("%8s %8s", "State", "IP"); for (U32 i = 0; i < ip2state_map.count; ++i) { - String8 line_str = str8_zero(); // TODO: syms_line_for_voff(arena, group, ip2state_map.voffs[i]); + String8 line_str = rd_format_line_from_voff(scratch.arena, rdi, ip2state_map.voffs[i], PathStyle_WindowsAbsolute); rd_printf("%8d %08X %S", ip2state_map.states[i], ip2state_map.voffs[i], line_str); } rd_unindent(); @@ -4074,25 +6538,25 @@ pe_format_exceptions_x8664(Arena *arena, } internal void -pe_format_exceptions(Arena *arena, +pe_print_exceptions(Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, - Rng1U64 except_frange) + Rng1U64 except_frange, + RDI_Parsed *rdi) { if (dim_1u64(except_frange)) { rd_printf("# Exceptions"); rd_indent(); rd_printf("%-8s %-8s %-8s %-8s", "Offset", "Begin", "End", "Unwind Info"); - switch (machine) { case COFF_MachineType_UNKNOWN: break; case COFF_MachineType_X64: case COFF_MachineType_X86: { - pe_format_exceptions_x8664(arena, out, indent, section_count, sections, raw_data, except_frange); + pe_print_exceptions_x8664(arena, out, indent, section_count, sections, raw_data, except_frange, rdi); } break; default: NotImplemented; break; } @@ -4102,7 +6566,7 @@ pe_format_exceptions(Arena *arena, } internal void -pe_format_base_relocs(Arena *arena, +pe_print_base_relocs(Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, @@ -4110,7 +6574,8 @@ pe_format_base_relocs(Arena *arena, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, - Rng1U64 base_reloc_franges) + Rng1U64 base_reloc_franges, + RDI_Parsed *rdi) { Temp scratch = scratch_begin(&arena, 1); @@ -4172,21 +6637,9 @@ pe_format_base_relocs(Arena *arena, if (type == PE_BaseRelocKind_ABSOLUTE) { rd_printf("%-4x %-12s", offset, type_str); } else { - rd_printf("%-4x %-12s %016llx", offset, type_str, apply_to); - - // TODO - #if 0 - U64 reloc_voff = apply_to - image_base; - SYMS_UnitID uid = syms_group_uid_from_voff__accelerated(group, reloc_voff); - SYMS_SymbolID sid = syms_group_proc_sid_from_uid_voff__accelerated(group, uid, reloc_voff); - if (sid) { - SYMS_UnitAccel *unit = syms_group_unit_from_uid(group, uid); - String8 name = syms_group_symbol_name_from_sid(arena, group, unit, sid); - str8_list_pushf(arena, list, " %-4X %-12s %016llX %.*s", offset, type_str, apply_to, syms_expand_string(name)); - } else { - str8_list_pushf(arena, list, " %-4X %-12s %016llX", offset, type_str, apply_to); - } - #endif + U64 reloc_voff = apply_to - image_base; + String8 name = rd_format_proc_line(scratch.arena, rdi, reloc_voff); + rd_printf("%-4x %-12s %016llx%s%S", offset, type_str, apply_to, name.size ? " " : "", name); } } rd_unindent(); @@ -4200,7 +6653,7 @@ pe_format_base_relocs(Arena *arena, } internal void -pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts) +pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts, RDI_Parsed *rdi) { Temp scratch = scratch_begin(&arena, 1); @@ -4258,10 +6711,11 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O str8_deserial_read_array(raw_data, opt_header_off, raw_opt_header, coff_header->optional_header_size); if (opts & RD_Option_Headers) { - coff_format_header(arena, out, indent, coff_header); + coff_print_header(arena, out, indent, coff_header); rd_newline(); } + Arch arch = arch_from_coff_machine(coff_header->machine); U64 image_base = 0; U64 dir_count = 0; PE_DataDirectory *dirs = 0; @@ -4277,7 +6731,7 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O } if (opts & RD_Option_Headers) { - pe_format_optional_header32(arena, out, indent, opt_header, dirs); + pe_print_optional_header32(arena, out, indent, opt_header, dirs); } } else if (opt_header_magic == PE_PE32PLUS_MAGIC) { PE_OptionalHeader32Plus *opt_header = (PE_OptionalHeader32Plus *)raw_opt_header; @@ -4290,7 +6744,7 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O } if (opts & RD_Option_Headers) { - pe_format_optional_header32plus(arena, out, indent, opt_header, dirs); + pe_print_optional_header32plus(arena, out, indent, opt_header, dirs); } } @@ -4305,15 +6759,15 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O } if (opts & RD_Option_Sections) { - coff_format_section_table(arena, out, indent, raw_data, string_table_off, symbols, coff_header->section_count, sections); + coff_print_seciton_table(arena, out, indent, raw_data, string_table_off, symbols, coff_header->section_count, sections); } if (opts & RD_Option_Relocs) { - coff_format_relocs(arena, out, indent, raw_data, string_table_off, coff_header->machine, coff_header->section_count, sections, symbols); + coff_print_relocs(arena, out, indent, raw_data, string_table_off, coff_header->machine, coff_header->section_count, sections, symbols); } if (opts & RD_Option_Symbols) { - coff_format_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); + coff_print_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); } if (opts & RD_Option_Exports) { @@ -4323,41 +6777,42 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O raw_data, dirs_file_ranges[PE_DataDirectoryIndex_EXPORT], dirs_virt_ranges[PE_DataDirectoryIndex_EXPORT]); + pe_print_export_table(arena, out, indent, exptab); } if (opts & RD_Option_Imports) { B32 is_pe32 = opt_header_magic == PE_PE32_MAGIC; PE_ParsedStaticImportTable static_imptab = pe_static_imports_from_data(arena, is_pe32, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_IMPORT]); PE_ParsedDelayImportTable delay_imptab = pe_delay_imports_from_data(arena, is_pe32, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_DELAY_IMPORT]); - pe_format_static_import_table(arena, out, indent, image_base, static_imptab); - pe_format_delay_import_table(arena, out, indent, image_base, delay_imptab); + pe_print_static_import_table(arena, out, indent, image_base, static_imptab); + pe_print_delay_import_table(arena, out, indent, image_base, delay_imptab); } if (opts & RD_Option_Resources) { String8 raw_dir = str8_substr(raw_data, dirs_file_ranges[PE_DataDirectoryIndex_RESOURCES]); PE_ResourceDir *dir_root = pe_resource_table_from_directory_data(scratch.arena, raw_dir); - pe_format_resources(arena, out, indent, dir_root); + pe_print_resources(arena, out, indent, dir_root); } if (opts & RD_Option_Exceptions) { - pe_format_exceptions(arena, out, indent, coff_header->machine, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_EXCEPTIONS]); + pe_print_exceptions(arena, out, indent, coff_header->machine, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_EXCEPTIONS], rdi); } if (opts & RD_Option_Relocs) { - pe_format_base_relocs(arena, out, indent, coff_header->machine, image_base, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_BASE_RELOC]); + pe_print_base_relocs(arena, out, indent, coff_header->machine, image_base, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_BASE_RELOC], rdi); } if (opts & RD_Option_Debug) { if (PE_DataDirectoryIndex_DEBUG < dir_count) { String8 raw_dir = str8_substr(raw_data, dirs_file_ranges[PE_DataDirectoryIndex_DEBUG]); - pe_format_debug_directory(arena, out, indent, raw_data, raw_dir); + pe_print_debug_diretory(arena, out, indent, raw_data, raw_dir); } } if (opts & RD_Option_Tls) { if (dim_1u64(dirs_file_ranges[PE_DataDirectoryIndex_TLS])) { PE_ParsedTLS tls = pe_tls_from_data(scratch.arena, coff_header->machine, image_base, coff_header->section_count, sections, raw_data, dirs_file_ranges[PE_DataDirectoryIndex_TLS]); - pe_format_tls(arena, out, indent, tls); + pe_print_tls(arena, out, indent, tls); } } @@ -4369,7 +6824,7 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O case COFF_MachineType_X86: { PE_LoadConfig32 *lc = str8_deserial_get_raw_ptr(raw_lc, 0, sizeof(*lc)); if (lc) { - pe_format_load_config32(arena, out, indent, lc); + pe_print_load_config32(arena, out, indent, lc); } else { rd_errorf("not enough bytes to parse 32bit load config"); } @@ -4377,7 +6832,7 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O case COFF_MachineType_X64: { PE_LoadConfig64 *lc = str8_deserial_get_raw_ptr(raw_lc, 0, sizeof(*lc)); if (lc) { - pe_format_load_config64(arena, out, indent, lc); + pe_print_load_config64(arena, out, indent, lc); } else { rd_errorf("not enough bytes to parse 64bit load config"); } @@ -4400,49 +6855,12 @@ pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_O coff_disasm_sections(arena, out, indent, raw_data, coff_header->machine, 0, 1, section_markers, coff_header->section_count, sections); } + if (opts & RD_Option_Dwarf) { + DW_SectionArray dwarf_sections = rd_dw_sections_from_coff_section_table(scratch.arena, raw_data, string_table_off, coff_header->section_count, sections); + dw_format(arena, out, indent, opts, &dwarf_sections, arch, Image_COFF_PE); + } + exit:; scratch_end(scratch); } -internal B32 -is_pe(String8 raw_data) -{ - PE_DosHeader header = {0}; - str8_deserial_read_struct(raw_data, 0, &header); - return header.magic == PE_DOS_MAGIC; -} - -internal void -format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data) -{ - Temp scratch = scratch_begin(&arena, 1); - - char *input_type_string = "???"; - - if (coff_is_archive(raw_data)) { - input_type_string = "Archive"; - } else if (coff_is_thin_archive(raw_data)) { - input_type_string = "Thin Archive"; - } else if (coff_is_big_obj(raw_data)) { - input_type_string = "Big Obj"; - } else if (coff_is_obj(raw_data)) { - input_type_string = "Obj"; - } else if (is_pe(raw_data)) { - input_type_string = "COFF/PE"; - } - - DateTime universal_dt = os_now_universal_time(); - DateTime local_dt = os_local_time_from_universal(&universal_dt); - String8 time = push_date_time_string(scratch.arena, &local_dt); - - rd_printf("# Input"); - rd_indent(); - rd_printf("Path: %S", input_path); - rd_printf("Type: %s", input_type_string); - rd_printf("Time: %S", time); - rd_unindent(); - rd_newline(); - - scratch_end(scratch); -} - diff --git a/src/raddump/raddump.h b/src/raddump/raddump.h index c835f576..90738f38 100644 --- a/src/raddump/raddump.h +++ b/src/raddump/raddump.h @@ -9,31 +9,63 @@ #define rd_printf(f, ...) str8_list_pushf(arena, out, "%S" f, indent, __VA_ARGS__) #define rd_newline() str8_list_pushf(arena, out, ""); -#define rd_errorf(f, ...) rd_printf("ERROR: "f, __VA_ARGS__) +#define rd_errorf(f, ...) rd_stderr("ERROR: "f, __VA_ARGS__) +#define rd_warningf(f, ...) rd_stderr("WARNING: "f, __VA_ARGS__) #define rd_indent() do { if (indent.size + RD_INDENT_WIDTH <= RD_INDENT_MAX) { indent.size += RD_INDENT_WIDTH; } else { Assert(!"indent overflow"); } } while (0) -#define rd_unindent() do { if (indent.size >= RD_INDENT_WIDTH) { indent.size -= RD_INDENT_WIDTH; } else { Assert(!"unbalanced indent"); } } while (0) +#define rd_unindent() do { if (indent.size >= RD_INDENT_WIDTH) { indent.size -= RD_INDENT_WIDTH; } else { Assert(!"unbalanced indent"); } } while (0) typedef U64 RD_Option; -enum RD_OptionEnum -{ - RD_Option_Help = (1 << 0), - RD_Option_Version = (1 << 1), - RD_Option_Headers = (1 << 2), - RD_Option_Sections = (1 << 3), - RD_Option_Debug = (1 << 4), - RD_Option_Imports = (1 << 5), - RD_Option_Exports = (1 << 6), - RD_Option_Disasm = (1 << 7), - RD_Option_Rawdata = (1 << 8), - RD_Option_Tls = (1 << 9), - RD_Option_Codeview = (1 << 10), - RD_Option_Symbols = (1 << 11), - RD_Option_Relocs = (1 << 12), - RD_Option_Exceptions = (1 << 13), - RD_Option_LoadConfig = (1 << 14), - RD_Option_Resources = (1 << 15), - RD_Option_LongNames = (1 << 16), -}; + +#define RD_Option_Help (1ull << 0) +#define RD_Option_Version (1ull << 1) +#define RD_Option_Headers (1ull << 2) +#define RD_Option_Sections (1ull << 3) +#define RD_Option_Debug (1ull << 4) +#define RD_Option_Imports (1ull << 5) +#define RD_Option_Exports (1ull << 6) +#define RD_Option_Disasm (1ull << 7) +#define RD_Option_Rawdata (1ull << 8) +#define RD_Option_Tls (1ull << 9) +#define RD_Option_Codeview (1ull << 10) +#define RD_Option_Symbols (1ull << 11) +#define RD_Option_Relocs (1ull << 12) +#define RD_Option_Exceptions (1ull << 13) +#define RD_Option_LoadConfig (1ull << 14) +#define RD_Option_Resources (1ull << 15) +#define RD_Option_LongNames (1ull << 16) +// DWARF +#define RD_Option_DebugInfo (1ull << 17) +#define RD_Option_DebugAbbrev (1ull << 18) +#define RD_Option_DebugLine (1ull << 19) +#define RD_Option_DebugStr (1ull << 20) +#define RD_Option_DebugLoc (1ull << 21) +#define RD_Option_DebugRanges (1ull << 22) +#define RD_Option_DebugARanges (1ull << 23) +#define RD_Option_DebugAddr (1ull << 24) +#define RD_Option_DebugLocLists (1ull << 25) +#define RD_Option_DebugRngLists (1ull << 26) +#define RD_Option_DebugPubNames (1ull << 27) +#define RD_Option_DebugPubTypes (1ull << 28) +#define RD_Option_DebugLineStr (1ull << 29) +#define RD_Option_DebugStrOffsets (1ull << 30) +#define RD_Option_Dwarf \ + (RD_Option_DebugInfo | \ + RD_Option_DebugAbbrev | \ + RD_Option_DebugLine | \ + RD_Option_DebugStr | \ + RD_Option_DebugLoc | \ + RD_Option_DebugRanges | \ + RD_Option_DebugARanges | \ + RD_Option_DebugAddr | \ + RD_Option_DebugLocLists | \ + RD_Option_DebugRngLists | \ + RD_Option_DebugPubNames | \ + RD_Option_DebugPubTypes | \ + RD_Option_DebugLineStr | \ + RD_Option_DebugStrOffsets) +#define RD_Option_RelaxDwarfParser (1ull << 31ull) +// RDI +#define RD_Option_NoRdi (1ull << 32ull) typedef struct RD_Marker { @@ -66,77 +98,124 @@ typedef struct RD_DisasmResult U64 size; } RD_DisasmResult; +typedef struct RD_Section +{ + String8 name; + String8 raw_data; +} RD_Section; + +typedef struct RD_SectionArray +{ + U64 count; + RD_Section *v; +} RD_SectionArray; + +typedef struct RD_Line +{ + String8 file_path; + U32 line_num; +} RD_Line; + //////////////////////////////// -//- Markers +// raddump + +internal B32 rd_is_pe(String8 raw_data); +internal void rd_format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data); + +// Markers internal RD_MarkerArray * rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 string_table_off, U64 section_count, COFF_Symbol32Array symbols); -//- Disasm +// Sections + +internal RD_SectionArray rd_sections_from_coff_section_table(Arena *arnea, String8 raw_image, U64 string_table_off, U64 section_count, COFF_SectionHeader *sections); + +// Disasm internal RD_DisasmResult rd_disasm_next_instruction(Arena *arena, Arch arch, U64 addr, String8 raw_code); -internal void rd_format_disasm(Arena *arena, String8List *out, String8 indent, Arch arch, U64 image_base, U64 sect_off, U64 marker_count, RD_Marker *markers, String8 raw_code); +internal void rd_print_disasm (Arena *arena, String8List *out, String8 indent, Arch arch, U64 image_base, U64 sect_off, U64 marker_count, RD_Marker *markers, String8 raw_code); -//- Raw Data +// Raw Data internal String8 rd_format_hex_array(Arena *arena, U8 *ptr, U64 size); -internal void rd_format_raw_data(Arena *arena, String8List *out, String8 indent, U64 bytes_per_row, U64 marker_count, RD_Marker *markers, String8 raw_data); +internal void rd_print_raw_data (Arena *arena, String8List *out, String8 indent, U64 bytes_per_row, U64 marker_count, RD_Marker *markers, String8 raw_data); -//- CodeView +// DWARF -internal void cv_format_binary_annots(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data); -internal void cv_format_lvar_addr_range(Arena *arena, String8List *out, String8 indent, CV_LvarAddrRange range); -internal void cv_format_lvar_addr_gap(Arena *arena, String8List *out, String8 indent, String8 raw_data); -internal void cv_format_lvar_attr(Arena *arena, String8List *out, String8 indent, CV_LocalVarAttr attr); -internal void cv_format_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, U32 type, String8 raw_symbol); -internal U64 cv_format_leaf(Arena *arena, String8List *out, String8 indent, CV_LeafKind kind, String8 raw_leaf); -internal void cv_format_debug_t(Arena *arena, String8List *out, String8 indent, CV_DebugT debug_t); -internal void cv_format_symbols_c13(Arena *arena, String8List *out, String8 indent, String8 raw_data); -internal void cv_format_lines_c13(Arena *arena, String8List *out, String8 indent, String8 raw_lines); -internal void cv_format_file_checksums(Arena *arena, String8List *out, String8 indent, String8 raw_chksums); -internal void cv_format_string_table(Arena *arena, String8List *out, String8 indent, String8 raw_strtab); -internal void cv_format_inlinee_lines(Arena *arena, String8List *out, String8 indent, String8 raw_data); -internal void cv_format_symbols_section(Arena *arena, String8List *out, String8 indent, String8 raw_ss); +internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64); +internal String8 dw_format_expression_single_line(Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64); +internal String8 dw_format_eh_ptr_enc (Arena *arena, DW_EhPtrEnc enc); +internal void dw_print_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64); -//- COFF +internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, DW_EhPtrCtx *ptr_ctx); +internal void dw_print_debug_info (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed); +internal void dw_print_debug_abbrev (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_line (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, B32 relaxed); +internal void dw_print_debug_str (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed); +internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed); +internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_vranges, Arch arch); +internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_vranges); +internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); -internal void coff_format_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ArchiveMemberHeader header, String8 long_names); -internal void coff_format_section_table(Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_Symbol32Array symbols, U64 sect_count, COFF_SectionHeader *sect_headers); -internal void coff_disasm_sections(Arena *arena, String8List *out, String8 indent, String8 raw_data, COFF_MachineType machine, U64 image_base, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); -internal void coff_raw_data_sections(Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); -internal void coff_format_relocs(Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, COFF_Symbol32Array symbols); -internal void coff_format_symbol_table(Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, U64 string_table_off, COFF_Symbol32Array symbols); -internal void coff_format_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_HeaderBigObj *header); -internal void coff_format_header(Arena *arena, String8List *out, String8 indent, COFF_Header *header); -internal void coff_format_import(Arena *arena, String8List *out, String8 indent, COFF_ImportHeader *header); -internal void coff_format_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); -internal void coff_format_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); -internal void coff_format_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts); +// CodeView -//- MSVC CRT +internal void cv_print_binary_annots (Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data); +internal void cv_print_lvar_addr_range(Arena *arena, String8List *out, String8 indent, CV_LvarAddrRange range); +internal void cv_print_lvar_addr_gap (Arena *arena, String8List *out, String8 indent, String8 raw_data); +internal void cv_print_lvar_attr (Arena *arena, String8List *out, String8 indent, CV_LocalVarAttr attr); +internal void cv_print_symbol (Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV_TypeIndex min_itype, CV_SymKind type, String8 raw_symbol); +internal U64 cv_print_leaf (Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_itype, CV_LeafKind kind, String8 raw_leaf); +internal void cv_print_debug_t (Arena *arena, String8List *out, String8 indent, CV_DebugT debug_t); +internal void cv_print_symbols_c13 (Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data); +internal void cv_print_lines_c13 (Arena *arena, String8List *out, String8 indent, String8 raw_lines); +internal void cv_print_file_checksums (Arena *arena, String8List *out, String8 indent, String8 raw_chksums); +internal void cv_print_string_table (Arena *arena, String8List *out, String8 indent, String8 raw_strtab); +internal void cv_print_inlinee_lines (Arena *arena, String8List *out, String8 indent, String8 raw_data); +internal void cv_print_symbols_section(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_ss); -internal void mscrt_format_eh_handler_type32(Arena *arena, String8List *out, String8 indent, MSCRT_EhHandlerType32 *handler); +// COFF -//- PE +internal void coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ArchiveMemberHeader header, String8 long_names); +internal void coff_print_seciton_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_Symbol32Array symbols, U64 sect_count, COFF_SectionHeader *sect_headers); +internal void coff_disasm_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, COFF_MachineType machine, U64 image_base, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); +internal void coff_raw_data_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); +internal void coff_print_relocs (Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, COFF_Symbol32Array symbols); +internal void coff_print_symbol_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, U64 string_table_off, COFF_Symbol32Array symbols); +internal void coff_print_big_obj_header (Arena *arena, String8List *out, String8 indent, COFF_HeaderBigObj *header); +internal void coff_print_header (Arena *arena, String8List *out, String8 indent, COFF_Header *header); +internal void coff_print_import (Arena *arena, String8List *out, String8 indent, COFF_ImportHeader *header); +internal void coff_print_big_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); +internal void coff_print_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); +internal void coff_print_archive (Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts); -internal void pe_format_data_directory_ranges(Arena *arena, String8List *out, String8 indent, U64 count, PE_DataDirectory *dirs); -internal void pe_format_optional_header32(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32 *opt_header, PE_DataDirectory *dirs); -internal void pe_format_optional_header32plus(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32Plus *opt_header, PE_DataDirectory *dirs); -internal void pe_format_load_config32(Arena *arena, String8List *out, String8 indent, PE_LoadConfig32 *lc); -internal void pe_format_load_config64(Arena *arena, String8List *out, String8 indent, PE_LoadConfig64 *lc); -internal void pe_format_tls(Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls); -internal void pe_format_debug_directory(Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir); -internal void pe_format_export_table(Arena *arena, String8List *out, String8 indent, PE_ParsedExportTable exptab); -internal void pe_format_static_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedStaticImportTable imptab); -internal void pe_format_delay_import_table(Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedDelayImportTable imptab); -internal void pe_format_resources(Arena *arena, String8List *out, String8 indent, PE_ResourceDir *root); -internal void pe_format_exceptions_x8664(Arena *arena, String8List *out, String8 indent, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 except_frange); -internal void pe_format_exceptions(Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 except_frange); -internal void pe_format_base_relocs(Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 image_base, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 base_reloc_franges); -internal void pe_format(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts); +// MSVC CRT -//////////////////////////////// +internal void mscrt_print_eh_handler_type32(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, MSCRT_EhHandlerType32 *handler); -internal void format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data); +// PE + +internal void pe_print_data_directory_ranges(Arena *arena, String8List *out, String8 indent, U64 count, PE_DataDirectory *dirs); +internal void pe_print_optional_header32 (Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32 *opt_header, PE_DataDirectory *dirs); +internal void pe_print_optional_header32plus(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32Plus *opt_header, PE_DataDirectory *dirs); +internal void pe_print_load_config32 (Arena *arena, String8List *out, String8 indent, PE_LoadConfig32 *lc); +internal void pe_print_load_config64 (Arena *arena, String8List *out, String8 indent, PE_LoadConfig64 *lc); +internal void pe_print_tls (Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls); +internal void pe_print_debug_diretory (Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir); +internal void pe_print_export_table (Arena *arena, String8List *out, String8 indent, PE_ParsedExportTable exptab); +internal void pe_print_static_import_table (Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedStaticImportTable imptab); +internal void pe_print_delay_import_table (Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedDelayImportTable imptab); +internal void pe_print_resources (Arena *arena, String8List *out, String8 indent, PE_ResourceDir *root); +internal void pe_print_exceptions_x8664 (Arena *arena, String8List *out, String8 indent, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 except_frange, RDI_Parsed *rdi); +internal void pe_print_exceptions (Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 except_frange, RDI_Parsed *rdi); +internal void pe_print_base_relocs (Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 image_base, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 base_reloc_franges, RDI_Parsed *rdi); +internal void pe_print (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts, RDI_Parsed *rdi); #endif // RADDUMP_H + diff --git a/src/raddump/raddump_main.c b/src/raddump/raddump_main.c index 432651fe..3277ba54 100644 --- a/src/raddump/raddump_main.c +++ b/src/raddump/raddump_main.c @@ -6,16 +6,25 @@ //////////////////////////////// +#include "linker/base_ext/base_blake3.h" +#include "linker/base_ext/base_blake3.c" #include "third_party/xxHash/xxhash.c" #include "third_party/xxHash/xxhash.h" #include "third_party/radsort/radsort.h" +#include "third_party/md5/md5.c" +#include "third_party/md5/md5.h" #include "third_party/zydis/zydis.h" #include "third_party/zydis/zydis.c" +#include "third_party/rad_lzb_simple/rad_lzb_simple.h" +#include "third_party/rad_lzb_simple/rad_lzb_simple.c" //////////////////////////////// #include "base/base_inc.h" #include "os/os_inc.h" +#include "async/async.h" +#include "rdi_format/rdi_format_local.h" +#include "rdi_make/rdi_make_local.h" #include "path/path.h" #include "coff/coff.h" #include "coff/coff_enum.h" @@ -28,9 +37,19 @@ #include "msf/msf.h" #include "msf/msf_parse.h" #include "pdb/pdb.h" +#include "pdb/pdb_parse.h" +#include "rdi_from_pdb/rdi_from_pdb.h" +#include "dwarf/dwarf.h" +#include "dwarf/dwarf_parse.h" +#include "dwarf/dwarf_expr.h" +#include "dwarf/dwarf_unwind.h" +#include "dwarf/dwarf_enum.h" #include "base/base_inc.c" #include "os/os_inc.c" +#include "async/async.c" +#include "rdi_format/rdi_format_local.c" +#include "rdi_make/rdi_make_local.c" #include "path/path.c" #include "coff/coff.c" #include "coff/coff_enum.c" @@ -43,9 +62,16 @@ #include "msf/msf.c" #include "msf/msf_parse.c" #include "pdb/pdb.c" +#include "pdb/pdb_parse.c" +#include "rdi_from_pdb/rdi_from_pdb.c" +#include "dwarf/dwarf.c" +#include "dwarf/dwarf_parse.c" +#include "dwarf/dwarf_expr.c" +#include "dwarf/dwarf_unwind.c" +#include "dwarf/dwarf_enum.c" -#include "linker/base_ext/base_core.h" -#include "linker/base_ext/base_core.c" +#include "linker/base_ext/base_inc.h" +#include "linker/base_ext/base_inc.c" #include "linker/path_ext/path.h" #include "linker/path_ext/path.c" #include "linker/thread_pool/thread_pool.h" @@ -66,29 +92,66 @@ global read_only struct char *name; char *help; } g_rd_dump_option_map[] = { - { RD_Option_Help, "help", "Print help and exit" }, - { RD_Option_Version, "v", "Print version and exit" }, - { RD_Option_Headers, "headers", "Dump DOS header, file header, optional header, and/or archive header" }, - { RD_Option_Sections, "sections", "Dump section headers as table" }, - { RD_Option_Rawdata, "rawdata", "Dump raw section data" }, - { RD_Option_Codeview, "cv", "Dump CodeView" }, - { RD_Option_Disasm, "disasm", "Disassemble code sections" }, - { RD_Option_Symbols, "symbols", "Dump COFF symbol table" }, - { RD_Option_Relocs, "relocs", "Dump relocations" }, - { RD_Option_Exceptions, "exceptions", "Dump exceptions" }, - { RD_Option_Tls, "tls", "Dump Thread Local Storage directory" }, - { RD_Option_Debug, "debug", "Dump debug directory" }, - { RD_Option_Imports, "imports", "Dump import table" }, - { RD_Option_Exports, "exports", "Dump export table" }, - { RD_Option_LoadConfig, "loadconfig", "Dump load config" }, - { RD_Option_Resources, "resources", "Dump resource directory" }, - { RD_Option_LongNames, "longnames", "Dump archive long names" }, + { RD_Option_Help, "help", "Print help and exit" }, + { RD_Option_Version, "version", "Print version and exit" }, + { RD_Option_Headers, "headers", "Dump DOS header, file header, optional header, and/or archive header" }, + { RD_Option_Sections, "sections", "Dump section headers as table" }, + { RD_Option_Rawdata, "rawdata", "Dump raw section data" }, + { RD_Option_Codeview, "cv", "Dump CodeView" }, + { RD_Option_Disasm, "disasm", "Disassemble code sections" }, + { RD_Option_Symbols, "symtab", "Dump COFF symbol table" }, + { RD_Option_Relocs, "relocs", "Dump relocations" }, + { RD_Option_Exceptions, "exceptions", "Dump exceptions" }, + { RD_Option_Tls, "tls", "Dump Thread Local Storage directory" }, + { RD_Option_Debug, "debug", "Dump debug directory" }, + { RD_Option_Imports, "imports", "Dump import table" }, + { RD_Option_Exports, "exports", "Dump export table" }, + { RD_Option_LoadConfig, "loadconfig", "Dump load config" }, + { RD_Option_Resources, "resources", "Dump resource directory" }, + { RD_Option_LongNames, "longnames", "Dump archive long names" }, + { RD_Option_DebugInfo, "debug_info", "Dump .debug_info" }, + { RD_Option_DebugAbbrev, "debug_abbrev", "Dump .debug_abbrev" }, + { RD_Option_DebugLine, "debug_line", "Dump .debug_line" }, + { RD_Option_DebugStr, "debug_str", "Dump .debug_str" }, + { RD_Option_DebugLoc, "debug_loc", "Dump .debug_loc" }, + { RD_Option_DebugRanges, "debug_ranges", "Dump .debug_ranges" }, + { RD_Option_DebugARanges, "debug_aranges", "Dump .debug_aranges" }, + { RD_Option_DebugAddr, "debug_addr", "Dump .debug_addr" }, + { RD_Option_DebugLocLists, "debug_loclists", "Dump .debug_loclists" }, + { RD_Option_DebugRngLists, "debug_rnglists", "Dump .debug_rnglists" }, + { RD_Option_DebugPubNames, "debug_pubnames", "Dump .debug_pubnames" }, + { RD_Option_DebugPubTypes, "debug_pubtypes", "Dump .debug_putypes" }, + { RD_Option_DebugLineStr, "debug_linestr", "Dump .debug_linestr" }, + { RD_Option_DebugStrOffsets, "debug_stroffsets", "Dump .debug_stroffsets" }, + { RD_Option_Dwarf, "dwarf", "Dump all DWARF sections" }, + { RD_Option_RelaxDwarfParser, "relax_dwarf_parser", "Relaxes version requirement on attribute and form encodings" }, + { RD_Option_NoRdi, "nordi", "Don't load RAD Debug Info" }, + + { RD_Option_Help, "h", "Alias for -help" }, + { RD_Option_Version, "v", "Alias for -version" }, + { RD_Option_Sections, "s", "Alias for -sections" }, + { RD_Option_Exceptions, "e", "Alias for -exceptions" }, + { RD_Option_Imports, "i", "Alias for -imports" }, + { RD_Option_Exports, "x", "Alias for -exports" }, + { RD_Option_LoadConfig, "l", "Alias for -loadconifg" }, + { RD_Option_Resources, "c", "Alias for -resources" }, + { RD_Option_Relocs, "r", "Alias for -relocs" }, }; internal void entry_point(CmdLine *cmdline) { - Temp scratch = scratch_begin(0,0); + Arena *arena = arena_alloc(); + + // make indent + String8List *out = push_array(arena, String8List, 1); + String8 indent; + { + U64 indent_buffer_size = RD_INDENT_WIDTH * RD_INDENT_MAX; + U8 *indent_buffer = push_array(arena, U8, indent_buffer_size); + MemorySet(indent_buffer, ' ', indent_buffer_size); + indent = str8(indent_buffer, 0); + } // parse options RD_Option opts = 0; @@ -107,8 +170,8 @@ entry_point(CmdLine *cmdline) } if (opt == 0) { - fprintf(stderr, "Unknown argument: \"%.*s\"\n", str8_varg(cmd->string)); - os_abort(1); + rd_errorf("Unknown argument: \"%S\"", cmd->string); + goto exit; } opts |= opt; @@ -117,66 +180,73 @@ entry_point(CmdLine *cmdline) // print help if (opts & RD_Option_Help) { + int longest_cmd_switch = 0; for (U64 opt_idx = 0; opt_idx < ArrayCount(g_rd_dump_option_map); ++opt_idx) { - fprintf(stdout, "-%s %s\n", g_rd_dump_option_map[opt_idx].name, g_rd_dump_option_map[opt_idx].help); + longest_cmd_switch = Max(longest_cmd_switch, strlen(g_rd_dump_option_map[opt_idx].name)); } - os_abort(0); + rd_printf(BUILD_TITLE_STRING_LITERAL); + rd_newline(); + rd_printf("# Help"); + rd_indent(); + for (U64 opt_idx = 0; opt_idx < ArrayCount(g_rd_dump_option_map); ++opt_idx) { + char *name = g_rd_dump_option_map[opt_idx].name; + char *help = g_rd_dump_option_map[opt_idx].help; + int indent_size = longest_cmd_switch - strlen(name) + 1; + rd_printf("-%s%.*s%s", g_rd_dump_option_map[opt_idx].name, indent_size, indent.str, g_rd_dump_option_map[opt_idx].help); + } + rd_unindent(); + goto exit; } // print version if (opts & RD_Option_Version) { - fprintf(stdout, BUILD_TITLE_STRING_LITERAL "\n"); - fprintf(stdout, "\traddump \n"); - os_abort(0); + rd_printf(BUILD_TITLE_STRING_LITERAL); + rd_printf("\traddump "); + goto exit; } // input check if (cmdline->inputs.node_count == 0) { - fprintf(stderr, "No input file specified\n"); - os_abort(1); + rd_errorf("No input file specified"); + goto exit; } else if (cmdline->inputs.node_count > 1) { - fprintf(stderr, "Too many inputs specified, expected one\n"); - os_abort(1); + rd_errorf("Too many inputs specified, expected one"); + goto exit; } // read input String8 file_path = str8_list_first(&cmdline->inputs); - String8 raw_data = os_data_from_file_path(scratch.arena, file_path); + String8 raw_data = os_data_from_file_path(arena, file_path); // is read ok? if (raw_data.size == 0) { - fprintf(stderr, "Unable to read input file \"%.*s\"\n", str8_varg(file_path)); - os_abort(1); - } - - // make indent - String8 indent; - { - U64 indent_buffer_size = RD_INDENT_WIDTH * RD_INDENT_MAX; - U8 *indent_buffer = push_array(scratch.arena, U8, indent_buffer_size); - MemorySet(indent_buffer, ' ', indent_buffer_size); - indent = str8(indent_buffer, 0); + rd_errorf("Unable to read input file \"%S\"", file_path); + goto exit; } // format input - String8List out = {0}; - format_preamble(scratch.arena, &out, indent, file_path, raw_data); + rd_format_preamble(arena, out, indent, file_path, raw_data); if (coff_is_archive(raw_data) || coff_is_thin_archive(raw_data)) { - coff_format_archive(scratch.arena, &out, indent, raw_data, opts); + coff_print_archive(arena, out, indent, raw_data, opts); } else if (coff_is_big_obj(raw_data)) { - coff_format_big_obj(scratch.arena, &out, indent, raw_data, opts); + coff_print_big_obj(arena, out, indent, raw_data, opts); } else if (coff_is_obj(raw_data)) { - coff_format_obj(scratch.arena, &out, indent, raw_data, opts); - } else if (is_pe(raw_data)) { - pe_format(scratch.arena, &out, indent, raw_data, opts); + coff_print_obj(arena, out, indent, raw_data, opts); + } else if (rd_is_pe(raw_data)) { + RDI_Parsed *rdi = 0; + if (!(opts & RD_Option_NoRdi)) { + rdi = rd_rdi_from_pe(arena, file_path, raw_data); + } + pe_print(arena, out, indent, raw_data, opts, rdi); } else if (pe_is_res(raw_data)) { //tool_out_coff_res(stdout, file_data); } +exit:; // print formatted string - String8 out_string = str8_list_join(scratch.arena, &out, &(StringJoin){ .sep = str8_lit("\n"),}); + String8 out_string = str8_list_join(arena, out, &(StringJoin){ .sep = str8_lit("\n"),}); fprintf(stdout, "%.*s", str8_varg(out_string)); - scratch_end(scratch); + arena_release(arena); }