[elfabi] Add support for reading dynamic symbols from binaries

This patch adds initial support for reading dynamic symbols from ELF binaries. Currently, STT_NOTYPE, STT_OBJECT, STT_FUNC, and STT_TLS are explicitly supported. Other symbol types are mapped to ELFSymbolType::Unknown to improve signal/noise ratio.

Symbols must meet two criteria to be read into in an ELFStub:

 - The symbol's binding must be STB_GLOBAL or STB_WEAK.
 - The symbol's visibility must be STV_DEFAULT or STV_PROTECTED.

This filters out symbols that aren't of interest during compile-time linking against a shared object.

This change uses DT_HASH and DT_GNU_HASH to determine the size of .dynsym. Using hash tables to determine the number of symbols in .dynsym allows llvm-elfabi to work on binaries without relying on section headers.

Differential Revision: https://reviews.llvm.org/D56031

llvm-svn: 352121
diff --git a/llvm/test/tools/llvm-elfabi/Inputs/gnu_hash.so b/llvm/test/tools/llvm-elfabi/Inputs/gnu_hash.so
new file mode 100755
index 0000000..3970e58
--- /dev/null
+++ b/llvm/test/tools/llvm-elfabi/Inputs/gnu_hash.so
Binary files differ
diff --git a/llvm/test/tools/llvm-elfabi/Inputs/sysv_hash.so b/llvm/test/tools/llvm-elfabi/Inputs/sysv_hash.so
new file mode 100755
index 0000000..46b3b2a
--- /dev/null
+++ b/llvm/test/tools/llvm-elfabi/Inputs/sysv_hash.so
Binary files differ
diff --git a/llvm/test/tools/llvm-elfabi/binary-read-add-soname.test b/llvm/test/tools/llvm-elfabi/binary-read-add-soname.test
index dbc5a00..49c37ef 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-add-soname.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-add-soname.test
@@ -18,11 +18,12 @@
     Flags:           [ SHF_ALLOC ]
     Address:         0x0008
     AddressAlign:    8
-    Content:         "0a0000000000000001000000000000000500000000000000000000000000000000000000000000000000000000000000"
+    Content:         "0a000000000000000100000000000000050000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000"
       # DT_STRSZ      1 (0x1)
       # DT_STRTAB     0x0
+      # DT_SYMTAB     0x0
       # DT_NULL       0x0
-    Size:            48
+    Size:            64
     Link:            .dynstr
 ProgramHeaders:
   - Type: PT_LOAD
diff --git a/llvm/test/tools/llvm-elfabi/binary-read-arch.test b/llvm/test/tools/llvm-elfabi/binary-read-arch.test
index f2c2d8b..23f99a3 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-arch.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-arch.test
@@ -18,11 +18,12 @@
     Flags:           [ SHF_ALLOC ]
     Address:         0x0008
     AddressAlign:    8
-    Content:         "0a0000000000000001000000000000000500000000000000000000000000000000000000000000000000000000000000"
+    Content:         "0a000000000000000100000000000000050000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000"
       # DT_STRSZ      1 (0x1)
       # DT_STRTAB     0x0
+      # DT_SYMTAB     0x0
       # DT_NULL       0x0
-    Size:            48
+    Size:            64
     Link:            .dynstr
 ProgramHeaders:
   - Type: PT_LOAD
diff --git a/llvm/test/tools/llvm-elfabi/binary-read-bad-soname.test b/llvm/test/tools/llvm-elfabi/binary-read-bad-soname.test
index cc7205b..e0e6ac2 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-bad-soname.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-bad-soname.test
@@ -18,12 +18,13 @@
     Flags:           [ SHF_ALLOC ]
     Address:         0x0008
     AddressAlign:    8
-    Content:         "0e000000000000000d000000000000000a0000000000000001000000000000000500000000000000000000000000000000000000000000000000000000000000"
+    Content:         "0e000000000000000d000000000000000a000000000000000100000000000000050000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000"
       # DT_SONAME     13 (0x0d)
       # DT_STRSZ      1 (0x01)
       # DT_STRTAB     0x0
+      # DT_SYMTAB     0x0
       # DT_NULL       0x0
-    Size:            64
+    Size:            80
     Link:            .dynstr
 ProgramHeaders:
   - Type: PT_LOAD
diff --git a/llvm/test/tools/llvm-elfabi/binary-read-bad-vaddr.test b/llvm/test/tools/llvm-elfabi/binary-read-bad-vaddr.test
index 5dc96df..03d453c 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-bad-vaddr.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-bad-vaddr.test
@@ -18,12 +18,13 @@
     Flags:           [ SHF_ALLOC ]
     Address:         0x1008
     AddressAlign:    8
-    Content:         "0e0000000000000000000000000000000a0000000000000001000000000000000500000000000000600200000000000000000000000000000000000000000000"
+    Content:         "0e0000000000000000000000000000000a000000000000000100000000000000050000000000000060020000000000000600000000000000001000000000000000000000000000000000000000000000"
       # DT_SONAME     0
       # DT_STRSZ      1
       # DT_STRTAB     0x0260 # Bad vaddr (no PT_LOAD for 0x0000 to 0x0FFF)
