Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(80)

Side by Side Diff: util/mac/mach_o_image_reader_test.cc

Issue 539263003: Add MachOImageSymbolTableReader and hook it up to MachOImageReader (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Fix 32-bit x86 Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Crashpad Authors. All rights reserved. 1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with 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 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 #include "util/mac/mach_o_image_reader.h" 15 #include "util/mac/mach_o_image_reader.h"
16 16
17 #include <dlfcn.h> 17 #include <dlfcn.h>
18 #include <mach-o/dyld.h>
18 #include <mach-o/dyld_images.h> 19 #include <mach-o/dyld_images.h>
19 #include <mach-o/getsect.h> 20 #include <mach-o/getsect.h>
21 #include <mach-o/ldsyms.h>
20 #include <mach-o/loader.h> 22 #include <mach-o/loader.h>
23 #include <mach-o/nlist.h>
21 #include <stdint.h> 24 #include <stdint.h>
22 25
23 #include "base/strings/stringprintf.h" 26 #include "base/strings/stringprintf.h"
24 #include "build/build_config.h" 27 #include "build/build_config.h"
25 #include "gtest/gtest.h" 28 #include "gtest/gtest.h"
26 #include "util/mac/mach_o_image_segment_reader.h" 29 #include "util/mac/mach_o_image_segment_reader.h"
27 #include "util/mac/process_reader.h" 30 #include "util/mac/process_reader.h"
28 #include "util/mac/process_types.h" 31 #include "util/mac/process_types.h"
29 #include "util/misc/uuid.h" 32 #include "util/misc/uuid.h"
30 #include "util/test/mac/dyld.h" 33 #include "util/test/mac/dyld.h"
31 34
35 // This file is responsible for testing MachOImageReader,
36 // MachOImageSegmentReader, and MachOImageSymbolTableReader.
37
32 namespace { 38 namespace {
33 39
34 using namespace crashpad; 40 using namespace crashpad;
35 41
36 // Native types and constants, in cases where the 32-bit and 64-bit versions 42 // Native types and constants, in cases where the 32-bit and 64-bit versions
37 // are different. 43 // are different.
38 #if defined(ARCH_CPU_64_BITS) 44 #if defined(ARCH_CPU_64_BITS)
39 typedef mach_header_64 MachHeader; 45 typedef mach_header_64 MachHeader;
40 const uint32_t kMachMagic = MH_MAGIC_64; 46 const uint32_t kMachMagic = MH_MAGIC_64;
41 typedef segment_command_64 SegmentCommand; 47 typedef segment_command_64 SegmentCommand;
42 const uint32_t kSegmentCommand = LC_SEGMENT_64; 48 const uint32_t kSegmentCommand = LC_SEGMENT_64;
43 typedef section_64 Section; 49 typedef section_64 Section;
50 typedef nlist_64 Nlist;
44 #else 51 #else
45 typedef mach_header MachHeader; 52 typedef mach_header MachHeader;
46 const uint32_t kMachMagic = MH_MAGIC; 53 const uint32_t kMachMagic = MH_MAGIC;
47 typedef segment_command SegmentCommand; 54 typedef segment_command SegmentCommand;
48 const uint32_t kSegmentCommand = LC_SEGMENT; 55 const uint32_t kSegmentCommand = LC_SEGMENT;
49 typedef section Section; 56 typedef section Section;
57
58 // This needs to be called “struct nlist” because “nlist” without the struct
59 // refers to the nlist() function.
60 typedef struct nlist Nlist;
50 #endif 61 #endif
51 62
52 #if defined(ARCH_CPU_X86_64) 63 #if defined(ARCH_CPU_X86_64)
53 const int kCPUType = CPU_TYPE_X86_64; 64 const int kCPUType = CPU_TYPE_X86_64;
54 #elif defined(ARCH_CPU_X86) 65 #elif defined(ARCH_CPU_X86)
55 const int kCPUType = CPU_TYPE_X86; 66 const int kCPUType = CPU_TYPE_X86;
56 #endif 67 #endif
57 68
58 // Verifies that |expect_section| and |actual_section| agree. 69 // Verifies that |expect_section| and |actual_section| agree.
59 void ExpectSection(const Section* expect_section, 70 void ExpectSection(const Section* expect_section,
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 &expect_section_size); 192 &expect_section_size);
182 mach_vm_address_t expect_section_address = 193 mach_vm_address_t expect_section_address =
183 reinterpret_cast<mach_vm_address_t>(expect_section_data); 194 reinterpret_cast<mach_vm_address_t>(expect_section_data);
184 EXPECT_EQ(expect_section_address, actual_section_address); 195 EXPECT_EQ(expect_section_address, actual_section_address);
185 EXPECT_EQ(expect_section_size, actual_section->size); 196 EXPECT_EQ(expect_section_size, actual_section->size);
186 } else { 197 } else {
187 EXPECT_EQ(actual_section_address, actual_section->addr); 198 EXPECT_EQ(actual_section_address, actual_section->addr);
188 } 199 }
189 200
190 // Test the parent MachOImageReader’s GetSectionAtIndex as well. 201 // Test the parent MachOImageReader’s GetSectionAtIndex as well.
202 const MachOImageSegmentReader* containing_segment;
191 mach_vm_address_t actual_section_address_at_index; 203 mach_vm_address_t actual_section_address_at_index;
192 const process_types::section* actual_section_from_image_at_index = 204 const process_types::section* actual_section_from_image_at_index =
193 actual_image->GetSectionAtIndex(++(*section_index), 205 actual_image->GetSectionAtIndex(++(*section_index),
206 &containing_segment,
194 &actual_section_address_at_index); 207 &actual_section_address_at_index);
195 EXPECT_EQ(actual_section, actual_section_from_image_at_index); 208 EXPECT_EQ(actual_section, actual_section_from_image_at_index);
209 EXPECT_EQ(actual_segment, containing_segment);
196 EXPECT_EQ(actual_section_address, actual_section_address_at_index); 210 EXPECT_EQ(actual_section_address, actual_section_address_at_index);
197 } 211 }
198 212
199 EXPECT_EQ(NULL, actual_segment->GetSectionByName("NoSuchSection")); 213 EXPECT_EQ(NULL, actual_segment->GetSectionByName("NoSuchSection"));
200 } 214 }
201 215
202 // Walks through the load commands of |expect_image|, finding all of the 216 // Walks through the load commands of |expect_image|, finding all of the
203 // expected segment commands. For each expected segment command, calls 217 // expected segment commands. For each expected segment command, calls
204 // actual_image->GetSegmentByName() to obtain an actual segment command, and 218 // actual_image->GetSegmentByName() to obtain an actual segment command, and
205 // calls ExpectSegmentCommand() to compare the expected and actual segments. A 219 // calls ExpectSegmentCommand() to compare the expected and actual segments. A
(...skipping 12 matching lines...) Expand all
218 232
219 const char* commands_base = reinterpret_cast<const char*>(&expect_image[1]); 233 const char* commands_base = reinterpret_cast<const char*>(&expect_image[1]);
220 uint32_t position = 0; 234 uint32_t position = 0;
221 size_t section_index = 0; 235 size_t section_index = 0;
222 for (uint32_t index = 0; index < expect_image->ncmds; ++index) { 236 for (uint32_t index = 0; index < expect_image->ncmds; ++index) {
223 ASSERT_LT(position, expect_image->sizeofcmds); 237 ASSERT_LT(position, expect_image->sizeofcmds);
224 const load_command* command = 238 const load_command* command =
225 reinterpret_cast<const load_command*>(&commands_base[position]); 239 reinterpret_cast<const load_command*>(&commands_base[position]);
226 ASSERT_LE(position + command->cmdsize, expect_image->sizeofcmds); 240 ASSERT_LE(position + command->cmdsize, expect_image->sizeofcmds);
227 if (command->cmd == kSegmentCommand) { 241 if (command->cmd == kSegmentCommand) {
242 ASSERT_GE(command->cmdsize, sizeof(SegmentCommand));
228 const SegmentCommand* expect_segment = 243 const SegmentCommand* expect_segment =
229 reinterpret_cast<const SegmentCommand*>(command); 244 reinterpret_cast<const SegmentCommand*>(command);
230 std::string segment_name = 245 std::string segment_name =
231 MachOImageSegmentReader::SegmentNameString(expect_segment->segname); 246 MachOImageSegmentReader::SegmentNameString(expect_segment->segname);
232 mach_vm_address_t actual_segment_address; 247 mach_vm_address_t actual_segment_address;
233 mach_vm_size_t actual_segment_size; 248 mach_vm_size_t actual_segment_size;
234 const MachOImageSegmentReader* actual_segment = 249 const MachOImageSegmentReader* actual_segment =
235 actual_image->GetSegmentByName( 250 actual_image->GetSegmentByName(
236 segment_name, &actual_segment_address, &actual_segment_size); 251 segment_name, &actual_segment_address, &actual_segment_size);
237 ExpectSegmentCommand(expect_segment, 252 ExpectSegmentCommand(expect_segment,
238 expect_image, 253 expect_image,
239 actual_segment, 254 actual_segment,
240 actual_segment_address, 255 actual_segment_address,
241 actual_segment_size, 256 actual_segment_size,
242 actual_image, 257 actual_image,
243 &section_index); 258 &section_index);
244 if (testing::Test::HasFatalFailure()) { 259 if (testing::Test::HasFatalFailure()) {
245 return; 260 return;
246 } 261 }
247 } 262 }
248 position += command->cmdsize; 263 position += command->cmdsize;
249 } 264 }
250 EXPECT_EQ(expect_image->sizeofcmds, position); 265 EXPECT_EQ(expect_image->sizeofcmds, position);
251 266
252 if (test_section_index_bounds) { 267 if (test_section_index_bounds) {
253 // GetSectionAtIndex uses a 1-based index. Make sure that the range is 268 // GetSectionAtIndex uses a 1-based index. Make sure that the range is
254 // correct. 269 // correct.
255 EXPECT_EQ(NULL, actual_image->GetSectionAtIndex(0, NULL)); 270 EXPECT_EQ(NULL, actual_image->GetSectionAtIndex(0, NULL, NULL));
256 EXPECT_EQ(NULL, actual_image->GetSectionAtIndex(section_index + 1, NULL)); 271 EXPECT_EQ(NULL,
272 actual_image->GetSectionAtIndex(section_index + 1, NULL, NULL));
257 } 273 }
258 274
259 // Make sure that by-name lookups for names that don’t exist work properly: 275 // Make sure that by-name lookups for names that don’t exist work properly:
260 // they should return NULL. 276 // they should return NULL.
261 EXPECT_FALSE(actual_image->GetSegmentByName("NoSuchSegment", NULL, NULL)); 277 EXPECT_FALSE(actual_image->GetSegmentByName("NoSuchSegment", NULL, NULL));
262 EXPECT_FALSE( 278 EXPECT_FALSE(
263 actual_image->GetSectionByName("NoSuchSegment", "NoSuchSection", NULL)); 279 actual_image->GetSectionByName("NoSuchSegment", "NoSuchSection", NULL));
264 280
265 // Make sure that there’s a __TEXT segment so that this can do a valid test of 281 // Make sure that there’s a __TEXT segment so that this can do a valid test of
266 // a section that doesn’t exist within a segment that does. 282 // a section that doesn’t exist within a segment that does.
267 EXPECT_TRUE(actual_image->GetSegmentByName(SEG_TEXT, NULL, NULL)); 283 EXPECT_TRUE(actual_image->GetSegmentByName(SEG_TEXT, NULL, NULL));
268 EXPECT_FALSE(actual_image->GetSectionByName(SEG_TEXT, "NoSuchSection", NULL)); 284 EXPECT_FALSE(actual_image->GetSectionByName(SEG_TEXT, "NoSuchSection", NULL));
269 285
270 // Similarly, make sure that a section name that exists in one segment isn’t 286 // Similarly, make sure that a section name that exists in one segment isn’t
271 // accidentally found during a lookup for that section in a different segment. 287 // accidentally found during a lookup for that section in a different segment.
272 EXPECT_TRUE(actual_image->GetSectionByName(SEG_TEXT, SECT_TEXT, NULL)); 288 EXPECT_TRUE(actual_image->GetSectionByName(SEG_TEXT, SECT_TEXT, NULL));
273 EXPECT_FALSE( 289 EXPECT_FALSE(
274 actual_image->GetSectionByName("NoSuchSegment", SECT_TEXT, NULL)); 290 actual_image->GetSectionByName("NoSuchSegment", SECT_TEXT, NULL));
275 EXPECT_FALSE(actual_image->GetSectionByName(SEG_DATA, SECT_TEXT, NULL)); 291 EXPECT_FALSE(actual_image->GetSectionByName(SEG_DATA, SECT_TEXT, NULL));
276 292
277 // The __LINKEDIT segment normally does exist but doesn’t have any sections. 293 // The __LINKEDIT segment normally does exist but doesn’t have any sections.
278 EXPECT_FALSE( 294 EXPECT_FALSE(
279 actual_image->GetSectionByName(SEG_LINKEDIT, "NoSuchSection", NULL)); 295 actual_image->GetSectionByName(SEG_LINKEDIT, "NoSuchSection", NULL));
280 EXPECT_FALSE(actual_image->GetSectionByName(SEG_LINKEDIT, SECT_TEXT, NULL)); 296 EXPECT_FALSE(actual_image->GetSectionByName(SEG_LINKEDIT, SECT_TEXT, NULL));
281 } 297 }
282 298
299 // In some cases, the expected slide value for an image is unknown, because no
300 // reasonable API to return it is provided. When this happens, use kSlideUnknown
301 // to avoid checking the actual slide value against anything.
302 const mach_vm_size_t kSlideUnknown = std::numeric_limits<mach_vm_size_t>::max();
303
283 // Verifies that |expect_image| is a vaild Mach-O header for the current system 304 // Verifies that |expect_image| is a vaild Mach-O header for the current system
284 // by checking its |magic| and |cputype| fields. Then, verifies that the 305 // by checking its |magic| and |cputype| fields. Then, verifies that the
285 // information in |actual_image| matches that in |expect_image|. The |filetype| 306 // information in |actual_image| matches that in |expect_image|. The |filetype|
286 // field is examined, and actual_image->Address() is compared to 307 // field is examined, actual_image->Address() is compared to
287 // |expect_image_address|. Various other attributes of |actual_image| are 308 // |expect_image_address|, and actual_image->Slide() is compared to
288 // sanity-checked depending on the Mach-O file type. Finally, 309 // |expect_image_slide|, unless |expect_image_slide| is kSlideUnknown. Various
289 // ExpectSegmentCommands() is called to verify all that all of the segments 310 // other attributes of |actual_image| are sanity-checked depending on the Mach-O
290 // match; |test_section_index_bounds| is used as an argument to that function. 311 // file type. Finally, ExpectSegmentCommands() is called to verify all that all
312 // of the segments match; |test_section_index_bounds| is used as an argument to
313 // that function.
291 void ExpectMachImage(const MachHeader* expect_image, 314 void ExpectMachImage(const MachHeader* expect_image,
292 mach_vm_address_t expect_image_address, 315 mach_vm_address_t expect_image_address,
316 mach_vm_size_t expect_image_slide,
293 const MachOImageReader* actual_image, 317 const MachOImageReader* actual_image,
294 bool test_section_index_bounds) { 318 bool test_section_index_bounds) {
295 ASSERT_TRUE(expect_image); 319 ASSERT_TRUE(expect_image);
296 ASSERT_TRUE(actual_image); 320 ASSERT_TRUE(actual_image);
297 321
298 EXPECT_EQ(kMachMagic, expect_image->magic); 322 EXPECT_EQ(kMachMagic, expect_image->magic);
299 EXPECT_EQ(kCPUType, expect_image->cputype); 323 EXPECT_EQ(kCPUType, expect_image->cputype);
300 324
301 EXPECT_EQ(expect_image->filetype, actual_image->FileType()); 325 EXPECT_EQ(expect_image->filetype, actual_image->FileType());
302 EXPECT_EQ(expect_image_address, actual_image->Address()); 326 EXPECT_EQ(expect_image_address, actual_image->Address());
327 if (expect_image_slide != kSlideUnknown) {
328 EXPECT_EQ(expect_image_slide, actual_image->Slide());
329 }
303 330
304 mach_vm_address_t actual_text_segment_address; 331 mach_vm_address_t actual_text_segment_address;
305 mach_vm_size_t actual_text_segment_size; 332 mach_vm_size_t actual_text_segment_size;
306 const MachOImageSegmentReader* actual_text_segment = 333 const MachOImageSegmentReader* actual_text_segment =
307 actual_image->GetSegmentByName( 334 actual_image->GetSegmentByName(
308 SEG_TEXT, &actual_text_segment_address, &actual_text_segment_size); 335 SEG_TEXT, &actual_text_segment_address, &actual_text_segment_size);
309 ASSERT_TRUE(actual_text_segment); 336 ASSERT_TRUE(actual_text_segment);
310 EXPECT_EQ(expect_image_address, actual_text_segment_address); 337 EXPECT_EQ(expect_image_address, actual_text_segment_address);
311 EXPECT_EQ(actual_image->Size(), actual_text_segment_size); 338 EXPECT_EQ(actual_image->Size(), actual_text_segment_size);
312 EXPECT_EQ(expect_image_address - actual_text_segment->vmaddr(), 339 EXPECT_EQ(expect_image_address - actual_text_segment->vmaddr(),
313 actual_image->Slide()); 340 actual_image->Slide());
314 341
315 uint32_t file_type = actual_image->FileType(); 342 uint32_t file_type = actual_image->FileType();
316 EXPECT_TRUE(file_type == MH_EXECUTE || file_type == MH_DYLIB || 343 EXPECT_TRUE(file_type == MH_EXECUTE || file_type == MH_DYLIB ||
317 file_type == MH_DYLINKER || file_type == MH_BUNDLE); 344 file_type == MH_DYLINKER || file_type == MH_BUNDLE);
318 345
319 if (file_type == MH_EXECUTE || file_type == MH_DYLINKER) { 346 if (file_type == MH_EXECUTE || file_type == MH_DYLINKER) {
320 EXPECT_EQ("/usr/lib/dyld", actual_image->DylinkerName()); 347 EXPECT_EQ("/usr/lib/dyld", actual_image->DylinkerName());
321 } 348 }
322 349
323 // For these, just don’t crash or anything. 350 // For these, just don’t crash or anything.
324 if (file_type == MH_DYLIB) { 351 if (file_type == MH_DYLIB) {
325 actual_image->DylibVersion(); 352 actual_image->DylibVersion();
326 } 353 }
327 actual_image->SourceVersion(); 354 actual_image->SourceVersion();
328 UUID uuid; 355 UUID uuid;
329 actual_image->UUID(&uuid); 356 actual_image->UUID(&uuid);
330 357
331 ExpectSegmentCommands(expect_image, actual_image, test_section_index_bounds); 358 ExpectSegmentCommands(expect_image, actual_image, test_section_index_bounds);
359 if (testing::Test::HasFatalFailure()) {
360 return;
361 }
362 }
363
364 // Verifies the symbol whose Nlist structure is |entry| and whose name is |name|
365 // matches the value of a symbol by the same name looked up in |actual_image|.
366 // MachOImageReader::LookUpExternalDefinedSymbol() is used for this purpose.
367 // Only external defined symbols are considered, other types of symbols are
368 // excluded because LookUpExternalDefinedSymbol() only deals with external
369 // defined symbols.
370 void ExpectSymbol(const Nlist* entry,
371 const char* name,
372 const MachOImageReader* actual_image) {
373 SCOPED_TRACE(name);
374
375 uint32_t entry_type = entry->n_type & N_TYPE;
376 if ((entry->n_type & N_STAB) == 0 && (entry->n_type & N_PEXT) == 0 &&
377 entry_type != N_UNDF && entry_type != N_PBUD &&
378 (entry->n_type & N_EXT) == 1) {
379
380 // Note that this catches more symbols than MachOImageSymbolTableReader
381 // does. This test looks for all external defined symbols, but the
382 // implementation excludes indirect (N_INDR) symbols. This is intentional,
383 // because indirect symbols are currently not seen in the wild, but if they
384 // begin to be used more widely, this test is expected to catch them so that
385 // a decision can be made regarding whether support ought to be implemented.
386 mach_vm_address_t actual_address;
387 ASSERT_TRUE(
388 actual_image->LookUpExternalDefinedSymbol(name, &actual_address));
389
390 // Since the nlist interface was used to read the symbol, use it to compute
391 // the symbol address too. This isn’t perfect, and it should be possible in
392 // theory to use dlsym() to get the expected address of a symbol. In
393 // practice, dlsym() is difficult to use when only a MachHeader* is
394 // available as in this function, as opposed to a void* opaque handle. It is
395 // possible to get a void* handle by using dladdr() to find the file name
396 // corresponding to the MachHeader*, and using dlopen() again on that name,
397 // assuming it hasn’t changed on disk since being loaded. However, even with
398 // that being done, dlsym() can only deal with symbols whose names begin
399 // with an underscore (and requires that the leading underscore be trimmed).
400 // dlsym() will also return different addresses for symbols that are
401 // resolved via symbol resolver.
402 mach_vm_address_t expect_address = entry->n_value;
403 if (entry_type == N_SECT) {
404 EXPECT_GE(entry->n_sect, 1u);
405 expect_address += actual_image->Slide();
406 } else {
407 EXPECT_EQ(NO_SECT, entry->n_sect);
408 }
409
410 EXPECT_EQ(expect_address, actual_address);
411 }
412
413 // You’d think that it might be a good idea to verify that if the conditions
414 // above weren’t met, that the symbol didn’t show up in actual_image’s symbol
415 // table at all. Unfortunately, it’s possible for the same name to show up as
416 // both an external defined symbol and as something else, so it’s not possible
417 // to verify this reliably.
418 }
419
420 // Locates the symbol table in |expect_image| and verifies that all of the
421 // external defined symbols found there are also present and have the same
422 // values in |actual_image|. ExpectSymbol() is used to verify the actual symbol.
423 void ExpectSymbolTable(const MachHeader* expect_image,
424 const MachOImageReader* actual_image) {
425 // This intentionally consults only LC_SYMTAB and not LC_DYSYMTAB so that it
426 // can look at the larger set of all symbols. The actual implementation being
427 // tested is free to consult LC_DYSYMTAB, but that’s considered an
428 // optimization. It’s not necessary for the test, and it’s better for the test
429 // to expose bugs in that optimization rather than duplicate them.
430 const char* commands_base = reinterpret_cast<const char*>(&expect_image[1]);
Robert Sesek 2014/09/05 19:04:16 Why [1]?
Mark Mentovai 2014/09/05 20:22:31 rsesek wrote:
Robert Sesek 2014/09/05 20:41:31 I'd just add a comment saying it's moving past the
431 uint32_t position = 0;
432 const symtab_command* symtab = NULL;
433 const SegmentCommand* linkedit = NULL;
434 for (uint32_t index = 0; index < expect_image->ncmds; ++index) {
435 ASSERT_LT(position, expect_image->sizeofcmds);
436 const load_command* command =
437 reinterpret_cast<const load_command*>(&commands_base[position]);
438 ASSERT_LE(position + command->cmdsize, expect_image->sizeofcmds);
439 if (command->cmd == LC_SYMTAB) {
440 ASSERT_FALSE(symtab);
441 ASSERT_EQ(sizeof(symtab_command), command->cmdsize);
442 symtab = reinterpret_cast<const symtab_command*>(command);
443 } else if (command->cmd == kSegmentCommand) {
444 ASSERT_GE(command->cmdsize, sizeof(SegmentCommand));
445 const SegmentCommand* segment =
446 reinterpret_cast<const SegmentCommand*>(command);
447 std::string segment_name =
448 MachOImageSegmentReader::SegmentNameString(segment->segname);
449 if (segment_name == SEG_LINKEDIT) {
450 ASSERT_FALSE(linkedit);
451 linkedit = segment;
452 }
453 }
454 position += command->cmdsize;
455 }
456
457 if (symtab) {
458 ASSERT_TRUE(linkedit);
459
460 const char* linkedit_base =
461 reinterpret_cast<const char*>(linkedit->vmaddr + actual_image->Slide());
462 const Nlist* nlist = reinterpret_cast<const Nlist*>(
463 linkedit_base + symtab->symoff - linkedit->fileoff);
464 const char* strtab = linkedit_base + symtab->stroff - linkedit->fileoff;
465
466 for (uint32_t index = 0; index < symtab->nsyms; ++index) {
467 const Nlist* entry = nlist + index;
468 const char* name = strtab + entry->n_un.n_strx;
469 ExpectSymbol(entry, name, actual_image);
470 if (testing::Test::HasFatalFailure()) {
471 return;
472 }
473 }
474 }
475
476 mach_vm_address_t ignore;
477 EXPECT_FALSE(actual_image->LookUpExternalDefinedSymbol("", &ignore));
478 EXPECT_FALSE(
479 actual_image->LookUpExternalDefinedSymbol("NoSuchSymbolName", &ignore));
480 EXPECT_FALSE(
481 actual_image->LookUpExternalDefinedSymbol("_NoSuchSymbolName", &ignore));
332 } 482 }
333 483
334 TEST(MachOImageReader, Self_MainExecutable) { 484 TEST(MachOImageReader, Self_MainExecutable) {
335 ProcessReader process_reader; 485 ProcessReader process_reader;
336 ASSERT_TRUE(process_reader.Initialize(mach_task_self())); 486 ASSERT_TRUE(process_reader.Initialize(mach_task_self()));
337 487
338 const MachHeader* mh_execute_header = reinterpret_cast<MachHeader*>( 488 const MachHeader* mh_execute_header = reinterpret_cast<MachHeader*>(
339 dlsym(RTLD_MAIN_ONLY, "_mh_execute_header")); 489 dlsym(RTLD_MAIN_ONLY, MH_EXECUTE_SYM));
340 ASSERT_NE(static_cast<void*>(NULL), mh_execute_header); 490 ASSERT_NE(static_cast<void*>(NULL), mh_execute_header);
341 mach_vm_address_t mh_execute_header_address = 491 mach_vm_address_t mh_execute_header_address =
342 reinterpret_cast<mach_vm_address_t>(mh_execute_header); 492 reinterpret_cast<mach_vm_address_t>(mh_execute_header);
343 493
344 MachOImageReader image_reader; 494 MachOImageReader image_reader;
345 ASSERT_TRUE(image_reader.Initialize( 495 ASSERT_TRUE(image_reader.Initialize(
346 &process_reader, mh_execute_header_address, "mh_execute_header")); 496 &process_reader, mh_execute_header_address, "executable"));
347 497
348 EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), image_reader.FileType()); 498 EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), image_reader.FileType());
349 499
350 ExpectMachImage( 500 // The main executable has image index 0.
351 mh_execute_header, mh_execute_header_address, &image_reader, true); 501 intptr_t image_slide = _dyld_get_image_vmaddr_slide(0);
502
503 ExpectMachImage(mh_execute_header,
504 mh_execute_header_address,
505 image_slide,
506 &image_reader,
507 true);
508 if (Test::HasFatalFailure()) {
509 return;
510 }
511
512 // This symbol, __mh_execute_header, is known to exist in all MH_EXECUTE
513 // Mach-O files.
514 mach_vm_address_t symbol_address;
515 ASSERT_TRUE(image_reader.LookUpExternalDefinedSymbol(_MH_EXECUTE_SYM,
516 &symbol_address));
517 EXPECT_EQ(mh_execute_header_address, symbol_address);
518
519 ExpectSymbolTable(mh_execute_header, &image_reader);
520 if (Test::HasFatalFailure()) {
521 return;
522 }
352 } 523 }
353 524
354 TEST(MachOImageReader, Self_DyldImages) { 525 TEST(MachOImageReader, Self_DyldImages) {
355 ProcessReader process_reader; 526 ProcessReader process_reader;
356 ASSERT_TRUE(process_reader.Initialize(mach_task_self())); 527 ASSERT_TRUE(process_reader.Initialize(mach_task_self()));
357 528
358 const struct dyld_all_image_infos* dyld_image_infos = 529 uint32_t count = _dyld_image_count();
359 _dyld_get_all_image_infos(); 530 ASSERT_GE(count, 1u);
360 ASSERT_GE(dyld_image_infos->version, 1u);
361 ASSERT_TRUE(dyld_image_infos->infoArray);
362 531
363 for (uint32_t index = 0; index < dyld_image_infos->infoArrayCount; ++index) { 532 for (uint32_t index = 0; index < count; ++index) {
364 const dyld_image_info* dyld_image = &dyld_image_infos->infoArray[index]; 533 const char* image_name = _dyld_get_image_name(index);
365 SCOPED_TRACE(base::StringPrintf( 534 SCOPED_TRACE(base::StringPrintf("index %u, image %s", index, image_name));
366 "index %u, image %s", index, dyld_image->imageFilePath));
367 535
368 // dyld_image_info::imageLoadAddress is poorly-declared: it’s declared as 536 // _dyld_get_image_header() is poorly-declared: it’s declared as returning
369 // const mach_header* in both 32-bit and 64-bit environments, but in the 537 // const mach_header* in both 32-bit and 64-bit environments, but in the
370 // 64-bit environment, it should be const mach_header_64*. 538 // 64-bit environment, it should be const mach_header_64*.
371 const MachHeader* mach_header = 539 const MachHeader* mach_header =
372 reinterpret_cast<const MachHeader*>(dyld_image->imageLoadAddress); 540 reinterpret_cast<const MachHeader*>(_dyld_get_image_header(index));
373 mach_vm_address_t image_address = 541 mach_vm_address_t image_address =
374 reinterpret_cast<mach_vm_address_t>(mach_header); 542 reinterpret_cast<mach_vm_address_t>(mach_header);
375 543
376 MachOImageReader image_reader; 544 MachOImageReader image_reader;
377 ASSERT_TRUE(image_reader.Initialize( 545 ASSERT_TRUE(image_reader.Initialize(
378 &process_reader, image_address, dyld_image->imageFilePath)); 546 &process_reader, image_address, image_name));
379 547
380 uint32_t file_type = image_reader.FileType(); 548 uint32_t file_type = image_reader.FileType();
381 if (index == 0) { 549 if (index == 0) {
382 EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), file_type); 550 EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), file_type);
383 } else { 551 } else {
384 EXPECT_TRUE(file_type == MH_DYLIB || file_type == MH_BUNDLE); 552 EXPECT_TRUE(file_type == MH_DYLIB || file_type == MH_BUNDLE);
385 } 553 }
386 554
387 ExpectMachImage(mach_header, image_address, &image_reader, false); 555 intptr_t image_slide = _dyld_get_image_vmaddr_slide(index);
556 ExpectMachImage(
557 mach_header, image_address, image_slide, &image_reader, false);
388 if (Test::HasFatalFailure()) { 558 if (Test::HasFatalFailure()) {
389 return; 559 return;
390 } 560 }
561
562 ExpectSymbolTable(mach_header, &image_reader);
563 if (Test::HasFatalFailure()) {
564 return;
565 }
391 } 566 }
392 567
393 // Now that all of the modules have been verified, make sure that dyld itself 568 // Now that all of the modules have been verified, make sure that dyld itself
394 // can be read properly too. 569 // can be read properly too.
570 const struct dyld_all_image_infos* dyld_image_infos =
571 _dyld_get_all_image_infos();
572 ASSERT_GE(dyld_image_infos->version, 1u);
573 EXPECT_EQ(count, dyld_image_infos->infoArrayCount);
574
395 if (dyld_image_infos->version >= 2) { 575 if (dyld_image_infos->version >= 2) {
396 SCOPED_TRACE("dyld"); 576 SCOPED_TRACE("dyld");
397 577
398 // dyld_all_image_infos::dyldImageLoadAddress is poorly-declared too. 578 // dyld_all_image_infos::dyldImageLoadAddress is poorly-declared too.
399 const MachHeader* mach_header = reinterpret_cast<const MachHeader*>( 579 const MachHeader* mach_header = reinterpret_cast<const MachHeader*>(
400 dyld_image_infos->dyldImageLoadAddress); 580 dyld_image_infos->dyldImageLoadAddress);
401 mach_vm_address_t image_address = 581 mach_vm_address_t image_address =
402 reinterpret_cast<mach_vm_address_t>(mach_header); 582 reinterpret_cast<mach_vm_address_t>(mach_header);
403 583
404 MachOImageReader image_reader; 584 MachOImageReader image_reader;
405 ASSERT_TRUE( 585 ASSERT_TRUE(
406 image_reader.Initialize(&process_reader, image_address, "dyld")); 586 image_reader.Initialize(&process_reader, image_address, "dyld"));
407 587
408 EXPECT_EQ(static_cast<uint32_t>(MH_DYLINKER), image_reader.FileType()); 588 EXPECT_EQ(static_cast<uint32_t>(MH_DYLINKER), image_reader.FileType());
409 589
410 ExpectMachImage(mach_header, image_address, &image_reader, false); 590 // There’s no good API to get dyld’s slide, so don’t bother checking it.
591 ExpectMachImage(
592 mach_header, image_address, kSlideUnknown, &image_reader, false);
411 if (Test::HasFatalFailure()) { 593 if (Test::HasFatalFailure()) {
412 return; 594 return;
413 } 595 }
596
597 ExpectSymbolTable(mach_header, &image_reader);
598 if (Test::HasFatalFailure()) {
599 return;
600 }
414 } 601 }
415 602
416 // If dyld is new enough to record UUIDs, check the UUID of any module that 603 // If dyld is new enough to record UUIDs, check the UUID of any module that
417 // it says has one. Note that dyld doesn’t record UUIDs of anything that 604 // it says has one. Note that dyld doesn’t record UUIDs of anything that
418 // loaded out of the shared cache, but it should at least have a UUID for the 605 // loaded out of the shared cache, but it should at least have a UUID for the
419 // main executable if it has one. 606 // main executable if it has one.
420 if (dyld_image_infos->version >= 8 && dyld_image_infos->uuidArray) { 607 if (dyld_image_infos->version >= 8 && dyld_image_infos->uuidArray) {
421 for (uint32_t index = 0; 608 for (uint32_t index = 0;
422 index < dyld_image_infos->uuidArrayCount; 609 index < dyld_image_infos->uuidArrayCount;
423 ++index) { 610 ++index) {
424 const dyld_uuid_info* dyld_image = &dyld_image_infos->uuidArray[index]; 611 const dyld_uuid_info* dyld_image = &dyld_image_infos->uuidArray[index];
425 SCOPED_TRACE(base::StringPrintf("uuid index %u", index)); 612 SCOPED_TRACE(base::StringPrintf("uuid index %u", index));
426 613
427 // dyld_uuid_info::imageLoadAddress is poorly-declared too. 614 // dyld_uuid_info::imageLoadAddress is poorly-declared too.
428 const MachHeader* mach_header = 615 const MachHeader* mach_header =
429 reinterpret_cast<const MachHeader*>(dyld_image->imageLoadAddress); 616 reinterpret_cast<const MachHeader*>(dyld_image->imageLoadAddress);
430 mach_vm_address_t image_address = 617 mach_vm_address_t image_address =
431 reinterpret_cast<mach_vm_address_t>(mach_header); 618 reinterpret_cast<mach_vm_address_t>(mach_header);
432 619
433 MachOImageReader image_reader; 620 MachOImageReader image_reader;
434 ASSERT_TRUE( 621 ASSERT_TRUE(
435 image_reader.Initialize(&process_reader, image_address, "uuid")); 622 image_reader.Initialize(&process_reader, image_address, "uuid"));
436 623
437 ExpectMachImage(mach_header, image_address, &image_reader, false); 624 // There’s no good way to get the image’s slide here, although the image
625 // should have already been checked along with its slide above, in the
626 // loop through all images.
627 ExpectMachImage(
628 mach_header, image_address, kSlideUnknown, &image_reader, false);
438 629
439 UUID expected_uuid; 630 UUID expected_uuid;
440 expected_uuid.InitializeFromBytes(dyld_image->imageUUID); 631 expected_uuid.InitializeFromBytes(dyld_image->imageUUID);
441 UUID actual_uuid; 632 UUID actual_uuid;
442 image_reader.UUID(&actual_uuid); 633 image_reader.UUID(&actual_uuid);
443 EXPECT_EQ(expected_uuid, actual_uuid); 634 EXPECT_EQ(expected_uuid, actual_uuid);
444 } 635 }
445 } 636 }
446 } 637 }
447 638
448 } // namespace 639 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698