[llvm] 1ae449f - Reland "[llvm-readobj][MachO] Add option to sort the symbol table before dumping (MachO only, for now)."

Vy Nguyen via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 31 11:21:57 PDT 2022


Author: Vy Nguyen
Date: 2022-03-31T14:21:41-04:00
New Revision: 1ae449f9a33b9c8cc3bbf38013b24bd4e9e5bb27

URL: https://github.com/llvm/llvm-project/commit/1ae449f9a33b9c8cc3bbf38013b24bd4e9e5bb27
DIFF: https://github.com/llvm/llvm-project/commit/1ae449f9a33b9c8cc3bbf38013b24bd4e9e5bb27.diff

LOG: Reland  "[llvm-readobj][MachO] Add option to sort the symbol table before dumping (MachO only, for now)."
    https://reviews.llvm.org/D116787

This reverts commit 33b3c86afab06ad61d46456c85c0b565cfff8287.

New change: fixed build failures:
 - in stabs-sorted:restore the the ERR-KEY statements, which were accidentally deleted during refactoring
 - in ObjDumper.h/MachODumper.cpp: refactor so that current dumpers which didn't provide an impl that accept a SymCom still works

Added: 
    llvm/test/tools/llvm-readobj/MachO/stabs-sorted.yaml
    llvm/test/tools/llvm-readobj/sort-symbols.test

Modified: 
    llvm/docs/CommandGuide/llvm-readobj.rst
    llvm/tools/llvm-readobj/MachODumper.cpp
    llvm/tools/llvm-readobj/ObjDumper.h
    llvm/tools/llvm-readobj/Opts.td
    llvm/tools/llvm-readobj/llvm-readobj.cpp
    llvm/tools/llvm-readobj/llvm-readobj.h

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/llvm-readobj.rst b/llvm/docs/CommandGuide/llvm-readobj.rst
index ef2ea3eb0e587..b33e722403468 100644
--- a/llvm/docs/CommandGuide/llvm-readobj.rst
+++ b/llvm/docs/CommandGuide/llvm-readobj.rst
@@ -106,6 +106,10 @@ file formats.
  When used with :option:`--sections`, display symbols for each section shown.
  This option has no effect for GNU style output.
 
+.. option:: --sort-symbols=<sort_key[,sort_key]>
+
+ Specify the keys to sort symbols before displaying symtab.
+ Valid values for sort_key are ``name`` and ``type``.
 .. option:: --stackmap
 
  Display contents of the stackmap section.

