188 строки
8.3 KiB
Objective-C
188 строки
8.3 KiB
Objective-C
/*
|
|
* Author: Landon Fuller <landonf@plausiblelabs.com>
|
|
*
|
|
* Copyright (c) 2008-2013 Plausible Labs Cooperative, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use,
|
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following
|
|
* conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#import "SenTestCompat.h"
|
|
|
|
#import "PLCrashAsyncImageList.h"
|
|
|
|
#import <mach-o/dyld.h>
|
|
|
|
#import <dlfcn.h>
|
|
#import <execinfo.h>
|
|
|
|
#import <objc/runtime.h>
|
|
|
|
@interface PLCrashAsyncImageTests : SenTestCase {
|
|
plcrash_async_image_list_t _list;
|
|
}
|
|
@end
|
|
|
|
// XXX TODO: Decouple the async image list from the Mach-O parsing, such that
|
|
// we can properly test it independently of Mach-O.
|
|
//
|
|
// Some work on this has been done in the bitstadium-upstream branch, but
|
|
// no tests were written for the changes.
|
|
@implementation PLCrashAsyncImageTests
|
|
|
|
- (void) setUp {
|
|
plcrash_nasync_image_list_init(&_list, mach_task_self());
|
|
}
|
|
|
|
- (void) tearDown {
|
|
plcrash_nasync_image_list_free(&_list);
|
|
}
|
|
|
|
- (void) testAppendImage {
|
|
// XXX - This is required due to the tight coupling with the Mach-O parser
|
|
uint32_t count = _dyld_image_count();
|
|
STAssertTrue(count >= 5, @"We need at least five Mach-O images for this test. This should not be a problem on a modern system.");
|
|
|
|
plcrash_nasync_image_list_append(&_list, (pl_vm_address_t) _dyld_get_image_header(0), _dyld_get_image_name(0));
|
|
plcrash_nasync_image_list_append(&_list, (pl_vm_address_t) _dyld_get_image_header(1), _dyld_get_image_name(1));
|
|
plcrash_nasync_image_list_append(&_list, (pl_vm_address_t) _dyld_get_image_header(2), _dyld_get_image_name(2));
|
|
plcrash_nasync_image_list_append(&_list, (pl_vm_address_t) _dyld_get_image_header(3), _dyld_get_image_name(3));
|
|
plcrash_nasync_image_list_append(&_list, (pl_vm_address_t) _dyld_get_image_header(4), _dyld_get_image_name(4));
|
|
|
|
/* Verify the appended elements */
|
|
plcrash_async_image_t *item = NULL;
|
|
|
|
plcrash_async_image_list_set_reading(&_list, true);
|
|
for (uint32_t i = 0; i <= 5; i++) {
|
|
/* Fetch the next item */
|
|
item = plcrash_async_image_list_next(&_list, item);
|
|
if (i <= 4) {
|
|
STAssertNotNULL(item, @"Item should not be NULL");
|
|
} else {
|
|
STAssertNULL(item, @"Item should be NULL");
|
|
break;
|
|
}
|
|
|
|
/* Validate its value */
|
|
STAssertEquals((pl_vm_address_t) _dyld_get_image_header(i), item->macho_image.header_addr, @"Incorrect header value");
|
|
STAssertEquals((pl_vm_off_t)_dyld_get_image_vmaddr_slide(i), item->macho_image.vmaddr_slide, @"Incorrect slide value");
|
|
STAssertEqualCStrings(_dyld_get_image_name(i), item->macho_image.name, @"Incorrect name value");
|
|
}
|
|
plcrash_async_image_list_set_reading(&_list, false);
|
|
|
|
}
|
|
|
|
|
|
/* Test removing the last image in the list. */
|
|
- (void) testRemoveLastImage {
|
|
plcrash_nasync_image_list_append(&_list, 0x0, "image_name");
|
|
plcrash_nasync_image_list_remove(&_list, 0x0);
|
|
|
|
plcrash_async_image_list_set_reading(&_list, true);
|
|
STAssertNULL(plcrash_async_image_list_next(&_list, NULL), @"List should be empty");
|
|
plcrash_async_image_list_set_reading(&_list, false);
|
|
}
|
|
|
|
- (void) testRemoveImage {
|
|
// XXX - This is required due to the tight coupling with the Mach-O parser
|
|
uint32_t count = _dyld_image_count();
|
|
STAssertTrue(count >= 5, @"We need at least five Mach-O images for this test. This should not be a problem on a modern system.");
|
|
|
|
plcrash_nasync_image_list_append(&_list, (pl_vm_address_t) _dyld_get_image_header(0), _dyld_get_image_name(0));
|
|
plcrash_nasync_image_list_append(&_list, (pl_vm_address_t) _dyld_get_image_header(1), _dyld_get_image_name(1));
|
|
plcrash_nasync_image_list_append(&_list, (pl_vm_address_t) _dyld_get_image_header(2), _dyld_get_image_name(2));
|
|
plcrash_nasync_image_list_append(&_list, (pl_vm_address_t) _dyld_get_image_header(3), _dyld_get_image_name(3));
|
|
plcrash_nasync_image_list_append(&_list, (pl_vm_address_t) _dyld_get_image_header(4), _dyld_get_image_name(4));
|
|
|
|
/* Try a non-existent item */
|
|
plcrash_nasync_image_list_remove(&_list, 0x42);
|
|
|
|
/* Remove real items */
|
|
plcrash_nasync_image_list_remove(&_list, (pl_vm_address_t) _dyld_get_image_header(1));
|
|
plcrash_nasync_image_list_remove(&_list, (pl_vm_address_t) _dyld_get_image_header(3));
|
|
|
|
/* Verify the contents of the list */
|
|
plcrash_async_image_t *item = NULL;
|
|
plcrash_async_image_list_set_reading(&_list, true);
|
|
int val = 0x0;
|
|
for (int i = 0; i <= 3; i++) {
|
|
/* Fetch the next item */
|
|
item = plcrash_async_image_list_next(&_list, item);
|
|
if (i <= 2) {
|
|
STAssertNotNULL(item, @"Item should not be NULL");
|
|
} else {
|
|
STAssertNULL(item, @"Item should be NULL");
|
|
break;
|
|
}
|
|
|
|
/* Validate its value */
|
|
STAssertEquals((pl_vm_address_t) _dyld_get_image_header(val), item->macho_image.header_addr, @"Incorrect header value for %d", val);
|
|
STAssertEquals((pl_vm_off_t)_dyld_get_image_vmaddr_slide(val), item->macho_image.vmaddr_slide, @"Incorrect slide value for %d", val);
|
|
STAssertEqualCStrings(_dyld_get_image_name(val), item->macho_image.name, @"Incorrect name value for %d", val);
|
|
val += 0x2;
|
|
}
|
|
plcrash_async_image_list_set_reading(&_list, false);
|
|
}
|
|
|
|
- (void) testFindImageForAddress {
|
|
/* Fetch the our IMP address and symbolicate it using dladdr(). */
|
|
IMP localIMP = class_getMethodImplementation([self class], _cmd);
|
|
Dl_info dli;
|
|
STAssertTrue(dladdr((void *)localIMP, &dli) != 0, @"Failed to look up symbol");
|
|
|
|
/* Look up the vmaddr slide for our image */
|
|
pl_vm_off_t vmaddr_slide = 0;
|
|
bool found_image = false;
|
|
for (uint32_t i = 0; i < _dyld_image_count(); i++) {
|
|
if (_dyld_get_image_header(i) == dli.dli_fbase) {
|
|
vmaddr_slide = _dyld_get_image_vmaddr_slide(i);
|
|
found_image = true;
|
|
break;
|
|
}
|
|
}
|
|
STAssertTrue(found_image, @"Could not find dyld image record");
|
|
|
|
/* Initialize our image list using our discovered image */
|
|
plcrash_nasync_image_list_append(&_list, (pl_vm_address_t) dli.dli_fbase, dli.dli_fname);
|
|
|
|
plcrash_async_image_list_set_reading(&_list, true); {
|
|
/* Verify that image_base-1 returns NULL */
|
|
STAssertNULL(plcrash_async_image_containing_address(&_list, (pl_vm_address_t) dli.dli_fbase-1), @"Should not return an image for invalid address");
|
|
|
|
/* Verify that image_base returns a valid value */
|
|
plcrash_async_image_t *image;
|
|
image = plcrash_async_image_containing_address(&_list, (pl_vm_address_t) dli.dli_fbase);
|
|
STAssertNotNULL(image, @"Failed to return valid image");
|
|
STAssertEquals(image->macho_image.header_addr, (pl_vm_address_t)dli.dli_fbase, @"Incorrect Mach-O header address");
|
|
STAssertEquals(image->macho_image.vmaddr_slide, vmaddr_slide, @"Incorrect slide value");
|
|
|
|
/* Verify that image_base+image_length-1 returns a valid value */
|
|
STAssertNotNULL(plcrash_async_image_containing_address(&_list, (pl_vm_address_t) dli.dli_fbase+image->macho_image.text_size-1), @"Should not return an image for invalid address");
|
|
|
|
/* Verify that image_base+image_length returns NULL */
|
|
STAssertNULL(plcrash_async_image_containing_address(&_list, (pl_vm_address_t) dli.dli_fbase+image->macho_image.text_size), @"Should not return an image for invalid address");
|
|
} plcrash_async_image_list_set_reading(&_list, false);
|
|
|
|
}
|
|
|
|
@end
|