Files
UnrealEngine/Engine/Source/ThirdParty/PLCrashReporter/PLCrashReporter-1.12.0/Tests/PLCrashAsyncDwarfCIETests.mm
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

246 lines
10 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 "PLCrashAsyncDwarfCIE.hpp"
#include "PLCrashAsyncDwarfFDE.hpp"
#include "PLCrashFeatureConfig.h"
#if PLCRASH_FEATURE_UNWIND_DWARF
using namespace plcrash::async;
struct __attribute__((packed)) cie_data {
struct __attribute__((packed)) {
uint32_t l1;
uint64_t l2;
} length;
uint64_t cie_id;
uint8_t cie_version;
uint8_t augmentation[7];
uint8_t address_size;
uint8_t segment_size;
uint8_t code_alignment_factor;
uint8_t data_alignment_factor;
uint8_t return_address_register;
uint8_t augmentation_data[6];
/* We don't supply any instructions below; this array exists to test the initial_instruction_length handling */
uint8_t initial_instructions[4];
};
@interface PLCrashAsyncDwarfCIETests : PLCrashTestCase {
struct cie_data _cie_data;
gnu_ehptr_reader<uint64_t> *_ptr_state;
}@end
@implementation PLCrashAsyncDwarfCIETests
- (void) setUp {
/* Set up the default pointer decode state. */
_ptr_state = new gnu_ehptr_reader<uint64_t>(&plcrash_async_byteorder_direct);
/* Set up default CIE data */
_cie_data.length.l1 = UINT32_MAX; /* 64-bit entry flag */
_cie_data.length.l2 = sizeof(_cie_data) - sizeof(_cie_data.length);
_cie_data.cie_id = 0x0;
_cie_data.cie_version = 4;
_cie_data.augmentation[0] = 'z';
_cie_data.augmentation[1] = 'L'; // LSDA encoding
_cie_data.augmentation[2] = 'P'; // Personality encoding
_cie_data.augmentation[3] = 'R'; // FDE address encoding
_cie_data.augmentation[4] = 'S'; // Signal frame
_cie_data.augmentation[5] = 'b'; // known-bad augmentation flag; used to test termination of parsing
_cie_data.augmentation[6] = '\0';
/* NOTE: This is a ULEB128 value, and thus will fail if it's not representable in the first 7 bits */
_cie_data.augmentation_data[0] = sizeof(_cie_data.augmentation_data ) - 1 /* size, minus this field */;
STAssertEquals((uint8_t)(_cie_data.augmentation_data[0] & 0x7f), _cie_data.augmentation_data[0], @"ULEB128 encoding will not fit in the available byte");
_cie_data.augmentation_data[1] = DW_EH_PE_udata4; // LSDA encoding
_cie_data.augmentation_data[2] = DW_EH_PE_udata2; // Personality pointer encoding
_cie_data.augmentation_data[3] = 0xAA; // Personality udata2 pointer data
_cie_data.augmentation_data[4] = 0xAA; // Personality udata2 pointer data
_cie_data.augmentation_data[5] = DW_EH_PE_udata8; // FDE address pointer encoding.
_cie_data.address_size = 4;
_cie_data.segment_size = 4;
_cie_data.code_alignment_factor = 1;
_cie_data.data_alignment_factor = 2;
_cie_data.return_address_register = 3;
_cie_data.initial_instructions[0] = 0xA;
_cie_data.initial_instructions[1] = 0xB;
_cie_data.initial_instructions[2] = 0xC;
_cie_data.initial_instructions[3] = 0xD;
}
- (void) tearDown {
delete _ptr_state;
}
/**
* Test default (standard path, no error) CIE parsing
*/
- (void) testParseCIE {
plcrash_async_dwarf_cie_info_t cie;
plcrash_async_mobject_t mobj;
plcrash_error_t err;
err = plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &_cie_data, sizeof(_cie_data), true);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to initialize mobj");
/* Try to parse the CIE */
pl_vm_size_t cie_length = sizeof(_cie_data) - sizeof(_cie_data.length);
err = plcrash_async_dwarf_cie_info_init(&cie, &mobj, &plcrash_async_byteorder_direct, _ptr_state, (pl_vm_address_t) &_cie_data);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to initialize CIE info");
STAssertEquals(cie.cie_offset, (uint64_t)sizeof(_cie_data.length), @"Incorrect offset");
STAssertEquals(cie.cie_length, (uint64_t)cie_length, @"Incorrect length");
/* Test basics */
STAssertEquals(cie.cie_id, _cie_data.cie_id, @"Incorrect ID");
STAssertEquals(cie.cie_version, _cie_data.cie_version, @"Incorrect version");
/* DWARF4 fields */
STAssertEquals(cie.address_size, _cie_data.address_size, @"Incorrect address size");
STAssertEquals(cie.segment_size, _cie_data.segment_size, @"Incorrect segment size");
/* Alignment and return address fields */
STAssertEquals(cie.code_alignment_factor, (uint64_t)_cie_data.code_alignment_factor, @"Incorrect code alignment factor");
STAssertEquals(cie.data_alignment_factor, (int64_t)_cie_data.data_alignment_factor, @"Incorrect data alignment factor");
STAssertEquals(cie.return_address_register, (uint64_t)_cie_data.return_address_register, @"Incorrect return address register");
/* Augmentation handling */
STAssertTrue(cie.has_eh_augmentation, @"No augmentation data was found");
STAssertTrue(cie.eh_augmentation.has_lsda_encoding, @"No LSDA data was found");
STAssertEquals(cie.eh_augmentation.lsda_encoding, (uint8_t)DW_EH_PE_udata4, @"Incorrect LSDA encoding");
STAssertTrue(cie.eh_augmentation.has_personality_address, @"No personality data was found");
STAssertEquals(cie.eh_augmentation.personality_address, (uint64_t)0xAAAA, @"Incorrect personality address");
STAssertTrue(cie.eh_augmentation.has_pointer_encoding, @"No pointer encoding was found");
STAssertEquals(cie.eh_augmentation.pointer_encoding, (uint8_t)DW_EH_PE_udata8, @"Incorrect pointer encoding");
STAssertTrue(cie.eh_augmentation.signal_frame, @"Did not parse signal frame flag");
/* Instructions */
STAssertEquals(plcrash_async_dwarf_cie_info_initial_instructions_offset(&cie), ((pl_vm_address_t)_cie_data.initial_instructions) - (pl_vm_address_t) &_cie_data, @"Incorrect initial instruction offset");
STAssertEquals(plcrash_async_dwarf_cie_info_initial_instructions_length(&cie), (pl_vm_size_t) sizeof(_cie_data.initial_instructions), @"Incorrect instruction length");
for (int i = 0; i < sizeof(_cie_data.initial_instructions) / sizeof(_cie_data.initial_instructions[0]); i++) {
uint8_t opcode;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_read_uint8(&mobj, (pl_vm_address_t) &_cie_data, plcrash_async_dwarf_cie_info_initial_instructions_offset(&cie)+i, &opcode), @"Failed to read instruction");
STAssertEquals((uint8_t)(0xA+i), opcode, @"Incorrect opcode");
}
/* Clean up */
plcrash_async_dwarf_cie_info_free(&cie);
plcrash_async_mobject_free(&mobj);
}
/**
* Test parsing of a CIE entry with an unknown augmentation string
*/
- (void) testParseCIEBadAugmentation {
plcrash_async_dwarf_cie_info_t cie;
plcrash_async_mobject_t mobj;
plcrash_error_t err;
_cie_data.augmentation[0] = 'P';
err = plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &_cie_data, sizeof(_cie_data), true);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to initialize mobj");
/* Try to parse the CIE, verify failure */
err = plcrash_async_dwarf_cie_info_init(&cie, &mobj, &plcrash_async_byteorder_direct, _ptr_state, (pl_vm_address_t) &_cie_data);
STAssertNotEquals(err, PLCRASH_ESUCCESS, @"Failed to initialize CIE info");
/* Clean up */
plcrash_async_dwarf_cie_info_free(&cie);
plcrash_async_mobject_free(&mobj);
}
/**
* Test parsing of a CIE entry with a bad identifier.
*/
- (void) testParseCIEBadIdentifier {
plcrash_async_dwarf_cie_info_t cie;
plcrash_async_mobject_t mobj;
plcrash_error_t err;
_cie_data.cie_id = 5; // invalid id
err = plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &_cie_data, sizeof(_cie_data), true);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to initialize mobj");
/* Try to parse the CIE, verify failure */
err = plcrash_async_dwarf_cie_info_init(&cie, &mobj, &plcrash_async_byteorder_direct, _ptr_state, (pl_vm_address_t) &_cie_data);
STAssertNotEquals(err, PLCRASH_ESUCCESS, @"Failed to initialize CIE info");
/* Clean up */
plcrash_async_dwarf_cie_info_free(&cie);
plcrash_async_mobject_free(&mobj);
}
/**
* Test parsing of a CIE entry with a bad version.
*/
- (void) testParseCIEBadVersion {
plcrash_async_dwarf_cie_info_t cie;
plcrash_async_mobject_t mobj;
plcrash_error_t err;
_cie_data.cie_version = (uint8_t)9999; // invalid version
err = plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t) &_cie_data, sizeof(_cie_data), true);
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to initialize mobj");
/* Try to parse the CIE, verify failure */
err = plcrash_async_dwarf_cie_info_init(&cie, &mobj, &plcrash_async_byteorder_direct, _ptr_state, (pl_vm_address_t) &_cie_data);
STAssertNotEquals(err, PLCRASH_ESUCCESS, @"Failed to initialize CIE info");
/* Clean up */
plcrash_async_dwarf_cie_info_free(&cie);
plcrash_async_mobject_free(&mobj);
}
@end
#endif /* PLCRASH_FEATURE_UNWIND_DWARF */