You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

826 lines
32 KiB

  1. // Copyright 2018 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // +build go1.7
  15. package elf
  16. import (
  17. "bytes"
  18. "compress/gzip"
  19. "encoding/binary"
  20. "io"
  21. "math/rand"
  22. "net"
  23. "os"
  24. "path"
  25. "reflect"
  26. "runtime"
  27. "testing"
  28. "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf"
  29. )
  30. type fileTest struct {
  31. file string
  32. hdr FileHeader
  33. sections []SectionHeader
  34. progs []ProgHeader
  35. needed []string
  36. }
  37. var fileTests = []fileTest{
  38. {
  39. "testdata/gcc-386-freebsd-exec",
  40. FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386, 0x80483cc},
  41. []SectionHeader{
  42. {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  43. {".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0, 0x15},
  44. {".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4, 0x90},
  45. {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10, 0x110},
  46. {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0, 0xbb},
  47. {".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8, 0x20},
  48. {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11},
  49. {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4, 0x50},
  50. {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0, 0x180},
  51. {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc},
  52. {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0, 0xa3},
  53. {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc},
  54. {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4},
  55. {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8, 0x98},
  56. {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
  57. {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
  58. {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4},
  59. {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4, 0x1c},
  60. {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20},
  61. {".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0, 0x12d},
  62. {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20},
  63. {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b},
  64. {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0, 0x11d},
  65. {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0, 0x41},
  66. {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0, 0x35},
  67. {".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0, 0x30},
  68. {".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
  69. {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0, 0xf8},
  70. {".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10, 0x4b0},
  71. {".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0, 0x206},
  72. },
  73. []ProgHeader{
  74. {PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4},
  75. {PT_INTERP, PF_R, 0xd4, 0x80480d4, 0x80480d4, 0x15, 0x15, 0x1},
  76. {PT_LOAD, PF_R + PF_X, 0x0, 0x8048000, 0x8048000, 0x5fb, 0x5fb, 0x1000},
  77. {PT_LOAD, PF_R + PF_W, 0x5fc, 0x80495fc, 0x80495fc, 0xd8, 0xf8, 0x1000},
  78. {PT_DYNAMIC, PF_R + PF_W, 0x60c, 0x804960c, 0x804960c, 0x98, 0x98, 0x4},
  79. },
  80. []string{"libc.so.6"},
  81. },
  82. {
  83. "testdata/gcc-amd64-linux-exec",
  84. FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64, 0x4003e0},
  85. []SectionHeader{
  86. {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  87. {".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0, 0x1c},
  88. {".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20},
  89. {".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4, 0x24},
  90. {".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0, 0x1c},
  91. {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18, 0x60},
  92. {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0, 0x3d},
  93. {".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2, 0x8},
  94. {".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0, 0x20},
  95. {".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18, 0x18},
  96. {".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18, 0x30},
  97. {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0, 0x18},
  98. {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10, 0x30},
  99. {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0, 0x1b4},
  100. {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0, 0xe},
  101. {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11},
  102. {".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0, 0x24},
  103. {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0, 0xa4},
  104. {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10},
  105. {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10},
  106. {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0, 0x8},
  107. {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10, 0x1a0},
  108. {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8, 0x8},
  109. {".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8, 0x28},
  110. {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0, 0x18},
  111. {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
  112. {".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0, 0x126},
  113. {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90},
  114. {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0, 0x25},
  115. {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0, 0x1a7},
  116. {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0, 0x6f},
  117. {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0, 0x13f},
  118. {".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1, 0xb1},
  119. {".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90},
  120. {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0, 0x149},
  121. {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18, 0x6f0},
  122. {".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0, 0x1fc},
  123. },
  124. []ProgHeader{
  125. {PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8},
  126. {PT_INTERP, PF_R, 0x200, 0x400200, 0x400200, 0x1c, 0x1c, 1},
  127. {PT_LOAD, PF_R + PF_X, 0x0, 0x400000, 0x400000, 0x684, 0x684, 0x200000},
  128. {PT_LOAD, PF_R + PF_W, 0x688, 0x600688, 0x600688, 0x210, 0x218, 0x200000},
  129. {PT_DYNAMIC, PF_R + PF_W, 0x6b0, 0x6006b0, 0x6006b0, 0x1a0, 0x1a0, 0x8},
  130. {PT_NOTE, PF_R, 0x21c, 0x40021c, 0x40021c, 0x20, 0x20, 0x4},
  131. {PT_LOOS + 0x474E550, PF_R, 0x5b8, 0x4005b8, 0x4005b8, 0x24, 0x24, 0x4},
  132. {PT_LOOS + 0x474E551, PF_R + PF_W, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8},
  133. },
  134. []string{"libc.so.6"},
  135. },
  136. {
  137. "testdata/hello-world-core.gz",
  138. FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_CORE, EM_X86_64, 0x0},
  139. []SectionHeader{},
  140. []ProgHeader{
  141. {Type: PT_NOTE, Flags: 0x0, Off: 0x3f8, Vaddr: 0x0, Paddr: 0x0, Filesz: 0x8ac, Memsz: 0x0, Align: 0x0},
  142. {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x1000, Vaddr: 0x400000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1000, Align: 0x1000},
  143. {Type: PT_LOAD, Flags: PF_R, Off: 0x1000, Vaddr: 0x401000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
  144. {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x2000, Vaddr: 0x402000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
  145. {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3000, Vaddr: 0x7f54078b8000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1b5000, Align: 0x1000},
  146. {Type: PT_LOAD, Flags: 0x0, Off: 0x3000, Vaddr: 0x7f5407a6d000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1ff000, Align: 0x1000},
  147. {Type: PT_LOAD, Flags: PF_R, Off: 0x3000, Vaddr: 0x7f5407c6c000, Paddr: 0x0, Filesz: 0x4000, Memsz: 0x4000, Align: 0x1000},
  148. {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x7000, Vaddr: 0x7f5407c70000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
  149. {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x9000, Vaddr: 0x7f5407c72000, Paddr: 0x0, Filesz: 0x5000, Memsz: 0x5000, Align: 0x1000},
  150. {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0xe000, Vaddr: 0x7f5407c77000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x22000, Align: 0x1000},
  151. {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0xe000, Vaddr: 0x7f5407e81000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
  152. {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x11000, Vaddr: 0x7f5407e96000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
  153. {Type: PT_LOAD, Flags: PF_R, Off: 0x14000, Vaddr: 0x7f5407e99000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
  154. {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x15000, Vaddr: 0x7f5407e9a000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
  155. {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x17000, Vaddr: 0x7fff79972000, Paddr: 0x0, Filesz: 0x23000, Memsz: 0x23000, Align: 0x1000},
  156. {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3a000, Vaddr: 0x7fff799f8000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
  157. {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3b000, Vaddr: 0xffffffffff600000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
  158. },
  159. nil,
  160. },
  161. {
  162. "testdata/compressed-32.obj",
  163. FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_386, 0x0},
  164. []SectionHeader{
  165. {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  166. {".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x34, 0x17, 0x0, 0x0, 0x1, 0x0, 0x17},
  167. {".rel.text", SHT_REL, SHF_INFO_LINK, 0x0, 0x3dc, 0x10, 0x13, 0x1, 0x4, 0x8, 0x10},
  168. {".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
  169. {".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
  170. {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x4b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
  171. {".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x58, 0xb4, 0x0, 0x0, 0x1, 0x0, 0x84},
  172. {".rel.debug_info", SHT_REL, SHF_INFO_LINK, 0x0, 0x3ec, 0xa0, 0x13, 0x6, 0x4, 0x8, 0xa0},
  173. {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xdc, 0x5a, 0x0, 0x0, 0x1, 0x0, 0x5a},
  174. {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x136, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20},
  175. {".rel.debug_aranges", SHT_REL, SHF_INFO_LINK, 0x0, 0x48c, 0x10, 0x13, 0x9, 0x4, 0x8, 0x10},
  176. {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x156, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c},
  177. {".rel.debug_line", SHT_REL, SHF_INFO_LINK, 0x0, 0x49c, 0x8, 0x13, 0xb, 0x4, 0x8, 0x8},
  178. {".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1b2, 0x10f, 0x0, 0x0, 0x1, 0x1, 0xb3},
  179. {".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x265, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a},
  180. {".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x28f, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
  181. {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x290, 0x38, 0x0, 0x0, 0x4, 0x0, 0x38},
  182. {".rel.eh_frame", SHT_REL, SHF_INFO_LINK, 0x0, 0x4a4, 0x8, 0x13, 0x10, 0x4, 0x8, 0x8},
  183. {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x4ac, 0xab, 0x0, 0x0, 0x1, 0x0, 0xab},
  184. {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2c8, 0x100, 0x14, 0xe, 0x4, 0x10, 0x100},
  185. {".strtab", SHT_STRTAB, 0x0, 0x0, 0x3c8, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13},
  186. },
  187. []ProgHeader{},
  188. nil,
  189. },
  190. {
  191. "testdata/compressed-64.obj",
  192. FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_X86_64, 0x0},
  193. []SectionHeader{
  194. {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  195. {".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x40, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b},
  196. {".rela.text", SHT_RELA, SHF_INFO_LINK, 0x0, 0x488, 0x30, 0x13, 0x1, 0x8, 0x18, 0x30},
  197. {".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
  198. {".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
  199. {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x5b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
  200. {".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x68, 0xba, 0x0, 0x0, 0x1, 0x0, 0x72},
  201. {".rela.debug_info", SHT_RELA, SHF_INFO_LINK, 0x0, 0x4b8, 0x1c8, 0x13, 0x6, 0x8, 0x18, 0x1c8},
  202. {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xda, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c},
  203. {".debug_aranges", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x136, 0x30, 0x0, 0x0, 0x1, 0x0, 0x2f},
  204. {".rela.debug_aranges", SHT_RELA, SHF_INFO_LINK, 0x0, 0x680, 0x30, 0x13, 0x9, 0x8, 0x18, 0x30},
  205. {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x165, 0x60, 0x0, 0x0, 0x1, 0x0, 0x60},
  206. {".rela.debug_line", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6b0, 0x18, 0x13, 0xb, 0x8, 0x18, 0x18},
  207. {".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1c5, 0x104, 0x0, 0x0, 0x1, 0x1, 0xc3},
  208. {".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x288, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a},
  209. {".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x2b2, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
  210. {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x2b8, 0x38, 0x0, 0x0, 0x8, 0x0, 0x38},
  211. {".rela.eh_frame", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6c8, 0x18, 0x13, 0x10, 0x8, 0x18, 0x18},
  212. {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x6e0, 0xb0, 0x0, 0x0, 0x1, 0x0, 0xb0},
  213. {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2f0, 0x180, 0x14, 0xe, 0x8, 0x18, 0x180},
  214. {".strtab", SHT_STRTAB, 0x0, 0x0, 0x470, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13},
  215. },
  216. []ProgHeader{},
  217. nil,
  218. },
  219. }
  220. func TestOpen(t *testing.T) {
  221. for i := range fileTests {
  222. tt := &fileTests[i]
  223. var f *File
  224. var err error
  225. if path.Ext(tt.file) == ".gz" {
  226. var r io.ReaderAt
  227. if r, err = decompress(tt.file); err == nil {
  228. f, err = NewFile(r)
  229. }
  230. } else {
  231. f, err = Open(tt.file)
  232. }
  233. if err != nil {
  234. t.Errorf("cannot open file %s: %v", tt.file, err)
  235. continue
  236. }
  237. defer f.Close()
  238. if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
  239. t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
  240. continue
  241. }
  242. for i, s := range f.Sections {
  243. if i >= len(tt.sections) {
  244. break
  245. }
  246. sh := &tt.sections[i]
  247. if !reflect.DeepEqual(&s.SectionHeader, sh) {
  248. t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &s.SectionHeader, sh)
  249. }
  250. }
  251. for i, p := range f.Progs {
  252. if i >= len(tt.progs) {
  253. break
  254. }
  255. ph := &tt.progs[i]
  256. if !reflect.DeepEqual(&p.ProgHeader, ph) {
  257. t.Errorf("open %s, program %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &p.ProgHeader, ph)
  258. }
  259. }
  260. tn := len(tt.sections)
  261. fn := len(f.Sections)
  262. if tn != fn {
  263. t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
  264. }
  265. tn = len(tt.progs)
  266. fn = len(f.Progs)
  267. if tn != fn {
  268. t.Errorf("open %s: len(Progs) = %d, want %d", tt.file, fn, tn)
  269. }
  270. tl := tt.needed
  271. fl, err := f.ImportedLibraries()
  272. if err != nil {
  273. t.Error(err)
  274. }
  275. if !reflect.DeepEqual(tl, fl) {
  276. t.Errorf("open %s: DT_NEEDED = %v, want %v", tt.file, tl, fl)
  277. }
  278. }
  279. }
  280. // elf.NewFile requires io.ReaderAt, which compress/gzip cannot
  281. // provide. Decompress the file to a bytes.Reader.
  282. func decompress(gz string) (io.ReaderAt, error) {
  283. in, err := os.Open(gz)
  284. if err != nil {
  285. return nil, err
  286. }
  287. defer in.Close()
  288. r, err := gzip.NewReader(in)
  289. if err != nil {
  290. return nil, err
  291. }
  292. var out bytes.Buffer
  293. _, err = io.Copy(&out, r)
  294. return bytes.NewReader(out.Bytes()), err
  295. }
  296. type relocationTestEntry struct {
  297. entryNumber int
  298. entry *dwarf.Entry
  299. }
  300. type relocationTest struct {
  301. file string
  302. entries []relocationTestEntry
  303. }
  304. var relocationTests = []relocationTest{
  305. {
  306. "testdata/go-relocation-test-gcc441-x86-64.obj",
  307. []relocationTestEntry{
  308. {0, &dwarf.Entry{
  309. Offset: 0xb,
  310. Tag: dwarf.TagCompileUnit,
  311. Children: true,
  312. Field: []dwarf.Field{
  313. {Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"},
  314. {Attr: dwarf.AttrLanguage, Val: int64(1)},
  315. {Attr: dwarf.AttrName, Val: "go-relocation-test.c"},
  316. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  317. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  318. {Attr: dwarf.AttrHighpc, Val: uint64(0x6)},
  319. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  320. },
  321. }},
  322. },
  323. },
  324. {
  325. "testdata/go-relocation-test-gcc441-x86.obj",
  326. []relocationTestEntry{
  327. {0, &dwarf.Entry{
  328. Offset: 0xb,
  329. Tag: dwarf.TagCompileUnit,
  330. Children: true,
  331. Field: []dwarf.Field{
  332. {Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"},
  333. {Attr: dwarf.AttrLanguage, Val: int64(1)},
  334. {Attr: dwarf.AttrName, Val: "t.c"},
  335. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  336. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  337. {Attr: dwarf.AttrHighpc, Val: uint64(0x5)},
  338. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  339. },
  340. }},
  341. },
  342. },
  343. {
  344. "testdata/go-relocation-test-gcc424-x86-64.obj",
  345. []relocationTestEntry{
  346. {0, &dwarf.Entry{
  347. Offset: 0xb,
  348. Tag: dwarf.TagCompileUnit,
  349. Children: true,
  350. Field: []dwarf.Field{
  351. {Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"},
  352. {Attr: dwarf.AttrLanguage, Val: int64(1)},
  353. {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"},
  354. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  355. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  356. {Attr: dwarf.AttrHighpc, Val: uint64(0x6)},
  357. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  358. },
  359. }},
  360. },
  361. },
  362. {
  363. "testdata/go-relocation-test-gcc482-aarch64.obj",
  364. []relocationTestEntry{
  365. {0, &dwarf.Entry{
  366. Offset: 0xb,
  367. Tag: dwarf.TagCompileUnit,
  368. Children: true,
  369. Field: []dwarf.Field{
  370. {Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector"},
  371. {Attr: dwarf.AttrLanguage, Val: int64(1)},
  372. {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c"},
  373. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  374. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  375. {Attr: dwarf.AttrHighpc, Val: int64(0x24)},
  376. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  377. },
  378. }},
  379. },
  380. },
  381. {
  382. "testdata/go-relocation-test-gcc492-arm.obj",
  383. []relocationTestEntry{
  384. {0, &dwarf.Entry{
  385. Offset: 0xb,
  386. Tag: dwarf.TagCompileUnit,
  387. Children: true,
  388. Field: []dwarf.Field{
  389. {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 20141224 (prerelease) -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mtls-dialect=gnu -g"},
  390. {Attr: dwarf.AttrLanguage, Val: int64(1)},
  391. {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c"},
  392. {Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata"},
  393. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  394. {Attr: dwarf.AttrHighpc, Val: int64(0x28)},
  395. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  396. },
  397. }},
  398. },
  399. },
  400. {
  401. "testdata/go-relocation-test-clang-arm.obj",
  402. []relocationTestEntry{
  403. {0, &dwarf.Entry{
  404. Offset: 0xb,
  405. Tag: dwarf.TagCompileUnit,
  406. Children: true,
  407. Field: []dwarf.Field{
  408. {Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)"},
  409. {Attr: dwarf.AttrLanguage, Val: int64(12)},
  410. {Attr: dwarf.AttrName, Val: "hello.c"},
  411. {Attr: dwarf.AttrStmtList, Val: int64(0x0)},
  412. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  413. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  414. {Attr: dwarf.AttrHighpc, Val: int64(48)},
  415. },
  416. }},
  417. },
  418. },
  419. {
  420. "testdata/go-relocation-test-gcc5-ppc.obj",
  421. []relocationTestEntry{
  422. {0, &dwarf.Entry{
  423. Offset: 0xb,
  424. Tag: dwarf.TagCompileUnit,
  425. Children: true,
  426. Field: []dwarf.Field{
  427. {Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g"},
  428. {Attr: dwarf.AttrLanguage, Val: int64(12)},
  429. {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c"},
  430. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  431. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  432. {Attr: dwarf.AttrHighpc, Val: int64(0x44)},
  433. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  434. },
  435. }},
  436. },
  437. },
  438. {
  439. "testdata/go-relocation-test-gcc482-ppc64le.obj",
  440. []relocationTestEntry{
  441. {0, &dwarf.Entry{
  442. Offset: 0xb,
  443. Tag: dwarf.TagCompileUnit,
  444. Children: true,
  445. Field: []dwarf.Field{
  446. {Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector"},
  447. {Attr: dwarf.AttrLanguage, Val: int64(1)},
  448. {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c"},
  449. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  450. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  451. {Attr: dwarf.AttrHighpc, Val: uint64(0x24)},
  452. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  453. },
  454. }},
  455. },
  456. },
  457. {
  458. "testdata/go-relocation-test-gcc492-mips64.obj",
  459. []relocationTestEntry{
  460. {0, &dwarf.Entry{
  461. Offset: 0xb,
  462. Tag: dwarf.TagCompileUnit,
  463. Children: true,
  464. Field: []dwarf.Field{
  465. {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -meb -mabi=64 -march=mips3 -mtune=mips64 -mllsc -mno-shared -g"},
  466. {Attr: dwarf.AttrLanguage, Val: int64(1)},
  467. {Attr: dwarf.AttrName, Val: "hello.c"},
  468. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  469. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  470. {Attr: dwarf.AttrHighpc, Val: int64(100)},
  471. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  472. },
  473. }},
  474. },
  475. },
  476. {
  477. "testdata/go-relocation-test-gcc531-s390x.obj",
  478. []relocationTestEntry{
  479. {0, &dwarf.Entry{
  480. Offset: 0xb,
  481. Tag: dwarf.TagCompileUnit,
  482. Children: true,
  483. Field: []dwarf.Field{
  484. {Attr: dwarf.AttrProducer, Val: "GNU C11 5.3.1 20160316 -march=zEC12 -m64 -mzarch -g -fstack-protector-strong"},
  485. {Attr: dwarf.AttrLanguage, Val: int64(12)},
  486. {Attr: dwarf.AttrName, Val: "hello.c"},
  487. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  488. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  489. {Attr: dwarf.AttrHighpc, Val: int64(58)},
  490. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  491. },
  492. }},
  493. },
  494. },
  495. {
  496. "testdata/go-relocation-test-gcc620-sparc64.obj",
  497. []relocationTestEntry{
  498. {0, &dwarf.Entry{
  499. Offset: 0xb,
  500. Tag: dwarf.TagCompileUnit,
  501. Children: true,
  502. Field: []dwarf.Field{
  503. {Attr: dwarf.AttrProducer, Val: "GNU C11 6.2.0 20160914 -mcpu=v9 -g -fstack-protector-strong"},
  504. {Attr: dwarf.AttrLanguage, Val: int64(12)},
  505. {Attr: dwarf.AttrName, Val: "hello.c"},
  506. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  507. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  508. {Attr: dwarf.AttrHighpc, Val: int64(0x2c)},
  509. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  510. },
  511. }},
  512. },
  513. },
  514. {
  515. "testdata/go-relocation-test-gcc492-mipsle.obj",
  516. []relocationTestEntry{
  517. {0, &dwarf.Entry{
  518. Offset: 0xb,
  519. Tag: dwarf.TagCompileUnit,
  520. Children: true,
  521. Field: []dwarf.Field{
  522. {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -mel -march=mips2 -mtune=mips32 -mllsc -mno-shared -mabi=32 -g"},
  523. {Attr: dwarf.AttrLanguage, Val: int64(1)},
  524. {Attr: dwarf.AttrName, Val: "hello.c"},
  525. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  526. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  527. {Attr: dwarf.AttrHighpc, Val: int64(0x58)},
  528. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  529. },
  530. }},
  531. },
  532. },
  533. {
  534. "testdata/go-relocation-test-gcc540-mips.obj",
  535. []relocationTestEntry{
  536. {0, &dwarf.Entry{
  537. Offset: 0xb,
  538. Tag: dwarf.TagCompileUnit,
  539. Children: true,
  540. Field: []dwarf.Field{
  541. {Attr: dwarf.AttrProducer, Val: "GNU C11 5.4.0 20160609 -meb -mips32 -mtune=mips32r2 -mfpxx -mllsc -mno-shared -mabi=32 -g -gdwarf-2"},
  542. {Attr: dwarf.AttrLanguage, Val: int64(12)},
  543. {Attr: dwarf.AttrName, Val: "hello.c"},
  544. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  545. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  546. {Attr: dwarf.AttrHighpc, Val: uint64(0x5c)},
  547. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  548. },
  549. }},
  550. },
  551. },
  552. {
  553. "testdata/go-relocation-test-gcc493-mips64le.obj",
  554. []relocationTestEntry{
  555. {0, &dwarf.Entry{
  556. Offset: 0xb,
  557. Tag: dwarf.TagCompileUnit,
  558. Children: true,
  559. Field: []dwarf.Field{
  560. {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.3 -mel -mabi=64 -mllsc -mno-shared -g -fstack-protector-strong"},
  561. {Attr: dwarf.AttrLanguage, Val: int64(1)},
  562. {Attr: dwarf.AttrName, Val: "hello.c"},
  563. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  564. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  565. {Attr: dwarf.AttrHighpc, Val: int64(100)},
  566. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  567. },
  568. }},
  569. },
  570. },
  571. {
  572. "testdata/go-relocation-test-gcc720-riscv64.obj",
  573. []relocationTestEntry{
  574. {0, &dwarf.Entry{
  575. Offset: 0xb,
  576. Tag: dwarf.TagCompileUnit,
  577. Children: true,
  578. Field: []dwarf.Field{
  579. {Attr: dwarf.AttrProducer, Val: "GNU C11 7.2.0 -march=rv64imafdc -mabi=lp64d -g -gdwarf-2"},
  580. {Attr: dwarf.AttrLanguage, Val: int64(12)},
  581. {Attr: dwarf.AttrName, Val: "hello.c"},
  582. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  583. {Attr: dwarf.AttrLowpc, Val: uint64(0x0)},
  584. {Attr: dwarf.AttrHighpc, Val: uint64(0x2c)},
  585. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  586. },
  587. }},
  588. },
  589. },
  590. {
  591. "testdata/go-relocation-test-clang-x86.obj",
  592. []relocationTestEntry{
  593. {0, &dwarf.Entry{
  594. Offset: 0xb,
  595. Tag: dwarf.TagCompileUnit,
  596. Children: true,
  597. Field: []dwarf.Field{
  598. {Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)"},
  599. {Attr: dwarf.AttrLanguage, Val: int64(12)},
  600. {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c"},
  601. {Attr: dwarf.AttrStmtList, Val: int64(0)},
  602. {Attr: dwarf.AttrCompDir, Val: "/tmp"},
  603. },
  604. }},
  605. },
  606. },
  607. {
  608. "testdata/gcc-amd64-openbsd-debug-with-rela.obj",
  609. []relocationTestEntry{
  610. {203, &dwarf.Entry{
  611. Offset: 0xc62,
  612. Tag: dwarf.TagMember,
  613. Children: false,
  614. Field: []dwarf.Field{
  615. {Attr: dwarf.AttrName, Val: "it_interval"},
  616. {Attr: dwarf.AttrDeclFile, Val: int64(7)},
  617. {Attr: dwarf.AttrDeclLine, Val: int64(236)},
  618. {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)},
  619. {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}},
  620. },
  621. }},
  622. {204, &dwarf.Entry{
  623. Offset: 0xc70,
  624. Tag: dwarf.TagMember,
  625. Children: false,
  626. Field: []dwarf.Field{
  627. {Attr: dwarf.AttrName, Val: "it_value"},
  628. {Attr: dwarf.AttrDeclFile, Val: int64(7)},
  629. {Attr: dwarf.AttrDeclLine, Val: int64(237)},
  630. {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)},
  631. {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}},
  632. },
  633. }},
  634. },
  635. },
  636. }
  637. func TestDWARFRelocations(t *testing.T) {
  638. for i, test := range relocationTests {
  639. f, err := Open(test.file)
  640. if err != nil {
  641. t.Error(err)
  642. continue
  643. }
  644. dwarf, err := f.DWARF()
  645. if err != nil {
  646. t.Error(err)
  647. continue
  648. }
  649. for _, testEntry := range test.entries {
  650. reader := dwarf.Reader()
  651. for j := 0; j < testEntry.entryNumber; j++ {
  652. entry, err := reader.Next()
  653. if entry == nil || err != nil {
  654. t.Errorf("Failed to skip to entry %d: %v", testEntry.entryNumber, err)
  655. continue
  656. }
  657. }
  658. entry, err := reader.Next()
  659. if err != nil {
  660. t.Error(err)
  661. continue
  662. }
  663. if !reflect.DeepEqual(testEntry.entry, entry) {
  664. t.Errorf("#%d/%d: mismatch: got:%#v want:%#v", i, testEntry.entryNumber, entry, testEntry.entry)
  665. continue
  666. }
  667. }
  668. }
  669. }
  670. func TestCompressedDWARF(t *testing.T) {
  671. // Test file built with GCC 4.8.4 and as 2.24 using:
  672. // gcc -Wa,--compress-debug-sections -g -c -o zdebug-test-gcc484-x86-64.obj hello.c
  673. f, err := Open("testdata/zdebug-test-gcc484-x86-64.obj")
  674. if err != nil {
  675. t.Fatal(err)
  676. }
  677. dwarf, err := f.DWARF()
  678. if err != nil {
  679. t.Fatal(err)
  680. }
  681. reader := dwarf.Reader()
  682. n := 0
  683. for {
  684. entry, err := reader.Next()
  685. if err != nil {
  686. t.Fatal(err)
  687. }
  688. if entry == nil {
  689. break
  690. }
  691. n++
  692. }
  693. if n != 18 {
  694. t.Fatalf("want %d DWARF entries, got %d", 18, n)
  695. }
  696. }
  697. func TestCompressedSection(t *testing.T) {
  698. // Test files built with gcc -g -S hello.c and assembled with
  699. // --compress-debug-sections=zlib-gabi.
  700. f, err := Open("testdata/compressed-64.obj")
  701. if err != nil {
  702. t.Fatal(err)
  703. }
  704. sec := f.Section(".debug_info")
  705. wantData := []byte{
  706. 182, 0, 0, 0, 4, 0, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0,
  707. 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  708. 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 7,
  709. 0, 0, 0, 0, 2, 1, 8, 0, 0, 0, 0, 2, 2, 7, 0, 0,
  710. 0, 0, 2, 4, 7, 0, 0, 0, 0, 2, 1, 6, 0, 0, 0, 0,
  711. 2, 2, 5, 0, 0, 0, 0, 3, 4, 5, 105, 110, 116, 0, 2, 8,
  712. 5, 0, 0, 0, 0, 2, 8, 7, 0, 0, 0, 0, 4, 8, 114, 0,
  713. 0, 0, 2, 1, 6, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 4,
  714. 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0,
  715. 1, 156, 179, 0, 0, 0, 6, 0, 0, 0, 0, 1, 4, 87, 0, 0,
  716. 0, 2, 145, 108, 6, 0, 0, 0, 0, 1, 4, 179, 0, 0, 0, 2,
  717. 145, 96, 0, 4, 8, 108, 0, 0, 0, 0,
  718. }
  719. // Test Data method.
  720. b, err := sec.Data()
  721. if err != nil {
  722. t.Fatal(err)
  723. }
  724. if !bytes.Equal(wantData, b) {
  725. t.Fatalf("want data %x, got %x", wantData, b)
  726. }
  727. // Test Open method and seeking.
  728. buf, have, count := make([]byte, len(b)), make([]bool, len(b)), 0
  729. sf := sec.Open()
  730. if got, err := sf.Seek(0, io.SeekEnd); got != int64(len(b)) || err != nil {
  731. t.Fatalf("want seek end %d, got %d error %v", len(b), got, err)
  732. }
  733. if n, err := sf.Read(buf); n != 0 || err != io.EOF {
  734. t.Fatalf("want EOF with 0 bytes, got %v with %d bytes", err, n)
  735. }
  736. pos := int64(len(buf))
  737. for count < len(buf) {
  738. // Construct random seek arguments.
  739. whence := rand.Intn(3)
  740. target := rand.Int63n(int64(len(buf)))
  741. var offset int64
  742. switch whence {
  743. case io.SeekStart:
  744. offset = target
  745. case io.SeekCurrent:
  746. offset = target - pos
  747. case io.SeekEnd:
  748. offset = target - int64(len(buf))
  749. }
  750. pos, err = sf.Seek(offset, whence)
  751. if err != nil {
  752. t.Fatal(err)
  753. }
  754. if pos != target {
  755. t.Fatalf("want position %d, got %d", target, pos)
  756. }
  757. // Read data from the new position.
  758. end := pos + 16
  759. if end > int64(len(buf)) {
  760. end = int64(len(buf))
  761. }
  762. n, err := io.ReadFull(sf, buf[pos:end])
  763. if err != nil {
  764. t.Fatal(err)
  765. }
  766. for i := 0; i < n; i++ {
  767. if !have[pos] {
  768. have[pos] = true
  769. count++
  770. }
  771. pos++
  772. }
  773. }
  774. if !bytes.Equal(wantData, buf) {
  775. t.Fatalf("want data %x, got %x", wantData, buf)
  776. }
  777. }
  778. func TestNoSectionOverlaps(t *testing.T) {
  779. // Ensure cmd/link outputs sections without overlaps.
  780. switch runtime.GOOS {
  781. case "android", "darwin", "js", "nacl", "plan9", "windows":
  782. t.Skipf("cmd/link doesn't produce ELF binaries on %s", runtime.GOOS)
  783. }
  784. _ = net.ResolveIPAddr // force dynamic linkage
  785. f, err := Open(os.Args[0])
  786. if err != nil {
  787. t.Error(err)
  788. return
  789. }
  790. for i, si := range f.Sections {
  791. sih := si.SectionHeader
  792. if sih.Type == SHT_NOBITS {
  793. continue
  794. }
  795. for j, sj := range f.Sections {
  796. sjh := sj.SectionHeader
  797. if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.Size == 0 {
  798. continue
  799. }
  800. if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.Size {
  801. t.Errorf("ld produced ELF with section %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
  802. sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.Size, sjh.Offset+sjh.Size)
  803. }
  804. }
  805. }
  806. }