diff  --git a/llvm/test/tools/llvm-readobj/MachO/stabs-sorted.yaml b/llvm/test/tools/llvm-readobj/MachO/stabs-sorted.yaml
new file mode 100644
index 0000000000000..f89af79d0dabb
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/MachO/stabs-sorted.yaml
@@ -0,0 +1,233 @@
+## Verify that llvm-readobj can dump files with stabs symbols in a sorted order.
+
+# RUN: yaml2obj --docnum=1 %s -o %t
+
+# RUN: not llvm-readobj --syms --sort-symbols=foo %t 2>&1 | FileCheck %s --check-prefix ERR-KEY
+# RUN: not llvm-readobj --syms --sort-symbols=,, %t 2>&1 | FileCheck %s --check-prefix ERR-KEY-EMPT
+
+# RUN: llvm-readobj --syms --sort-symbols=type,name %t | FileCheck %s --check-prefix TYPE-NAME
+# RUN: llvm-readobj --syms --sort-symbols=name,type %t | FileCheck %s --check-prefix NAME-TYPE
+# RUN: llvm-readobj --syms --sort-symbols=type %t | FileCheck %s --check-prefix TYPE-ONLY
+
+# ERR-KEY: error: --sort-symbols value should be 'name' or 'type', but was 'foo'
+# ERR-KEY-EMPT: error: --sort-symbols value should be 'name' or 'type', but was ''
+
+# TYPE-NAME:      Name: _a (19)
+# TYPE-NAME-NEXT: Type: Section (0xE)
+# TYPE-NAME:      Name: _d (10)
+# TYPE-NAME-NEXT: Type: Section (0xE)
+# TYPE-NAME:      Name: _f (7)
+# TYPE-NAME-NEXT: Type: SymDebugTable (0x2E)
+# TYPE-NAME:      Name: _z (1)
+# TYPE-NAME-NEXT: Type: SymDebugTable (0x2E)
+# TYPE-NAME:      Name: _c (13)
+# TYPE-NAME-NEXT: Type: SymDebugTable (0x64)
+# TYPE-NAME:      Name: _g (4)
+# TYPE-NAME-NEXT: Type: SymDebugTable (0x64)
+# TYPE-NAME:      Name: _b (16)
+# TYPE-NAME-NEXT: Type: SymDebugTable (0x66)
+# TYPE-NAME:      Name: _d2 (22)
+# TYPE-NAME-NEXT: Type: SymDebugTable (0x66)
+
+# NAME-TYPE:         Name: _a (19)
+# NAME-TYPE-NEXT:    Type: Section (0xE)
+# NAME-TYPE:         Name: _b (16)
+# NAME-TYPE-NEXT:    Type: SymDebugTable (0x66)
+# NAME-TYPE:         Name: _c (13)
+# NAME-TYPE-NEXT:    Type: SymDebugTable (0x64)
+# NAME-TYPE:         Name: _d (10)
+# NAME-TYPE-NEXT:    Type: Section (0xE)
+# NAME-TYPE:         Name: _d2 (22)
+# NAME-TYPE-NEXT:    Type: SymDebugTable (0x66)
+# NAME-TYPE:         Name: _f (7)
+# NAME-TYPE-NEXT:    Type: SymDebugTable (0x2E)
+# NAME-TYPE:         Name: _g (4)
+# NAME-TYPE-NEXT:    Type: SymDebugTable (0x64)
+# NAME-TYPE:         Name: _z (1)
+# NAME-TYPE-NEXT:    Type: SymDebugTable (0x2E)
+
+# TYPE-ONLY:        Name: _d (10)
+# TYPE-ONLY-NEXT:   Type: Section (0xE)
+# TYPE-ONLY:        Name: _a (19)
+# TYPE-ONLY-NEXT:   Type: Section (0xE)
+# TYPE-ONLY:        Name: _f (7)
+# TYPE-ONLY-NEXT:   Type: SymDebugTable (0x2E)
+# TYPE-ONLY:        Name: _z (1)
+# TYPE-ONLY-NEXT:   Type: SymDebugTable (0x2E)
+# TYPE-ONLY:        Name: _g (4)
+# TYPE-ONLY-NEXT:   Type: SymDebugTable (0x64)
+# TYPE-ONLY:        Name: _c (13)
+# TYPE-ONLY-NEXT:   Type: SymDebugTable (0x64)
+# TYPE-ONLY:        Name: _d2 (22)
+# TYPE-ONLY-NEXT:   Type: SymDebugTable (0x66)
+# TYPE-ONLY:        Name: _b (16)
+# TYPE-ONLY-NEXT:   Type: SymDebugTable (0x66)
+
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x1000007
+  cpusubtype:      0x3
+  filetype:        0x1
+  ncmds:           3
+  sizeofcmds:      496
+  flags:           0x2000
+  reserved:        0x0
+LoadCommands:
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         392
+    segname:         ''
+    vmaddr:          0
+    vmsize:          32
+    fileoff:         528
+    filesize:        28
+    maxprot:         7
+    initprot:        7
+    nsects:          4
+    flags:           0
+    Sections:
+      - sectname:        __text
+        segname:         __TEXT
+        addr:            0x0
+        size:            9
+        offset:          0x210
+        align:           0
+        reloff:          0x230
+        nreloc:          1
+        flags:           0x80000000
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         '000000000000000000'
+        relocations:
+          - address:         0x0
+            symbolnum:       7
+            pcrel:           false
+            length:          3
+            extern:          true
+            type:            0
+            scattered:       false
+            value:           0
+      - sectname:        more_data
+        segname:         __DATA
+        addr:            0x9
+        size:            8
+        offset:          0x219
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         7B00000000000000
+      - sectname:        __data
+        segname:         __DATA
+        addr:            0x11
+        size:            11
+        offset:          0x221
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         7B00000000000000000000
+      - sectname:        __common
+        segname:         __DATA
+        addr:            0x1C
+        size:            4
+        offset:          0x0
+        align:           2
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x1
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          568
+    nsyms:           8
+    stroff:          696
+    strsize:         32
+  - cmd:             LC_DYSYMTAB
+    cmdsize:         80
+    ilocalsym:       0
+    nlocalsym:       7
+    iextdefsym:      7
+    nextdefsym:      0
+    iundefsym:       7
+    nundefsym:       1
+    tocoff:          0
+    ntoc:            0
+    modtaboff:       0
+    nmodtab:         0
+    extrefsymoff:    0
+    nextrefsyms:     0
+    indirectsymoff:  0
+    nindirectsyms:   0
+    extreloff:       0
+    nextrel:         0
+    locreloff:       0
+    nlocrel:         0
+LinkEditData:
+  NameList:
+    - n_strx:          4
+      n_type:          0x64
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          10
+      n_type:          0xE
+      n_sect:          1
+      n_desc:          0
+      n_value:         8
+    - n_strx:          22
+      n_type:          0x66
+      n_sect:          1
+      n_desc:          0
+      n_value:         8
+    - n_strx:          16
+      n_type:          0x66
+      n_sect:          2
+      n_desc:          0
+      n_value:         9
+    - n_strx:          19
+      n_type:          0xE
+      n_sect:          3
+      n_desc:          0
+      n_value:         17
+    - n_strx:          13
+      n_type:          0x64
+      n_sect:          4
+      n_desc:          0
+      n_value:         28
+    - n_strx:          7
+      n_type:          0x2E
+      n_sect:          3
+      n_desc:          0
+      n_value:         25
+    - n_strx:          1
+      n_type:          0x2E
+      n_sect:          0
+      n_desc:          0
+      n_value:         0
+  StringTable:
+    - ''
+    - _z
+    - _g
+    - _f
+    - _d
+    - _c
+    - _b
+    - _a
+    - _d2
+    - ''
+    - ''
+    - ''
+    - ''
+    - ''
+    - ''
+...