+      # DT_SYMTAB     0x1000
       # DT_NULL       0x0
-    Size:            64
+    Size:            80
     Link:            .dynstr
 ProgramHeaders:
   - Type: PT_LOAD
diff --git a/llvm/test/tools/llvm-elfabi/binary-read-neededlibs-bad-offset.test b/llvm/test/tools/llvm-elfabi/binary-read-neededlibs-bad-offset.test
index 439ca5c..e76aa5d 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-neededlibs-bad-offset.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-neededlibs-bad-offset.test
@@ -18,15 +18,16 @@
     Type:            SHT_DYNAMIC
     Flags:           [ SHF_ALLOC ]
     Address:         0x1024
-    Content:         "010000000000000001000000000000000e0000000000000015000000000000000100000000000000ffff0000000000000a0000000000000024000000000000000500000000000000001000000000000000000000000000000000000000000000"
+    Content:         "010000000000000001000000000000000e0000000000000015000000000000000100000000000000ffff0000000000000a000000000000002400000000000000050000000000000000100000000000000600000000000000001000000000000000000000000000000000000000000000"
       # DT_NEEDED     1 (0x01)
       # DT_SONAME     21 (0x15)
       # Bad DT_NEEDED entry (offset outside string table):
       # DT_NEEDED     65535 (0xffff)
       # DT_STRSZ      36 (0x24)
       # DT_STRTAB     0x1000
+      # DT_SYMTAB     0x1000
       # DT_NULL       0x0
-    Size:            96
+    Size:            112
 ProgramHeaders:
   - Type: PT_LOAD
     Flags: [ PF_R ]
diff --git a/llvm/test/tools/llvm-elfabi/binary-read-neededlibs.test b/llvm/test/tools/llvm-elfabi/binary-read-neededlibs.test
index 4245d19..48149950 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-neededlibs.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-neededlibs.test
@@ -18,14 +18,15 @@
     Type:            SHT_DYNAMIC
     Flags:           [ SHF_ALLOC ]
     Address:         0x1024
-    Content:         "010000000000000001000000000000000e00000000000000150000000000000001000000000000000b000000000000000a0000000000000024000000000000000500000000000000001000000000000000000000000000000000000000000000"
+    Content:         "010000000000000001000000000000000e00000000000000150000000000000001000000000000000b000000000000000a000000000000002400000000000000050000000000000000100000000000000600000000000000001000000000000000000000000000000000000000000000"
       # DT_NEEDED     1 (0x01)
       # DT_SONAME     21 (0x15)
       # DT_NEEDED     11 (0x0b)
       # DT_STRSZ      36 (0x24)
       # DT_STRTAB     0x1000
+      # DT_SYMTAB     0x1000
       # DT_NULL       0x0
-    Size:            96
+    Size:            112
 ProgramHeaders:
   - Type: PT_LOAD
     Flags: [ PF_R ]
diff --git a/llvm/test/tools/llvm-elfabi/binary-read-replace-soname.test b/llvm/test/tools/llvm-elfabi/binary-read-replace-soname.test
index 23f0ba3..da3427d 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-replace-soname.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-replace-soname.test
@@ -20,12 +20,13 @@
     Flags:           [ SHF_ALLOC ]
     Address:         0x1018
     AddressAlign:    8
-    Content:         "0e0000000000000005000000000000000a0000000000000014000000000000000500000000000000001000000000000000000000000000000000000000000000"
+    Content:         "0e0000000000000005000000000000000a000000000000001400000000000000050000000000000000100000000000000600000000000000001000000000000000000000000000000000000000000000"
       # DT_SONAME     5 (0x05)
       # DT_STRSZ      20 (0x14)
       # DT_STRTAB     0x1000
+      # DT_SYMTAB     0x1000
       # DT_NULL       0x0
-    Size:            64
+    Size:            80
     Link:            .dynstr
 ProgramHeaders:
   - Type: PT_LOAD
diff --git a/llvm/test/tools/llvm-elfabi/binary-read-soname-no-null.test b/llvm/test/tools/llvm-elfabi/binary-read-soname-no-null.test
index 224407d..f474878 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-soname-no-null.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-soname-no-null.test
@@ -19,12 +19,13 @@
     Flags:           [ SHF_ALLOC ]
     Address:         0x1018
     AddressAlign:    8
-    Content:         "0e0000000000000005000000000000000a000000000000000f000000000000000500000000000000001000000000000000000000000000000000000000000000"
+    Content:         "0e0000000000000005000000000000000a000000000000000f00000000000000050000000000000000100000000000000600000000000000001000000000000000000000000000000000000000000000"
       # DT_SONAME     5 (0x05)
       # DT_STRSZ      15 (0x0F)
       # DT_STRTAB     0x1000
+      # DT_SYMTAB     0x1000
       # DT_NULL       0x0
-    Size:            64
+    Size:            80
     Link:            .dynstr
 ProgramHeaders:
   - Type: PT_LOAD
