215 строки
8.1 KiB
Plaintext
215 строки
8.1 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 "dwarf_opstream.hpp"
|
||
|
|
||
|
#include "PLCrashFeatureConfig.h"
|
||
|
|
||
|
#if PLCRASH_FEATURE_UNWIND_DWARF
|
||
|
|
||
|
using namespace plcrash::async;
|
||
|
|
||
|
@interface dwarf_opstream_tests : PLCrashTestCase {
|
||
|
@private
|
||
|
}
|
||
|
@end
|
||
|
|
||
|
/**
|
||
|
* Test DWARF stack handling.
|
||
|
*/
|
||
|
@implementation dwarf_opstream_tests
|
||
|
|
||
|
/**
|
||
|
* Test integer read (and byteswapping) from an opcode stream.
|
||
|
*/
|
||
|
- (void) testReadIntU {
|
||
|
plcrash_async_mobject_t mobj;
|
||
|
uint8_t opcodes[] = { 0x1, 0x2, 0x3 };
|
||
|
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t)&opcodes, sizeof(opcodes), true), @"Failed to initialize mobj");
|
||
|
|
||
|
dwarf_opstream stream;
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, stream.init(&mobj, plcrash_async_byteorder_big_endian(), (pl_vm_address_t)&opcodes, 0, sizeof(opcodes)), @"Failed to initialize opcode stream");
|
||
|
|
||
|
uint16_t val1;
|
||
|
uint8_t val2;
|
||
|
STAssertTrue(stream.read_intU(&val1), @"Failed to read");
|
||
|
STAssertTrue(stream.read_intU(&val2), @"Failed to read");
|
||
|
STAssertFalse(stream.read_intU(&val2), @"Read off the end of the opcode stream");
|
||
|
|
||
|
STAssertEquals(val1, (uint16_t)0x102, @"Incorrect 16 byte value read");
|
||
|
STAssertEquals(val2, (uint8_t)0x3, @"Incorrect 8 byte value read");
|
||
|
|
||
|
plcrash_async_mobject_free(&mobj);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test uintmax64 read from an opcode stream.
|
||
|
*/
|
||
|
- (void) testReadMax64 {
|
||
|
plcrash_async_mobject_t mobj;
|
||
|
uint8_t opcodes[] = { 0x1, 0x2, 0x3 };
|
||
|
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t)&opcodes, sizeof(opcodes), true), @"Failed to initialize mobj");
|
||
|
|
||
|
dwarf_opstream stream;
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, stream.init(&mobj, plcrash_async_byteorder_big_endian(), (pl_vm_address_t)&opcodes, 0, sizeof(opcodes)), @"Failed to initialize opcode stream");
|
||
|
|
||
|
uint64_t val1;
|
||
|
uint64_t val2;
|
||
|
STAssertTrue(stream.read_uintmax64(2, &val1), @"Failed to read");
|
||
|
STAssertEquals(val1, (uint64_t)0x102, @"Incorrect 16 byte value read");
|
||
|
|
||
|
STAssertTrue(stream.read_uintmax64(1, &val2), @"Failed to read");
|
||
|
STAssertEquals(val2, (uint64_t)0x3, @"Incorrect 8 byte value read");
|
||
|
|
||
|
STAssertFalse(stream.read_uintmax64(1, &val2), @"Read off the end of the opcode stream");
|
||
|
|
||
|
plcrash_async_mobject_free(&mobj);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test uleb128 read from an opcode stream.
|
||
|
*/
|
||
|
- (void) testReadULEB128 {
|
||
|
plcrash_async_mobject_t mobj;
|
||
|
uint8_t opcodes[] = { 0x1 };
|
||
|
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t)&opcodes, sizeof(opcodes), true), @"Failed to initialize mobj");
|
||
|
|
||
|
dwarf_opstream stream;
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, stream.init(&mobj, plcrash_async_byteorder_big_endian(), (pl_vm_address_t)&opcodes, 0, sizeof(opcodes)), @"Failed to initialize opcode stream");
|
||
|
|
||
|
uint64_t val;
|
||
|
STAssertTrue(stream.read_uleb128(&val), @"Failed to read");
|
||
|
STAssertEquals(val, (uint64_t)0x1, @"Incorrect value read");
|
||
|
|
||
|
plcrash_async_mobject_free(&mobj);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test sleb128 read from an opcode stream.
|
||
|
*/
|
||
|
- (void) testReadSLEB128 {
|
||
|
plcrash_async_mobject_t mobj;
|
||
|
uint8_t opcodes[] = { 0x1 };
|
||
|
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t)&opcodes, sizeof(opcodes), true), @"Failed to initialize mobj");
|
||
|
|
||
|
dwarf_opstream stream;
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, stream.init(&mobj, plcrash_async_byteorder_big_endian(), (pl_vm_address_t)&opcodes, 0, sizeof(opcodes)), @"Failed to initialize opcode stream");
|
||
|
|
||
|
int64_t val;
|
||
|
STAssertTrue(stream.read_sleb128(&val), @"Failed to read");
|
||
|
STAssertEquals(val, (int64_t)0x1, @"Incorrect value read");
|
||
|
|
||
|
plcrash_async_mobject_free(&mobj);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test pointer read from an opcode stream.
|
||
|
*/
|
||
|
- (void) testReadGNUEHPointer {
|
||
|
plcrash_async_mobject_t mobj;
|
||
|
|
||
|
/* Set up an opcode stream with a 4 byte 'pointer' value */
|
||
|
uint8_t opcodes[] = { 0x1, 0x2, 0x3, 0x4 };
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t)&opcodes, sizeof(opcodes), true), @"Failed to initialize mobj");
|
||
|
|
||
|
/* Configure the stream */
|
||
|
dwarf_opstream stream;
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, stream.init(&mobj, plcrash_async_byteorder_big_endian(), (pl_vm_address_t)&opcodes, 0, sizeof(opcodes)), @"Failed to initialize opcode stream");
|
||
|
|
||
|
/* Configure the pointer state */
|
||
|
uint32_t result;
|
||
|
gnu_ehptr_reader<uint32_t> ptr_state(plcrash_async_byteorder_big_endian());
|
||
|
|
||
|
/* Test the read handling */
|
||
|
STAssertTrue(stream.read_gnueh_ptr(&ptr_state, DW_EH_PE_absptr, &result), @"Failed to read the pointer");
|
||
|
STAssertEquals(result, (uint32_t)0x1020304, @"Incorrect pointer value read");
|
||
|
|
||
|
/* Test overshoot handling */
|
||
|
STAssertTrue(stream.skip(-1), @"Failed to rewind stream");
|
||
|
STAssertFalse(stream.read_gnueh_ptr(&ptr_state, DW_EH_PE_absptr, &result), @"Succeeded when attempting to read past the end of the mapped opcode stream");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test skip handling.
|
||
|
*/
|
||
|
- (void) testSkip {
|
||
|
plcrash_async_mobject_t mobj;
|
||
|
uint8_t opcodes[] = { 0x1, 0x2, 0x3 };
|
||
|
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t)&opcodes, sizeof(opcodes), true), @"Failed to initialize mobj");
|
||
|
|
||
|
dwarf_opstream stream;
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, stream.init(&mobj, plcrash_async_byteorder_big_endian(), (pl_vm_address_t)&opcodes, 0, sizeof(opcodes)), @"Failed to initialize opcode stream");
|
||
|
|
||
|
/* Skip one, verify read */
|
||
|
uint8_t val;
|
||
|
STAssertTrue(stream.skip(1), @"Failed to skip within bounds");
|
||
|
STAssertTrue(stream.read_intU(&val), @"Failed to read");
|
||
|
STAssertEquals(val, (uint8_t)0x2, @"Incorrect byte value read");
|
||
|
|
||
|
/* Test bounds checking */
|
||
|
STAssertTrue(stream.skip(1), @"Failed to skip to end of stream");
|
||
|
STAssertFalse(stream.skip(1), @"Skipped past end of stream");
|
||
|
|
||
|
STAssertTrue(stream.skip(-3), @"Failed to skip to beginning of stream");
|
||
|
STAssertFalse(stream.skip(-1), @"Skipped past beginning of stream");
|
||
|
|
||
|
plcrash_async_mobject_free(&mobj);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test position getter.
|
||
|
*/
|
||
|
- (void) testGetPosition {
|
||
|
plcrash_async_mobject_t mobj;
|
||
|
uint8_t opcodes[] = { 0x1, 0x2 };
|
||
|
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t)&opcodes, sizeof(opcodes), true), @"Failed to initialize mobj");
|
||
|
|
||
|
dwarf_opstream stream;
|
||
|
STAssertEquals(PLCRASH_ESUCCESS, stream.init(&mobj, plcrash_async_byteorder_big_endian(), (pl_vm_address_t)&opcodes, 0, sizeof(opcodes)), @"Failed to initialize opcode stream");
|
||
|
|
||
|
/* Position smoke test. */
|
||
|
STAssertEquals(stream.get_position(), (uintptr_t)0, @"Incorrect position");
|
||
|
STAssertTrue(stream.skip(1), @"Failed to skip within bounds");
|
||
|
STAssertEquals(stream.get_position(), (uintptr_t)1, @"Incorrect position");
|
||
|
|
||
|
plcrash_async_mobject_free(&mobj);
|
||
|
}
|
||
|
|
||
|
|
||
|
@end
|
||
|
|
||
|
#endif /* PLCRASH_FEATURE_UNWIND_DWARF */
|