diff  --git a/llvm/test/tools/llvm-readobj/sort-symbols.test b/llvm/test/tools/llvm-readobj/sort-symbols.test
new file mode 100644
index 0000000000000..0d01c9b5d85cb
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/sort-symbols.test
@@ -0,0 +1,68 @@
+## Test that we print a warning for ELF, WASM, and COFF but still dump the contents for all.
+
+# RUN: yaml2obj --docnum=1 %s -o %t_macho
+# RUN: yaml2obj --docnum=2 %s -o %t_coff
+# RUN: yaml2obj --docnum=3 %s -o %t_elf
+# RUN: yaml2obj --docnum=4 %s -o %t_wasm
+# RUN: yaml2obj --docnum=5 %s -o %t_xcoff
+
+# RUN: llvm-readobj --syms --sort-symbols=type,name \
+# RUN:   %t_coff %t_elf %t_wasm %t_xcoff %t_macho 2>&1 | FileCheck %s \
+# RUN:  -DMSG="--sort-symbols is not supported yet for this format"
+
+# CHECK: warning: '{{.+}}_coff': [[MSG]]
+# CHECK: Format: COFF-ARM
+# CHECK: warning: '{{.+}}_elf': [[MSG]]
+# CHECK: Format: elf64-unknown
+# CHECK: warning: '{{.+}}_wasm': [[MSG]]
+# CHECK: Format: WASM
+# CHECK: warning: '{{.+}}_xcoff': [[MSG]]
+# CHECK: Format: aixcoff-rs6000
+# CHECK-NOT: warning '{{.+}}_macho': [[MSG]]
+# CHECK: Format: Mach-O 64-bit x86-64
+
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x1000007
+  cpusubtype:      0x3
+  filetype:        0x1
+  ncmds:           0
+  sizeofcmds:      0
+  flags:           0x2000
+  reserved:        0x0
+...
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: [  ]
+sections:
+symbols:
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+Sections:
+  - Name:    .gnu.version
+    Type:    SHT_GNU_versym
+...
+--- !WASM
+FileHeader:
+  Version:         0x00000001
+Sections:
+  - Type:            DATA
+    Segments:
+      - SectionOffset:   6
+        InitFlags:       0
+        Offset:
+          Opcode:          GLOBAL_GET
+          Index:           1
+        Content:         '64'
+...
+--- !XCOFF
+FileHeader:
+  MagicNumber:         0x01DF
+  CreationTime:        1
+  EntriesInSymbolTable: 1
+...

diff  --git a/llvm/tools/llvm-readobj/MachODumper.cpp b/llvm/tools/llvm-readobj/MachODumper.cpp
index 599b0355917e9..d875e3b3a381e 100644
--- a/llvm/tools/llvm-readobj/MachODumper.cpp
+++ b/llvm/tools/llvm-readobj/MachODumper.cpp
@@ -13,6 +13,7 @@
 #include "ObjDumper.h"
 #include "StackMapPrinter.h"
 #include "llvm-readobj.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Object/MachO.h"
