diff --git a/llvm/docs/CommandGuide/llvm-objdump.rst b/llvm/docs/CommandGuide/llvm-objdump.rst --- a/llvm/docs/CommandGuide/llvm-objdump.rst +++ b/llvm/docs/CommandGuide/llvm-objdump.rst @@ -179,6 +179,13 @@ * ``att``: x86 only (default). Print in the AT&T syntax. * ``intel``: x86 only. Print in the intel syntax. +.. option:: --markup-context= + + Adjust addresses using a JSON context file produced from llvm-symbolizer + markup (i.e., llvm-symbolizer --dump-context). Note that llvm-symbolizer can + emit multiple contexts as an array of JSON objects, but this flag accepts + either an object or an array with exactly one object. + .. option:: --mcpu= Target a specific CPU type for disassembly. Specify ``--mcpu=help`` to display diff --git a/llvm/test/tools/llvm-objdump/X86/markup-context.test b/llvm/test/tools/llvm-objdump/X86/markup-context.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/X86/markup-context.test @@ -0,0 +1,135 @@ +# RUN: split-file %s %t +# RUN: yaml2obj %t/obj.yaml -o %t/obj.o +# RUN: llvm-objdump --all-headers -D -z --markup-context=%t/context.json %t/obj.o | FileCheck %s --check-prefixes=OUTPUT +# RUN: not llvm-objdump --all-headers -D -z --markup-context=%t/missing.json %t/obj.o 2>&1 | FileCheck %s --check-prefixes=MISSING-FILE +# RUN: not llvm-objdump --all-headers -D -z --markup-context=%t/invalid.json %t/obj.o 2>&1 | FileCheck %s --check-prefixes=INVALID-JSON +# RUN: not llvm-objdump --all-headers -D -z --markup-context=%t/context.json %t/obj.o --adjust-vma=1 2>&1 | FileCheck %s --check-prefixes=FLAG-CONFLICT + +# OUTPUT: Sections: +# OUTPUT-NEXT: Idx Name Size VMA Type +# OUTPUT-NEXT: 0 00000000 0000000000000000 +# OUTPUT-NEXT: 1 .text 00000002 0000000000123000 TEXT +# OUTPUT-NEXT: 2 .debug_str 00000004 0000000000000000 +# OUTPUT-NEXT: 3 .rela.debug_str 00000018 0000000000000000 +# OUTPUT-NEXT: 4 .data 00000004 0000000000abc000 DATA +# OUTPUT-NEXT: 5 .rela.data 00000018 0000000000000000 +# OUTPUT-NEXT: 6 .symtab 00000060 0000000000000000 +# OUTPUT-NEXT: 7 .strtab 00000010 0000000000000000 +# OUTPUT-NEXT: 8 .shstrtab 0000003c 0000000000000000 + +# OUTPUT: SYMBOL TABLE: +# OUTPUT-NEXT: 0000000000000001 l F .text 0000000000000000 func +# OUTPUT-NEXT: 0000000000000000 l .text 0000000000000000 sym +# OUTPUT-NEXT: 0000000000000000 l d .text 0000000000000000 .text + +# OUTPUT: 0000000000123000 : +# OUTPUT-NEXT: 123000: {{.*}} nop +# OUTPUT: 0000000000123001 : +# OUTPUT-NEXT: 123001: {{.*}} retq + +# OUTPUT: 0000000000000000 <.debug_str>: +# OUTPUT-NEXT: 0: {{.*}} %al, (%rax) +# OUTPUT-NEXT: 0000000000123001: R_X86_64_32 .text +# OUTPUT-NEXT: 2: {{.*}} addb %al, (%rax) + +# OUTPUT: 0000000000000000 <.rela.debug_str>: +# OUTPUT-NEXT: 0: {{.*}} addl %eax, (%rax) +## ... There are more lines here. We do not care. + +# OUTPUT: 0000000000abc000 <.data>: +# OUTPUT-NEXT: abc000: {{.*}} addb %al, (%rax) +# OUTPUT-NEXT: 0000000000abc000: R_X86_64_32 .text +# OUTPUT-NEXT: abc002: {{.*}} addb %al, (%rax) + +# OUTPUT: 0000000000000000 <.rela.data>: +# OUTPUT-NEXT: 0: {{.*}} addb %al, (%rax) +## ... There are more lines here. We do not care. + +# MISSING-FILE: error: '{{.*}}missing.json': No such file or directory +# INVALID-JSON: error: '{{.*}}invalid.json': [2:0, byte=2]: Expected object key +# FLAG-CONFLICT: error: --adjust-vma and --markup-context are incompatible + +#--- obj.yaml +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0 + AddressAlign: 0x0000000000000004 + Content: 90C3 + - Name: .debug_str + Type: SHT_PROGBITS + Flags: [ SHF_MERGE, SHF_STRINGS ] + AddressAlign: 0x0000000000000001 + Content: '00000000' + - Name: .rela.debug_str + Type: SHT_RELA + Link: .symtab + AddressAlign: 0x0000000000000008 + Info: .debug_str + Relocations: + - Offset: 0x0000000000000001 + Symbol: .text + Type: R_X86_64_32 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Address: 0x0000000000000004 + Content: '00000000' + - Name: .rela.data + Type: SHT_RELA + Link: .symtab + AddressAlign: 0x0000000000000008 + Info: .data + Relocations: + - Offset: 0x0000000000000000 + Symbol: .text + Type: R_X86_64_32 +Symbols: + - Name: func + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 + - Name: sym + Section: .text + - Name: .text + Type: STT_SECTION + Section: .text + +#--- context.json +{ + "modules" : [{ + "id": 0, + "name": "a.o", + "type": "elf", + "buildID": "ab" + }], + "mmaps": [ + { + "address": 1191936, + "size": 2, + "type": "load", + "moduleID": 0, + "mode": "rx", + "moduleRelativeAddress": 0 + }, + { + "address": 11255808, + "size": 4, + "type": "load", + "moduleID": 0, + "mode": "rx", + "moduleRelativeAddress": 4 + } + ] +} + +#--- invalid.json +{ diff --git a/llvm/tools/llvm-objdump/ObjdumpOpts.td b/llvm/tools/llvm-objdump/ObjdumpOpts.td --- a/llvm/tools/llvm-objdump/ObjdumpOpts.td +++ b/llvm/tools/llvm-objdump/ObjdumpOpts.td @@ -128,6 +128,10 @@ MetaVarName<"a1,+a2,-a3,...">, HelpText<"Target specific attributes (--mattr=help for details)">; +def markup_context_EQ : Joined<["--"], "markup-context=">, + MetaVarName<"">, + HelpText<"Adjust addresses using a JSON context from llvm-symbolizer markup">; + def no_show_raw_insn : Flag<["--"], "no-show-raw-insn">, HelpText<"When disassembling instructions, " "do not print the instruction bytes.">; diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -32,6 +32,7 @@ #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Twine.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/Symbolize/MarkupContext.h" #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" #include "llvm/DebugInfo/Symbolize/Symbolize.h" #include "llvm/Debuginfod/BuildIDFetcher.h" @@ -207,6 +208,7 @@ static std::vector InputFilenames; bool objdump::PrintLines; static bool MachOOpt; +std::optional MarkupContext; std::string objdump::MCPU; std::vector objdump::MAttrs; bool objdump::ShowRawInsn; @@ -993,19 +995,26 @@ return Ret; } -// Used for --adjust-vma to check if address should be adjusted by the -// specified value for a given section. -// For ELF we do not adjust non-allocatable sections like debug ones, -// because they are not loadable. +// Adjust a virtual address for the --adjust-vma and --markup-context flags. For +// ELF we do not adjust non-allocatable sections like debug ones, because they +// are not loadable. // TODO: implement for other file formats. -static bool shouldAdjustVA(const SectionRef &Section) { +static uint64_t adjustVMA(uint64_t Addr, const SectionRef &Section) { const ObjectFile *Obj = Section.getObject(); - if (Obj->isELF()) - return ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC; - return false; + if (!Obj->isELF()) + return Addr; + if (!(ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC)) + return Addr; + if (MarkupContext) { + const symbolize::MarkupContext::MMap *MM = + MarkupContext->getContainingMMapForMRAddr(Addr); + if (!MM) + return Addr; + return MM->fromModuleRelativeAddr(Addr); + } + return Addr + AdjustVMA; } - typedef std::pair MappingSymbolPair; static char getMappingSymbolKind(ArrayRef MappingSymbols, uint64_t Address) { @@ -1512,10 +1521,6 @@ SmallString<40> Comments; raw_svector_ostream CommentStream(Comments); - uint64_t VMAAdjustment = 0; - if (shouldAdjustVA(Section)) - VMAAdjustment = AdjustVMA; - // In executable and shared objects, r_offset holds a virtual address. // Subtract SectionAddr from the r_offset field of a relocation to get // the section offset. @@ -1662,7 +1667,7 @@ if (LeadingAddr) outs() << format(Is64Bits ? "%016" PRIx64 " " : "%08" PRIx64 " ", - SectionAddr + Start + VMAAdjustment); + adjustVMA(SectionAddr + Start, Section)); if (Obj.isXCOFF() && SymbolDescription) { outs() << getXCOFFSymbolDescription(Symbol, SymbolName) << ":\n"; } else @@ -1820,8 +1825,8 @@ PIP.printInst( *IP, Disassembled ? &Inst : nullptr, Bytes.slice(Index, Size), - {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, FOS, - "", *STI, &SP, Obj.getFileName(), &Rels, LVP); + {adjustVMA(SectionAddr + Index, Section), Section.getIndex()}, + FOS, "", *STI, &SP, Obj.getFileName(), &Rels, LVP); IP->setCommentStream(llvm::nulls()); @@ -1965,17 +1970,17 @@ if (Offset >= Index + Size) break; + uint64_t Addr = SectionAddr + Offset; + // When --adjust-vma is used, update the address printed. if (RelCur->getSymbol() != Obj.symbol_end()) { Expected SymSI = RelCur->getSymbol()->getSection(); - if (SymSI && *SymSI != Obj.section_end() && - shouldAdjustVA(**SymSI)) - Offset += AdjustVMA; + if (SymSI && *SymSI != Obj.section_end()) + Addr = adjustVMA(Addr, **SymSI); } - printRelocation(FOS, Obj.getFileName(), *RelCur, - SectionAddr + Offset, Is64Bits); + printRelocation(FOS, Obj.getFileName(), *RelCur, Addr, Is64Bits); LVP.printAfterOtherLine(FOS, true); ++RelCur; } @@ -2280,9 +2285,7 @@ uint64_t Idx; for (const SectionRef &Section : ToolSectionFilter(Obj, &Idx)) { StringRef Name = unwrapOrError(Section.getName(), Obj.getFileName()); - uint64_t VMA = Section.getAddress(); - if (shouldAdjustVA(Section)) - VMA += AdjustVMA; + uint64_t VMA = adjustVMA(Section.getAddress(), Section); uint64_t Size = Section.getSize(); @@ -3020,6 +3023,9 @@ static void parseObjdumpOptions(const llvm::opt::InputArgList &InputArgs) { parseIntArg(InputArgs, OBJDUMP_adjust_vma_EQ, AdjustVMA); + if (InputArgs.hasArg(OBJDUMP_adjust_vma_EQ) && + InputArgs.hasArg(OBJDUMP_markup_context_EQ)) + reportCmdLineError("--adjust-vma and --markup-context are incompatible"); AllHeaders = InputArgs.hasArg(OBJDUMP_all_headers); ArchName = InputArgs.getLastArgValue(OBJDUMP_arch_name_EQ).str(); ArchiveHeaders = InputArgs.hasArg(OBJDUMP_archive_headers); @@ -3045,6 +3051,19 @@ PrintLines = InputArgs.hasArg(OBJDUMP_line_numbers); InputFilenames = InputArgs.getAllArgValues(OBJDUMP_INPUT); MachOOpt = InputArgs.hasArg(OBJDUMP_macho); + if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_markup_context_EQ)) { + StringRef Filename = A->getValue(); + ErrorOr> Buf = + MemoryBuffer::getFileOrSTDIN(Filename); + if (!Buf) + reportError(Filename, Buf.getError().message()); + Expected V = json::parse((*Buf)->getBuffer()); + if (!V) + reportError(V.takeError(), Filename); + json::Path::Root R; + if (!fromJSON(*V, MarkupContext.emplace(), R)) + reportError(R.getError(), Filename); + } MCPU = InputArgs.getLastArgValue(OBJDUMP_mcpu_EQ).str(); MAttrs = commaSeparatedValues(InputArgs, OBJDUMP_mattr_EQ); ShowRawInsn = !InputArgs.hasArg(OBJDUMP_no_show_raw_insn);