mirror of
https://github.com/microsoft/plcrashreporter.git
synced 2026-01-18 04:01:18 +01:00
177 lines
7.3 KiB
Plaintext
177 lines
7.3 KiB
Plaintext
/*
|
|
* Author: Landon Fuller <landonf@plausible.coop>
|
|
*
|
|
* Copyright (c) 2012-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 "PLCrashTestCase.h"
|
|
|
|
#include "PLCrashAsyncDwarfEncoding.hpp"
|
|
|
|
#include "dwarf_encoding_test.h"
|
|
|
|
#include "PLCrashFeatureConfig.h"
|
|
|
|
#if PLCRASH_FEATURE_UNWIND_DWARF
|
|
|
|
using namespace plcrash::async;
|
|
|
|
#if TARGET_OS_MAC && (!TARGET_OS_IPHONE || TARGET_OS_MACCATALYST)
|
|
# define TEST_BINARY @"test.macosx"
|
|
#elif TARGET_OS_SIMULATOR
|
|
# define TEST_BINARY @"test.sim"
|
|
#elif TARGET_OS_IPHONE
|
|
# define TEST_BINARY @"test.ios"
|
|
#else
|
|
# error Unsupported target
|
|
#endif
|
|
|
|
@interface PLCrashAsyncDwarfEncodingTests : PLCrashTestCase {
|
|
/* Loaded test image */
|
|
plcrash_async_macho_t _image;
|
|
|
|
/* Mapped __(PL)_DWARF sections */
|
|
plcrash_async_mobject_t _eh_frame;
|
|
plcrash_async_mobject_t _debug_frame;
|
|
|
|
/* Frame readers */
|
|
dwarf_frame_reader _eh_reader;
|
|
dwarf_frame_reader _debug_reader;
|
|
|
|
/* True if using 64-bit test data, false otherwise */
|
|
bool _m64;
|
|
}
|
|
@end
|
|
|
|
@implementation PLCrashAsyncDwarfEncodingTests
|
|
|
|
- (void) setUp {
|
|
/*
|
|
* Warning: This code assumes 1:1 correspondance between vmaddr/vmsize and foffset/fsize in the loaded binary.
|
|
* This is currently the case with our test binaries, but it could possibly change in the future. To handle this,
|
|
* one would either need to:
|
|
* - Implement 'real' segment loading, ala https://github.com/landonf/libevil_patch/blob/b80ebf4c0442f234c4f3f9ec180a2f873c5e2559/libevil/libevil.m#L253
|
|
* or
|
|
* - Add a 'file mode' to the Mach-O parser that causes it to use file offsets rather than VM offsets.
|
|
* or
|
|
* - Don't bother to load all the segments properly, just map the CFE data.
|
|
*
|
|
* I didn't implement the file mode for the Mach-O parser as I'd like to keep that code as simple as possible,
|
|
* given that it runs in a privileged crash time position, and 'file' mode is only required for unit tests.
|
|
*
|
|
* Performing segment loading or parsing the Mach-O binary isn't much work, so I'll probably just do that, and then
|
|
* this comment can go away.
|
|
*/
|
|
|
|
NSError *error;
|
|
plcrash_error_t err;
|
|
|
|
/* Map and load the binary */
|
|
NSData *mappedImage = [self nativeBinaryFromTestResource: TEST_BINARY];
|
|
STAssertNotNil(mappedImage, @"Failed to map image: %@", error);
|
|
|
|
err = plcrash_nasync_macho_init(&_image, mach_task_self(), [TEST_BINARY UTF8String], (pl_vm_address_t) [mappedImage bytes]);
|
|
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to initialize Mach-O parser");
|
|
|
|
/* Map the eh/debug frame sections. We use our own fake __PL_DWARF segment to avoid toolchain interference with our test data. */
|
|
err = plcrash_async_macho_map_section(&_image, "__PL_DWARF", "__eh_frame", &_eh_frame);
|
|
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to map __eh_frame section");
|
|
|
|
err = plcrash_async_macho_map_section(&_image, "__PL_DWARF", "__debug_frame", &_debug_frame);
|
|
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to map __debug_frame section");
|
|
|
|
/* Determine the address size */
|
|
const plcrash_async_byteorder_t *byteorder = plcrash_async_macho_byteorder(&_image);
|
|
cpu_type_t cputype = byteorder->swap32(_image.header.cputype);
|
|
_m64 = cputype & CPU_ARCH_ABI64;
|
|
|
|
/* Initialize eh/debug readers */
|
|
err = _eh_reader.init(&_eh_frame, byteorder, _m64, false);
|
|
STAssertEquals(PLCRASH_ESUCCESS, err, @"Failed to initialize reader");
|
|
|
|
err = _debug_reader.init(&_debug_frame, byteorder, _m64, true);
|
|
STAssertEquals(PLCRASH_ESUCCESS, err, @"Failed to initialize reader");
|
|
}
|
|
|
|
- (void) tearDown {
|
|
plcrash_async_mobject_free(&_eh_frame);
|
|
plcrash_async_mobject_free(&_debug_frame);
|
|
|
|
plcrash_nasync_macho_free(&_image);
|
|
}
|
|
|
|
- (void) testFindEHFrameDescriptorEntry {
|
|
plcrash_error_t err;
|
|
plcrash_async_dwarf_fde_info_t fde_info;
|
|
|
|
err = _eh_reader.find_fde(0x0, PL_CFI_EH_FRAME_PC+PL_CFI_EH_FRAME_PC_RANGE-1, &fde_info);
|
|
STAssertEquals(PLCRASH_ESUCCESS, err, @"FDE search failed");
|
|
|
|
/* Should be the second entry in the table, plus the initial length field. */
|
|
if (_m64) {
|
|
STAssertEquals(fde_info.fde_offset, (pl_vm_address_t) ((sizeof(pl_cfi_entry)) + PL_CFI_LEN_SIZE_64), @"Incorrect offset");
|
|
STAssertEquals(fde_info.fde_length, (uint64_t)PL_CFI_SIZE_64, @"Incorrect length");
|
|
} else {
|
|
STAssertEquals(fde_info.fde_offset, (pl_vm_address_t) ((sizeof(pl_cfi_entry)) + PL_CFI_LEN_SIZE_32), @"Incorrect offset");
|
|
STAssertEquals(fde_info.fde_length, (uint64_t)PL_CFI_SIZE_32, @"Incorrect length");
|
|
}
|
|
//STAssertEquals(fde_info.fde_instruction_offset, (pl_vm_address_t)0x0, @"Incorrect instruction offset (should be the first entry)");
|
|
|
|
plcrash_async_dwarf_fde_info_free(&fde_info);
|
|
|
|
/* Verify that an unknown PC returns ENOTFOUND. */
|
|
err = _debug_reader.find_fde(0x0, PL_CFI_EH_FRAME_PC+PL_CFI_EH_FRAME_PC_RANGE, &fde_info);
|
|
STAssertEquals(PLCRASH_ENOTFOUND, err, @"FDE should not have been found");
|
|
}
|
|
|
|
- (void) testFindDebugFrameDescriptorEntry {
|
|
plcrash_error_t err;
|
|
plcrash_async_dwarf_fde_info_t fde_info;
|
|
|
|
err = _debug_reader.find_fde(0x0, PL_CFI_DEBUG_FRAME_PC+PL_CFI_DEBUG_FRAME_PC_RANGE-1, &fde_info);
|
|
STAssertEquals(PLCRASH_ESUCCESS, err, @"FDE search failed");
|
|
|
|
/* Should be the second entry in the table, plus the initial length field. */
|
|
if (_m64) {
|
|
STAssertEquals(fde_info.fde_offset, (pl_vm_address_t) ((sizeof(pl_cfi_entry)) + PL_CFI_LEN_SIZE_64), @"Incorrect offset");
|
|
STAssertEquals(fde_info.fde_length, (uint64_t)PL_CFI_SIZE_64, @"Incorrect length");
|
|
} else {
|
|
STAssertEquals(fde_info.fde_offset, (pl_vm_address_t) ((sizeof(pl_cfi_entry)) + PL_CFI_LEN_SIZE_32), @"Incorrect offset");
|
|
STAssertEquals(fde_info.fde_length, (uint64_t)PL_CFI_SIZE_32, @"Incorrect length");
|
|
}
|
|
|
|
//STAssertEquals(fde_info.fde_instruction_offset, (pl_vm_address_t)0x0, @"Incorrect instruction offset (should be the first entry)");
|
|
|
|
plcrash_async_dwarf_fde_info_free(&fde_info);
|
|
|
|
/* Verify that an unknown PC freturns ENOTFOUND */
|
|
err = _debug_reader.find_fde(0x0, PL_CFI_DEBUG_FRAME_PC+PL_CFI_DEBUG_FRAME_PC_RANGE, &fde_info);
|
|
STAssertEquals(PLCRASH_ENOTFOUND, err, @"FDE should not have been found");
|
|
}
|
|
|
|
@end
|
|
|
|
#endif /* PLCRASH_FEATURE_UNWIND_DWARF */
|