diff --git a/llvm/test/tools/llvm-elfabi/binary-read-soname.test b/llvm/test/tools/llvm-elfabi/binary-read-soname.test
index b6877c6..61e8fcf 100644
--- a/llvm/test/tools/llvm-elfabi/binary-read-soname.test
+++ b/llvm/test/tools/llvm-elfabi/binary-read-soname.test
@@ -19,12 +19,13 @@
     Flags:           [ SHF_ALLOC ]
     Address:         0x1018
     AddressAlign:    8
-    Content:         "0e0000000000000005000000000000000a0000000000000014000000000000000500000000000000001000000000000000000000000000000000000000000000"
+    Content:         "0e0000000000000005000000000000000a000000000000001400000000000000050000000000000000100000000000000600000000000000001000000000000000000000000000000000000000000000"
       # DT_SONAME     5 (0x05)
       # DT_STRSZ      20 (0x14)
       # DT_STRTAB     0x1000
+      # DT_SYMTAB     0x1000
       # DT_NULL       0x0
-    Size:            64
+    Size:            80
     Link:            .dynstr
 ProgramHeaders:
   - Type: PT_LOAD
diff --git a/llvm/test/tools/llvm-elfabi/binary-read-syms-gnu-hash.test b/llvm/test/tools/llvm-elfabi/binary-read-syms-gnu-hash.test
new file mode 100644
index 0000000..777f271
--- /dev/null
+++ b/llvm/test/tools/llvm-elfabi/binary-read-syms-gnu-hash.test
@@ -0,0 +1,22 @@
+# RUN: llvm-elfabi --elf %p/Inputs/gnu_hash.so --emit-tbe=- | FileCheck %s
+
+# CHECK:      --- !tapi-tbe
+# CHECK-NEXT: TbeVersion:      1.0
+# CHECK-NEXT: SoName:          libsomething.so
+# CHECK-NEXT: Arch:            x86_64
+# CHECK-NEXT: NeededLibs:
+# CHECK-NEXT:   - libm.so.6
+# CHECK-NEXT:   - libc.so.6
+# CHECK-NEXT:   - ld-linux-x86-64.so.2
+# CHECK-NEXT: Symbols:
+# CHECK-NEXT:   AGlobalInteger:  { Type: Object, Size: 4 }
+# CHECK-NEXT:   AThreadLocalLongInteger: { Type: TLS, Size: 8 }
+# CHECK-NEXT:   _ITM_deregisterTMCloneTable: { Type: NoType, Undefined: true, Weak: true }
+# CHECK-NEXT:   _ITM_registerTMCloneTable: { Type: NoType, Undefined: true, Weak: true }
+# CHECK-NEXT:   _Z11rotateArrayPii: { Type: Func }
+# CHECK-NEXT:   __cxa_finalize:  { Type: Func, Undefined: true, Weak: true }
+# CHECK-NEXT:   __gmon_start__:  { Type: NoType, Undefined: true, Weak: true }
+# CHECK-NEXT:   __tls_get_addr:  { Type: Func, Undefined: true }
+# CHECK-NEXT:   _fini:           { Type: Func }
+# CHECK-NEXT:   _init:           { Type: Func }
+# CHECK-NEXT: ...
diff --git a/llvm/test/tools/llvm-elfabi/binary-read-syms-sysv-hash.test b/llvm/test/tools/llvm-elfabi/binary-read-syms-sysv-hash.test
new file mode 100644
index 0000000..0f29085
--- /dev/null
+++ b/llvm/test/tools/llvm-elfabi/binary-read-syms-sysv-hash.test
@@ -0,0 +1,22 @@
+# RUN: llvm-elfabi --elf %p/Inputs/sysv_hash.so --emit-tbe=- | FileCheck %s
+
+# CHECK:      --- !tapi-tbe
+# CHECK-NEXT: TbeVersion:      1.0
+# CHECK-NEXT: SoName:          libsomething.so
+# CHECK-NEXT: Arch:            x86_64
+# CHECK-NEXT: NeededLibs:
+# CHECK-NEXT:   - libm.so.6
+# CHECK-NEXT:   - libc.so.6
+# CHECK-NEXT:   - ld-linux-x86-64.so.2
+# CHECK-NEXT: Symbols:
+# CHECK-NEXT:   AGlobalInteger:  { Type: Object, Size: 4 }
+# CHECK-NEXT:   AThreadLocalLongInteger: { Type: TLS, Size: 8 }
+# CHECK-NEXT:   _ITM_deregisterTMCloneTable: { Type: NoType, Undefined: true, Weak: true }
+# CHECK-NEXT:   _ITM_registerTMCloneTable: { Type: NoType, Undefined: true, Weak: true }
+# CHECK-NEXT:   _Z11rotateArrayPii: { Type: Func }
+# CHECK-NEXT:   __cxa_finalize:  { Type: Func, Undefined: true, Weak: true }
+# CHECK-NEXT:   __gmon_start__:  { Type: NoType, Undefined: true, Weak: true }
+# CHECK-NEXT:   __tls_get_addr:  { Type: Func, Undefined: true }
+# CHECK-NEXT:   _fini:           { Type: Func }
+# CHECK-NEXT:   _init:           { Type: Func }
+# CHECK-NEXT: ...