@@ -39,6 +40,11 @@ class MachODumper : public ObjDumper {
 
   void printNeededLibraries() override;
 
+  bool canCompareSymbols() const override { return true; }
+  bool compareSymbolsByName(object::SymbolRef LHS,
+                            object::SymbolRef RHS) const override;
+  bool compareSymbolsByType(object::SymbolRef LHS,
+                            object::SymbolRef RHS) const override;
   // MachO-specific.
   void printMachODataInCode() override;
   void printMachOVersionMin() override;
@@ -51,10 +57,14 @@ class MachODumper : public ObjDumper {
   template<class MachHeader>
   void printFileHeaders(const MachHeader &Header);
 
-  StringRef getSymbolName(const SymbolRef &Symbol);
+  StringRef getSymbolName(const SymbolRef &Symbol) const;
+  uint8_t getSymbolType(const SymbolRef &Symbol) const;
 
   void printSymbols() override;
+  void printSymbols(Optional<SymbolComparator> SymComp) override;
   void printDynamicSymbols() override;
+  void printDynamicSymbols(Optional<SymbolComparator> SymComp) override;
+  void printSymbol(const SymbolRef &Symbol, ScopedPrinter &W);
   void printSymbol(const SymbolRef &Symbol);
 
   void printRelocation(const RelocationRef &Reloc);
@@ -602,7 +612,7 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj,
   }
 }
 
