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.
 
 
 

221 lines
7.3 KiB

  1. // Copyright 2018 Google Inc. All Rights Reserved.
  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. package macho
  15. import (
  16. "reflect"
  17. "testing"
  18. )
  19. type fileTest struct {
  20. file string
  21. hdr FileHeader
  22. segments []*SegmentHeader
  23. sections []*SectionHeader
  24. }
  25. var fileTests = []fileTest{
  26. {
  27. "testdata/gcc-386-darwin-exec",
  28. FileHeader{0xfeedface, Cpu386, 0x3, 0x2, 0xc, 0x3c0, 0x85},
  29. []*SegmentHeader{
  30. {LoadCmdSegment, 0x38, "__PAGEZERO", 0x0, 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  31. {LoadCmdSegment, 0xc0, "__TEXT", 0x1000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x2, 0x0},
  32. {LoadCmdSegment, 0xc0, "__DATA", 0x2000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x2, 0x0},
  33. {LoadCmdSegment, 0x7c, "__IMPORT", 0x3000, 0x1000, 0x2000, 0x1000, 0x7, 0x7, 0x1, 0x0},
  34. {LoadCmdSegment, 0x38, "__LINKEDIT", 0x4000, 0x1000, 0x3000, 0x12c, 0x7, 0x1, 0x0, 0x0},
  35. nil,
  36. nil,
  37. nil,
  38. nil,
  39. nil,
  40. nil,
  41. nil,
  42. },
  43. []*SectionHeader{
  44. {"__text", "__TEXT", 0x1f68, 0x88, 0xf68, 0x2, 0x0, 0x0, 0x80000400},
  45. {"__cstring", "__TEXT", 0x1ff0, 0xd, 0xff0, 0x0, 0x0, 0x0, 0x2},
  46. {"__data", "__DATA", 0x2000, 0x14, 0x1000, 0x2, 0x0, 0x0, 0x0},
  47. {"__dyld", "__DATA", 0x2014, 0x1c, 0x1014, 0x2, 0x0, 0x0, 0x0},
  48. {"__jump_table", "__IMPORT", 0x3000, 0xa, 0x2000, 0x6, 0x0, 0x0, 0x4000008},
  49. },
  50. },
  51. {
  52. "testdata/gcc-amd64-darwin-exec",
  53. FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0x2, 0xb, 0x568, 0x85},
  54. []*SegmentHeader{
  55. {LoadCmdSegment64, 0x48, "__PAGEZERO", 0x0, 0x100000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  56. {LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x5, 0x0},
  57. {LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x3, 0x0},
  58. {LoadCmdSegment64, 0x48, "__LINKEDIT", 0x100002000, 0x1000, 0x2000, 0x140, 0x7, 0x1, 0x0, 0x0},
  59. nil,
  60. nil,
  61. nil,
  62. nil,
  63. nil,
  64. nil,
  65. nil,
  66. },
  67. []*SectionHeader{
  68. {"__text", "__TEXT", 0x100000f14, 0x6d, 0xf14, 0x2, 0x0, 0x0, 0x80000400},
  69. {"__symbol_stub1", "__TEXT", 0x100000f81, 0xc, 0xf81, 0x0, 0x0, 0x0, 0x80000408},
  70. {"__stub_helper", "__TEXT", 0x100000f90, 0x18, 0xf90, 0x2, 0x0, 0x0, 0x0},
  71. {"__cstring", "__TEXT", 0x100000fa8, 0xd, 0xfa8, 0x0, 0x0, 0x0, 0x2},
  72. {"__eh_frame", "__TEXT", 0x100000fb8, 0x48, 0xfb8, 0x3, 0x0, 0x0, 0x6000000b},
  73. {"__data", "__DATA", 0x100001000, 0x1c, 0x1000, 0x3, 0x0, 0x0, 0x0},
  74. {"__dyld", "__DATA", 0x100001020, 0x38, 0x1020, 0x3, 0x0, 0x0, 0x0},
  75. {"__la_symbol_ptr", "__DATA", 0x100001058, 0x10, 0x1058, 0x2, 0x0, 0x0, 0x7},
  76. },
  77. },
  78. {
  79. "testdata/gcc-amd64-darwin-exec-debug",
  80. FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0xa, 0x4, 0x5a0, 0},
  81. []*SegmentHeader{
  82. nil,
  83. {LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x0, 0x7, 0x5, 0x5, 0x0},
  84. {LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x0, 0x0, 0x7, 0x3, 0x3, 0x0},
  85. {LoadCmdSegment64, 0x278, "__DWARF", 0x100002000, 0x1000, 0x1000, 0x1bc, 0x7, 0x3, 0x7, 0x0},
  86. },
  87. []*SectionHeader{
  88. {"__text", "__TEXT", 0x100000f14, 0x0, 0x0, 0x2, 0x0, 0x0, 0x80000400},
  89. {"__symbol_stub1", "__TEXT", 0x100000f81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000408},
  90. {"__stub_helper", "__TEXT", 0x100000f90, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0},
  91. {"__cstring", "__TEXT", 0x100000fa8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2},
  92. {"__eh_frame", "__TEXT", 0x100000fb8, 0x0, 0x0, 0x3, 0x0, 0x0, 0x6000000b},
  93. {"__data", "__DATA", 0x100001000, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
  94. {"__dyld", "__DATA", 0x100001020, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
  95. {"__la_symbol_ptr", "__DATA", 0x100001058, 0x0, 0x0, 0x2, 0x0, 0x0, 0x7},
  96. {"__debug_abbrev", "__DWARF", 0x100002000, 0x36, 0x1000, 0x0, 0x0, 0x0, 0x0},
  97. {"__debug_aranges", "__DWARF", 0x100002036, 0x30, 0x1036, 0x0, 0x0, 0x0, 0x0},
  98. {"__debug_frame", "__DWARF", 0x100002066, 0x40, 0x1066, 0x0, 0x0, 0x0, 0x0},
  99. {"__debug_info", "__DWARF", 0x1000020a6, 0x54, 0x10a6, 0x0, 0x0, 0x0, 0x0},
  100. {"__debug_line", "__DWARF", 0x1000020fa, 0x47, 0x10fa, 0x0, 0x0, 0x0, 0x0},
  101. {"__debug_pubnames", "__DWARF", 0x100002141, 0x1b, 0x1141, 0x0, 0x0, 0x0, 0x0},
  102. {"__debug_str", "__DWARF", 0x10000215c, 0x60, 0x115c, 0x0, 0x0, 0x0, 0x0},
  103. },
  104. },
  105. }
  106. func TestOpen(t *testing.T) {
  107. for i := range fileTests {
  108. tt := &fileTests[i]
  109. f, err := Open(tt.file)
  110. if err != nil {
  111. t.Error(err)
  112. continue
  113. }
  114. if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
  115. t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
  116. continue
  117. }
  118. for i, l := range f.Loads {
  119. if i >= len(tt.segments) {
  120. break
  121. }
  122. sh := tt.segments[i]
  123. s, ok := l.(*Segment)
  124. if sh == nil {
  125. if ok {
  126. t.Errorf("open %s, section %d: skipping %#v\n", tt.file, i, &s.SegmentHeader)
  127. }
  128. continue
  129. }
  130. if !ok {
  131. t.Errorf("open %s, section %d: not *Segment\n", tt.file, i)
  132. continue
  133. }
  134. have := &s.SegmentHeader
  135. want := sh
  136. if !reflect.DeepEqual(have, want) {
  137. t.Errorf("open %s, segment %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
  138. }
  139. }
  140. tn := len(tt.segments)
  141. fn := len(f.Loads)
  142. if tn != fn {
  143. t.Errorf("open %s: len(Loads) = %d, want %d", tt.file, fn, tn)
  144. }
  145. for i, sh := range f.Sections {
  146. if i >= len(tt.sections) {
  147. break
  148. }
  149. have := &sh.SectionHeader
  150. want := tt.sections[i]
  151. if !reflect.DeepEqual(have, want) {
  152. t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
  153. }
  154. }
  155. tn = len(tt.sections)
  156. fn = len(f.Sections)
  157. if tn != fn {
  158. t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
  159. }
  160. }
  161. }
  162. func TestOpenFailure(t *testing.T) {
  163. filename := "file.go" // not a Mach-O file
  164. _, err := Open(filename) // don't crash
  165. if err == nil {
  166. t.Errorf("open %s: succeeded unexpectedly", filename)
  167. }
  168. }
  169. func TestOpenFat(t *testing.T) {
  170. ff, err := OpenFat("testdata/fat-gcc-386-amd64-darwin-exec")
  171. if err != nil {
  172. t.Fatal(err)
  173. }
  174. if ff.Magic != MagicFat {
  175. t.Errorf("OpenFat: got magic number %#x, want %#x", ff.Magic, MagicFat)
  176. }
  177. if len(ff.Arches) != 2 {
  178. t.Errorf("OpenFat: got %d architectures, want 2", len(ff.Arches))
  179. }
  180. for i := range ff.Arches {
  181. arch := &ff.Arches[i]
  182. ftArch := &fileTests[i]
  183. if arch.Cpu != ftArch.hdr.Cpu || arch.SubCpu != ftArch.hdr.SubCpu {
  184. t.Errorf("OpenFat: architecture #%d got cpu=%#x subtype=%#x, expected cpu=%#x, subtype=%#x", i, arch.Cpu, arch.SubCpu, ftArch.hdr.Cpu, ftArch.hdr.SubCpu)
  185. }
  186. if !reflect.DeepEqual(arch.FileHeader, ftArch.hdr) {
  187. t.Errorf("OpenFat header:\n\tgot %#v\n\twant %#v\n", arch.FileHeader, ftArch.hdr)
  188. }
  189. }
  190. }
  191. func TestOpenFatFailure(t *testing.T) {
  192. filename := "file.go" // not a Mach-O file
  193. if _, err := OpenFat(filename); err == nil {
  194. t.Errorf("OpenFat %s: succeeded unexpectedly", filename)
  195. }
  196. filename = "testdata/gcc-386-darwin-exec" // not a fat Mach-O
  197. ff, err := OpenFat(filename)
  198. if err != ErrNotFat {
  199. t.Errorf("OpenFat %s: got %v, want ErrNotFat", filename, err)
  200. }
  201. if ff != nil {
  202. t.Errorf("OpenFat %s: got %v, want nil", filename, ff)
  203. }
  204. }