Files
plcrashreporter/Tests/PLCrashAsyncDwarfPrimitivesTests.mm
2020-04-27 12:49:57 +03:00

599 lines
28 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 "PLCrashAsyncDwarfPrimitives.hpp"
#include "PLCrashAsyncDwarfFDE.hpp"
#include "PLCrashFeatureConfig.h"
#include <inttypes.h>
#if PLCRASH_FEATURE_UNWIND_DWARF
using namespace plcrash::async;
@interface PLCrashAsyncDwarfPrimativesTests : PLCrashTestCase {
}
@end
@implementation PLCrashAsyncDwarfPrimativesTests
/**
* Test aligned pointer decoding
*/
- (void) testReadAlignedEncodedPointer {
plcrash_async_mobject_t mobj;
plcrash_error_t err;
uint64_t result;
size_t size;
/* 64-bit reader (supports both 32-bit and 64-bit test hosts) */
gnu_ehptr_reader<uint64_t> reader(plcrash_async_byteorder_big_endian());
/* Test data */
const uint8_t aligned_data[] = { 0xab, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb,
0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3 };
/* Default state; 1 byte shy of 8 byte alignment. */
reader.set_frame_section_base((uint64_t) aligned_data, (uint64_t) 1);
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) aligned_data, sizeof(aligned_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t) &aligned_data[0], 0, DW_EH_PE_aligned, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode aligned value");
/* The VM base is 1 byte shy of eight byte alignment. To align the pointer value, we'll have to skip 7 bytes. */
STAssertEquals(result, (uint64_t) 0xbcbdbebfc0c1c2c3, @"Incorrect value decoded, got 0%" PRIx64, (uint64_t) result);
STAssertEquals(size, (size_t)15, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
}
/**
* Test indirect pointer handling.
*/
- (void) testReadIndirectEncodedPointer {
plcrash_async_mobject_t mobj;
gnu_ehptr_reader<uint64_t> reader(&plcrash_async_byteorder_direct);
plcrash_error_t err;
uint64_t result;
size_t size;
/* Test data */
struct {
uint64_t udata8;
uint64_t ptr;
} test_data;
test_data.udata8 = (uint64_t) &test_data.ptr;
test_data.ptr = UINT32_MAX;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t) &test_data.udata8, 0, (DW_EH_PE_t) (DW_EH_PE_indirect|DW_EH_PE_udata8), &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode aligned value");
STAssertEquals(result, (uint64_t) test_data.ptr, @"Incorrect value decoded, got 0%" PRIx32, (uint32_t) result);
STAssertEquals(size, (size_t)8, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
}
/**
* Test pointer offset type handling
*/
- (void) testReadEncodedPointerOffset {
plcrash_async_mobject_t mobj;
gnu_ehptr_reader<uint64_t> reader(&plcrash_async_byteorder_direct);
plcrash_error_t err;
uint64_t result;
size_t size;
/* Test data */
union {
uint64_t udata8;
} test_data;
/* Default state */
#define T_TEXT_BASE 1
#define T_DATA_BASE 2
#define T_FUNC_BASE 3
reader.set_text_base(T_TEXT_BASE);
reader.set_data_base(T_DATA_BASE);
reader.set_func_base(T_FUNC_BASE);
/* Test absptr */
test_data.udata8 = UINT64_MAX;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t) &test_data, 0, DW_EH_PE_absptr, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uleb128");
STAssertEquals(result, (uint64_t)UINT64_MAX, @"Incorrect value decoded");
STAssertEquals(size, (size_t)8, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test pcrel */
test_data.udata8 = 5;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t) &test_data, 0, DW_EH_PE_pcrel, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode pcrel value");
STAssertEquals(result, (uint64_t)&test_data + 5, @"Incorrect value decoded");
STAssertEquals(size, (size_t)8, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test textrel */
test_data.udata8 = 5;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t) &test_data, 0, DW_EH_PE_textrel, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode textrel value");
STAssertEquals(result, (uint64_t)test_data.udata8+T_TEXT_BASE, @"Incorrect value decoded");
STAssertEquals(size, (size_t)8, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test datarel */
test_data.udata8 = 5;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t) &test_data, 0, DW_EH_PE_datarel, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode datarel value");
STAssertEquals(result, (uint64_t)test_data.udata8+T_DATA_BASE, @"Incorrect value decoded");
STAssertEquals(size, (size_t)8, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test funcrel */
test_data.udata8 = 5;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t) &test_data, 0, DW_EH_PE_funcrel, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode funcrel value");
STAssertEquals(result, (uint64_t)test_data.udata8+T_FUNC_BASE, @"Incorrect value decoded");
STAssertEquals(size, (size_t)8, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
}
/**
* Test pointer value type decoding.
*/
- (void) testReadEncodedPointerValue {
plcrash_async_mobject_t mobj;
gnu_ehptr_reader<uint64_t> reader(&plcrash_async_byteorder_direct);
plcrash_error_t err;
uint64_t result;
size_t size;
/* Test data */
union {
uint8_t leb128[2];
uint16_t udata2;
uint32_t udata4;
uint64_t udata8;
int16_t sdata2;
int16_t sdata4;
int16_t sdata8;
} test_data;
/* We use an -1 +1 offset below to verify the address+offset handling for all data types */
/* Test ULEB128 */
test_data.leb128[0] = 2;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t)&test_data-1, 1, DW_EH_PE_uleb128, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uleb128");
STAssertEquals(result, (uint64_t)2, @"Incorrect value decoded");
STAssertEquals(size, (size_t)1, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test udata2 */
test_data.udata2 = UINT16_MAX;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t)&test_data-1, 1, DW_EH_PE_udata2, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode udata2");
STAssertEquals(result, (uint64_t)UINT16_MAX, @"Incorrect value decoded");
STAssertEquals(size, (size_t)2, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test udata4 */
test_data.udata4 = UINT32_MAX;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t)&test_data-1, 1, DW_EH_PE_udata4, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode udata4");
STAssertEquals(result, (uint64_t)UINT32_MAX, @"Incorrect value decoded");
STAssertEquals(size, (size_t)4, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test udata8 */
test_data.udata8 = UINT64_MAX;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t)&test_data-1, 1, DW_EH_PE_udata8, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode udata8");
STAssertEquals(result, (uint64_t)UINT64_MAX, @"Incorrect value decoded");
STAssertEquals(size, (size_t)8, @"Incorrect byte length");
/* Test SLEB128 (including pcrel validation to ensure that signed values are handled as offsets) */
test_data.leb128[0] = 0x7e; // -2
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t)&test_data-1, 1, (DW_EH_PE_t)(DW_EH_PE_pcrel|DW_EH_PE_sleb128), &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode sleb128");
STAssertEquals(result, ((uint64_t) &test_data) - 2, @"Incorrect value decoded");
STAssertEquals(size, (size_t)1, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test sdata2 (including pcrel validation) */
test_data.sdata2 = -256;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t)&test_data-1, 1, (DW_EH_PE_t)(DW_EH_PE_pcrel|DW_EH_PE_sdata2), &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode udata2");
STAssertEquals(result, ((uint64_t) &test_data) - 256, @"Incorrect value decoded");
STAssertEquals(size, (size_t)2, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test sdata4 (including pcrel validation) */
test_data.sdata4 = -256;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t)&test_data-1, 1, (DW_EH_PE_t)(DW_EH_PE_pcrel|DW_EH_PE_sdata4), &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode sdata4");
STAssertEquals(result, ((uint64_t) &test_data) - 256, @"Incorrect value decoded");
STAssertEquals(size, (size_t)4, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test sdata8 (including pcrel validation) */
test_data.sdata8 = -256;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = reader.read(&mobj, (pl_vm_address_t)&test_data-1, 1, (DW_EH_PE_t)(DW_EH_PE_pcrel|DW_EH_PE_sdata8), &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode udata8");
STAssertEquals(result, ((uint64_t) &test_data) - 256, @"Incorrect value decoded");
STAssertEquals(size, (size_t)8, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
}
/**
* Test ULEB128 parsing.
*/
- (void) testReadULEB128 {
/* Configure test */
uint8_t buffer[11];
plcrash_async_mobject_t mobj;
plcrash_error_t err;
uint64_t result;
pl_vm_size_t size;
/* Test offset handling */
buffer[0] = 2;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, sizeof(buffer), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_uleb128(&mobj, (pl_vm_address_t) buffer+1, -1, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uleb128");
STAssertEquals(result, (uint64_t)2, @"Incorrect value decoded");
STAssertEquals(size, (pl_vm_size_t)1, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test a single byte */
buffer[0] = 2;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, sizeof(buffer), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_uleb128(&mobj, (pl_vm_address_t) buffer, 0, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uleb128");
STAssertEquals(result, (uint64_t)2, @"Incorrect value decoded");
STAssertEquals(size, (pl_vm_size_t)1, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test multi-byte */
buffer[0] = 0+0x80;
buffer[1] = 1;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, sizeof(buffer), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_uleb128(&mobj, (pl_vm_address_t) buffer, 0, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uleb128");
STAssertEquals(result, (uint64_t)128, @"Incorrect value decoded");
STAssertEquals(size, (pl_vm_size_t)2, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test UINT64_MAX */
memset(buffer, 0xFF, sizeof(buffer));
buffer[9] = 0x7F;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, sizeof(buffer), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_uleb128(&mobj, (pl_vm_address_t) buffer, 0, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uleb128");
STAssertEquals(result, (uint64_t)UINT64_MAX, @"Incorrect value decoded");
STAssertEquals(size, (pl_vm_size_t)10, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test handling of an integer larger than 64 bits. */
memset(buffer, 0x80, sizeof(buffer));
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, sizeof(buffer), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_uleb128(&mobj, (pl_vm_address_t) buffer, 0, &result, &size);
STAssertEquals(err, PLCRASH_ENOTSUP, @"ULEB128 should not be decodable");
plcrash_async_mobject_free(&mobj);
/* Test end-of-buffer handling */
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, 1, true), @"Failed to initialize mobj mapping");
buffer[0] = 1+0x80;
err = plcrash_async_dwarf_read_uleb128(&mobj, (pl_vm_address_t) buffer, 0, &result, &size);
STAssertEquals(err, PLCRASH_EINVAL, @"ULEB128 should not be decodable");
plcrash_async_mobject_free(&mobj);
}
/**
* Test direct task-based reading of a ULEB128 value. This uses the same ULEB128 parser as the plcrash_async_dwarf_read_uleb128() code,
* so we only test that the out-of-process memory read works as expected.
*/
- (void) readTaskULEB128 {
/* Configure test */
plcrash_async_mobject_t mobj;
plcrash_error_t err;
uint64_t result;
pl_vm_size_t size;
/* Test offset handling */
uint8_t buffer[] = { 2 };
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, sizeof(buffer), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_task_uleb128(mach_task_self(), (pl_vm_address_t) buffer+1, -1, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uleb128");
STAssertEquals(result, (uint64_t)2, @"Incorrect value decoded");
STAssertEquals(size, (pl_vm_size_t)1, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
}
/**
* Test uintmax64 reading.
*/
- (void) testReadUintMax64 {
plcrash_async_mobject_t mobj;
plcrash_error_t err;
uint64_t result;
/* Test data */
union {
uint8_t udata1;
uint16_t udata2;
uint32_t udata4;
uint64_t udata8;
} test_data;
/* uint8_t */
test_data.udata1 = UINT8_MAX;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_uintmax64(&mobj, &plcrash_async_byteorder_direct, ((pl_vm_address_t)&test_data)-1, 1, 1, &result);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uint8_t");
STAssertEquals(result, (uint64_t)UINT8_MAX, @"Incorrect value decoded");
plcrash_async_mobject_free(&mobj);
/* uint16_t */
test_data.udata2 = UINT16_MAX;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_uintmax64(&mobj, &plcrash_async_byteorder_direct, ((pl_vm_address_t)&test_data)-1, 1, 2, &result);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uint16_t");
STAssertEquals(result, (uint64_t)UINT16_MAX, @"Incorrect value decoded");
plcrash_async_mobject_free(&mobj);
/* uint32_t */
test_data.udata4 = UINT32_MAX;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_uintmax64(&mobj, &plcrash_async_byteorder_direct, ((pl_vm_address_t)&test_data)-1, 1, 4, &result);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uint32_t");
STAssertEquals(result, (uint64_t)UINT32_MAX, @"Incorrect value decoded");
plcrash_async_mobject_free(&mobj);
/* uint64_t */
test_data.udata8 = UINT64_MAX;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_uintmax64(&mobj, &plcrash_async_byteorder_direct, ((pl_vm_address_t)&test_data)-1, 1, 8, &result);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uint64_t");
STAssertEquals(result, (uint64_t)UINT64_MAX, @"Incorrect value decoded");
plcrash_async_mobject_free(&mobj);
/* Invalid size */
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &test_data, sizeof(test_data), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_uintmax64(&mobj, &plcrash_async_byteorder_direct, ((pl_vm_address_t)&test_data)-1, 1, 3, &result);
STAssertNotEquals(err, PLCRASH_ESUCCESS, @"Expected error with invalid byte size of 3");
plcrash_async_mobject_free(&mobj);
}
/**
* Test task-based uintmax64 reading.
*/
- (void) testReadTaskUintMax64 {
plcrash_error_t err;
uint64_t result;
/* Test data */
union {
uint8_t udata1;
uint16_t udata2;
uint32_t udata4;
uint64_t udata8;
} test_data;
/* uint8_t */
test_data.udata1 = UINT8_MAX;
err = plcrash_async_dwarf_read_task_uintmax64(mach_task_self(), &plcrash_async_byteorder_direct, ((pl_vm_address_t)&test_data)-1, 1, 1, &result);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uint8_t");
STAssertEquals(result, (uint64_t)UINT8_MAX, @"Incorrect value decoded");
/* uint16_t */
test_data.udata2 = UINT16_MAX;
err = plcrash_async_dwarf_read_task_uintmax64(mach_task_self(), &plcrash_async_byteorder_direct, ((pl_vm_address_t)&test_data)-1, 1, 2, &result);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uint16_t");
STAssertEquals(result, (uint64_t)UINT16_MAX, @"Incorrect value decoded");
/* uint32_t */
test_data.udata4 = UINT32_MAX;
err = plcrash_async_dwarf_read_task_uintmax64(mach_task_self(), &plcrash_async_byteorder_direct, ((pl_vm_address_t)&test_data)-1, 1, 4, &result);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uint32_t");
STAssertEquals(result, (uint64_t)UINT32_MAX, @"Incorrect value decoded");
/* uint64_t */
test_data.udata8 = UINT64_MAX;
err = plcrash_async_dwarf_read_task_uintmax64(mach_task_self(), &plcrash_async_byteorder_direct, ((pl_vm_address_t)&test_data)-1, 1, 8, &result);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode uint64_t");
STAssertEquals(result, (uint64_t)UINT64_MAX, @"Incorrect value decoded");
/* Invalid size */
err = plcrash_async_dwarf_read_task_uintmax64(mach_task_self(), &plcrash_async_byteorder_direct, ((pl_vm_address_t)&test_data)-1, 1, 3, &result);
STAssertNotEquals(err, PLCRASH_ESUCCESS, @"Expected error with invalid byte size of 3");
}
/**
* Test SLEB128 parsing.
*/
- (void) testReadSLEB128 {
/* Configure test */
uint8_t buffer[11];
plcrash_async_mobject_t mobj;
plcrash_error_t err;
int64_t result;
pl_vm_size_t size;
/* Test offset handling */
buffer[0] = 2;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, sizeof(buffer), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_sleb128(&mobj, (pl_vm_address_t) buffer+1, -1, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode sleb128");
STAssertEquals(result, (int64_t)2, @"Incorrect value decoded");
STAssertEquals(size, (pl_vm_size_t)1, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test a single byte */
buffer[0] = 2;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, sizeof(buffer), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_sleb128(&mobj, (pl_vm_address_t) buffer, 0, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode sleb128");
STAssertEquals(result, (int64_t)2, @"Incorrect value decoded");
STAssertEquals(size, (pl_vm_size_t)1, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test single (negative) byte */
buffer[0] = 0x7e;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, sizeof(buffer), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_sleb128(&mobj, (pl_vm_address_t) buffer, 0, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode sleb128");
STAssertEquals(result, (int64_t)-2, @"Incorrect value decoded");
STAssertEquals(size, (pl_vm_size_t)1, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test multi-byte */
buffer[0] = 0+0x80;
buffer[1] = 1;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, sizeof(buffer), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_sleb128(&mobj, (pl_vm_address_t) buffer, 0, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode sleb128");
STAssertEquals(result, (int64_t)128, @"Incorrect value decoded");
STAssertEquals(size, (pl_vm_size_t)2, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test -INT64_MAX */
memset(buffer, 0x80, sizeof(buffer));
buffer[9] = 0x7f;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, sizeof(buffer), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_sleb128(&mobj, (pl_vm_address_t) buffer, 0, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode sleb128");
STAssertEquals(result, INT64_MIN, @"Incorrect value decoded");
STAssertEquals(size, (pl_vm_size_t)10, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
/* Test handling of an integer larger than 64 bits. */
memset(buffer, 0x80, sizeof(buffer));
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, sizeof(buffer), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_sleb128(&mobj, (pl_vm_address_t) buffer, 0, &result, &size);
STAssertEquals(err, PLCRASH_ENOTSUP, @"SLEB128 should not be decodable");
plcrash_async_mobject_free(&mobj);
/* Test end-of-buffer handling */
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, 1, true), @"Failed to initialize mobj mapping");
buffer[0] = 1+0x80;
err = plcrash_async_dwarf_read_sleb128(&mobj, (pl_vm_address_t) buffer, 0, &result, &size);
STAssertEquals(err, PLCRASH_EINVAL, @"SLEB128 should not be decodable");
plcrash_async_mobject_free(&mobj);
}
/**
* Test direct task-based reading of a SLEB128 value. This uses the same SLEB128 parser as the plcrash_async_dwarf_read_sleb128() code,
* so we only test that the out-of-process memory read works as expected.
*/
- (void) readTaskSLEB128 {
/* Configure test */
plcrash_async_mobject_t mobj;
plcrash_error_t err;
int64_t result;
pl_vm_size_t size;
/* Test offset handling */
uint8_t buffer[] = { 2 };
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) buffer, sizeof(buffer), true), @"Failed to initialize mobj mapping");
err = plcrash_async_dwarf_read_sleb128(&mobj, (pl_vm_address_t) buffer+1, -1, &result, &size);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to decode sleb128");
STAssertEquals(result, (int64_t)2, @"Incorrect value decoded");
STAssertEquals(size, (pl_vm_size_t)1, @"Incorrect byte length");
plcrash_async_mobject_free(&mobj);
}
@end
#endif /* PLCRASH_FEATURE_UNWIND_DWARF */