-StringRef MachODumper::getSymbolName(const SymbolRef &Symbol) {
+StringRef MachODumper::getSymbolName(const SymbolRef &Symbol) const {
   Expected<StringRef> SymbolNameOrErr = Symbol.getName();
   if (!SymbolNameOrErr) {
     reportError(SymbolNameOrErr.takeError(), Obj->getFileName());
@@ -610,19 +620,48 @@ StringRef MachODumper::getSymbolName(const SymbolRef &Symbol) {
   return *SymbolNameOrErr;
 }
 
-void MachODumper::printSymbols() {
-  ListScope Group(W, "Symbols");
+uint8_t MachODumper::getSymbolType(const SymbolRef &Symbol) const {
+  return Obj->getSymbol64TableEntry(Symbol.getRawDataRefImpl()).n_type;
+}
+
+bool MachODumper::compareSymbolsByName(SymbolRef LHS, SymbolRef RHS) const {
+  return getSymbolName(LHS).str().compare(getSymbolName(RHS).str()) < 0;
+}
+
+bool MachODumper::compareSymbolsByType(SymbolRef LHS, SymbolRef RHS) const {
+  return getSymbolType(LHS) < getSymbolType(RHS);
+}
+
+void MachODumper::printSymbols() { printSymbols(None); }
 
-  for (const SymbolRef &Symbol : Obj->symbols()) {
-    printSymbol(Symbol);
+void MachODumper::printSymbols(Optional<SymbolComparator> SymComp) {
+  ListScope Group(W, "Symbols");
+  if (SymComp) {
+    auto SymbolRange = Obj->symbols();
+    std::vector<SymbolRef> SortedSymbols(SymbolRange.begin(),
+                                         SymbolRange.end());
+    llvm::stable_sort(SortedSymbols, *SymComp);
+    for (SymbolRef Symbol : SortedSymbols)
+      printSymbol(Symbol);
+  } else {
+    for (const SymbolRef &Symbol : Obj->symbols()) {
+      printSymbol(Symbol);
+    }
   }
 }
 
 void MachODumper::printDynamicSymbols() {
   ListScope Group(W, "DynamicSymbols");
 }
+void MachODumper::printDynamicSymbols(Optional<SymbolComparator> SymComp) {
+  ListScope Group(W, "DynamicSymbols");
+}
 
 void MachODumper::printSymbol(const SymbolRef &Symbol) {
+  printSymbol(Symbol, W);
+}
+
+void MachODumper::printSymbol(const SymbolRef &Symbol, ScopedPrinter &W) {
   StringRef SymbolName = getSymbolName(Symbol);
 
   MachOSymbol MOSymbol;

diff  --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index a09a243d381ec..c1edf981cf2a6 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -12,6 +12,10 @@
 #include <memory>
 #include <system_error>
 
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/CommandLine.h"
@@ -25,7 +29,7 @@ class COFFImportFile;
 class ObjectFile;
 class XCOFFObjectFile;
 class ELFObjectFileBase;
-}
+} // namespace object
 namespace codeview {
 class GlobalTypeTableBuilder;
 class MergingTypeTableBuilder;
@@ -33,6 +37,33 @@ class MergingTypeTableBuilder;
 
 class ScopedPrinter;
 
+// Comparator to compare symbols.
+// Usage: the caller registers predicates (i.e., how to compare the symbols) by
+// calling addPredicate(). The order in which predicates are registered is also
+// their priority.
+class SymbolComparator {
+public:
+  using CompPredicate =
+      function_ref<bool(object::SymbolRef, object::SymbolRef)>;
+
+  // Each Obj format has a slightly 
diff erent way of retrieving a symbol's info
+  // So we defer the predicate's impl to each format.
+  void addPredicate(CompPredicate Pred) { Predicates.push_back(Pred); }
+
+  bool operator()(object::SymbolRef LHS, object::SymbolRef RHS) {
+    for (CompPredicate Pred : Predicates) {
+      if (Pred(LHS, RHS))
+        return true;
+      if (Pred(RHS, LHS))
+        return false;
+    }
+    return false;
+  }
+
+private:
+  SmallVector<CompPredicate, 2> Predicates;
+};
+
 class ObjDumper {
 public:
   ObjDumper(ScopedPrinter &Writer, StringRef ObjName);
@@ -52,6 +83,17 @@ class ObjDumper {
     if (PrintDynamicSymbols)
       printDynamicSymbols();
   }
+  virtual void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols,
+                            llvm::Optional<SymbolComparator> SymComp) {
+    if (SymComp) {
+      if (PrintSymbols)
+        printSymbols(SymComp);
+      if (PrintDynamicSymbols)
+        printDynamicSymbols(SymComp);
+    } else {
+      printSymbols(PrintSymbols, PrintDynamicSymbols);
+    }
+  }
   virtual void printProgramHeaders(bool PrintProgramHeaders,
                                    cl::boolOrDefault PrintSectionMapping) {
     if (PrintProgramHeaders)
@@ -62,6 +104,17 @@ class ObjDumper {
 
   virtual void printUnwindInfo() = 0;
 
+  // Symbol comparison functions.
+  virtual bool canCompareSymbols() const { return false; }
+  virtual bool compareSymbolsByName(object::SymbolRef LHS,
+                                    object::SymbolRef RHS) const {
+    return true;
+  }
+  virtual bool compareSymbolsByType(object::SymbolRef LHS,
+                                    object::SymbolRef RHS) const {
+    return true;
+  }
+
   // Only implemented for ELF at this time.
   virtual void printDependentLibs() {}
   virtual void printDynamicRelocations() { }
@@ -133,7 +186,9 @@ class ObjDumper {
 
 private:
   virtual void printSymbols() {}
+  virtual void printSymbols(llvm::Optional<SymbolComparator> Comp) {}
   virtual void printDynamicSymbols() {}
+  virtual void printDynamicSymbols(llvm::Optional<SymbolComparator> Comp) {}
   virtual void printProgramHeaders() {}
   virtual void printSectionMapping() {}
 

diff  --git a/llvm/tools/llvm-readobj/Opts.td b/llvm/tools/llvm-readobj/Opts.td
index 528c7f64e2234..4687fc71245f8 100644
--- a/llvm/tools/llvm-readobj/Opts.td
+++ b/llvm/tools/llvm-readobj/Opts.td
@@ -37,6 +37,7 @@ def section_mapping : FF<"section-mapping", "Display the section to segment mapp
 def section_mapping_EQ_false : FF<"section-mapping=false", "Don't display the section to segment mapping">, Flags<[HelpHidden]>;
 def section_relocations : FF<"section-relocations", "Display relocations for each section shown. This option has no effect for GNU style output">;
 def section_symbols : FF<"section-symbols", "Display symbols for each section shown. This option has no effect for GNU style output">;
+defm sort_symbols : Eq<"sort-symbols", "Specify the keys to sort the symbols before displaying symtab">;
 def stack_sizes : FF<"stack-sizes", "Display contents of all stack sizes sections. This option has no effect for GNU style output">;
 def stackmap : FF<"stackmap", "Display contents of stackmap section">;
 defm string_dump : Eq<"string-dump", "Display the specified section(s) as a list of strings">, MetaVarName<"<name or index>">;

diff  --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index 543b0de82cdf6..e1ebbeb41f28b 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -21,6 +21,7 @@
 #include "llvm-readobj.h"
 #include "ObjDumper.h"
 #include "WindowsResourceDumper.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
 #include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
 #include "llvm/MC/TargetRegistry.h"
@@ -83,6 +84,14 @@ class ReadobjOptTable : public opt::OptTable {
 };
 
 enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols };
+
+enum SortSymbolKeyTy {
+  NAME = 0,
+  TYPE = 1,
+  UNKNOWN = 100,
+  // TODO: add ADDRESS, SIZE as needed.
+};
+
 } // namespace
 
 namespace opts {
@@ -113,6 +122,7 @@ static bool StringTable;
 static bool Symbols;
 static bool UnwindInfo;
 static cl::boolOrDefault SectionMapping;
+static SmallVector<SortSymbolKeyTy> SortKeys;
 
 // ELF specific options.
 static bool DynamicTable;
@@ -253,6 +263,19 @@ static void parseOptions(const opt::InputArgList &Args) {
   opts::ProgramHeaders = Args.hasArg(OPT_program_headers);
   opts::RawRelr = Args.hasArg(OPT_raw_relr);
   opts::SectionGroups = Args.hasArg(OPT_section_groups);
+  if (Arg *A = Args.getLastArg(OPT_sort_symbols_EQ)) {
+    std::string SortKeysString = A->getValue();
+    for (StringRef KeyStr : llvm::split(A->getValue(), ",")) {
+      SortSymbolKeyTy KeyType = StringSwitch<SortSymbolKeyTy>(KeyStr)
+                                    .Case("name", SortSymbolKeyTy::NAME)
+                                    .Case("type", SortSymbolKeyTy::TYPE)
+                                    .Default(SortSymbolKeyTy::UNKNOWN);
+      if (KeyType == SortSymbolKeyTy::UNKNOWN)
+        error("--sort-symbols value should be 'name' or 'type', but was '" +
+              Twine(KeyStr) + "'");
+      opts::SortKeys.push_back(KeyType);
+    }
+  }
   opts::VersionInfo = Args.hasArg(OPT_version_info);
 
   // Mach-O specific options.
@@ -334,11 +357,39 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
                        toString(std::move(ContentErr));
 
   ObjDumper *Dumper;
+  Optional<SymbolComparator> SymComp;
   Expected<std::unique_ptr<ObjDumper>> DumperOrErr = createDumper(Obj, Writer);
   if (!DumperOrErr)
     reportError(DumperOrErr.takeError(), FileStr);
   Dumper = (*DumperOrErr).get();
 
+  if (!opts::SortKeys.empty()) {
+    if (Dumper->canCompareSymbols()) {
+      SymComp = SymbolComparator();
+      for (SortSymbolKeyTy Key : opts::SortKeys) {
+        switch (Key) {
+        case NAME:
+          SymComp->addPredicate([Dumper](SymbolRef LHS, SymbolRef RHS) {
+            return Dumper->compareSymbolsByName(LHS, RHS);
+          });
+          break;
+        case TYPE:
+          SymComp->addPredicate([Dumper](SymbolRef LHS, SymbolRef RHS) {
+            return Dumper->compareSymbolsByType(LHS, RHS);
+          });
+          break;
+        case UNKNOWN:
+          llvm_unreachable("Unsupported sort key");
+        }
+      }
+
+    } else {
+      reportWarning(createStringError(
+                        errc::invalid_argument,
+                        "--sort-symbols is not supported yet for this format"),
+                    FileStr);
+    }
+  }
   Dumper->printFileSummary(FileStr, Obj, opts::InputFilenames, A);
 
   if (opts::FileHeaders)
@@ -374,7 +425,7 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
   if (opts::UnwindInfo)
     Dumper->printUnwindInfo();
   if (opts::Symbols || opts::DynamicSymbols)
-    Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols);
+    Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols, SymComp);
   if (!opts::StringDump.empty())
     Dumper->printSectionsAsString(Obj, opts::StringDump);
   if (!opts::HexDump.empty())

diff  --git a/llvm/tools/llvm-readobj/llvm-readobj.h b/llvm/tools/llvm-readobj/llvm-readobj.h
index 0ea695d1673d1..989cd0aba6c01 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.h
+++ b/llvm/tools/llvm-readobj/llvm-readobj.h
@@ -9,10 +9,13 @@
 #ifndef LLVM_TOOLS_LLVM_READOBJ_LLVM_READOBJ_H
 #define LLVM_TOOLS_LLVM_READOBJ_LLVM_READOBJ_H
 
+#include "ObjDumper.h"
+
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compiler.h"
-#include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
 #include <string>
 
 namespace llvm {


        


More information about the llvm-commits mailing list