2013-02-28 21:17:30 +04:00
/ *
* Copyright ( c ) 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 .
* /
2013-05-22 20:49:14 +04:00
# import "PLCrashTestCase.h"
2013-02-28 23:26:16 +04:00
# import "PLCrashAsyncCompactUnwindEncoding.h"
2013-02-28 21:17:30 +04:00
# import "PLCrashAsyncMachOImage.h"
2013-09-28 02:04:23 +04:00
# import "PLCrashFeatureConfig.h"
# import "PLCrashCompatConstants.h"
2013-07-17 02:34:42 +04:00
2013-02-28 21:17:30 +04:00
# import < TargetConditionals . h >
# import < mach - o / fat . h >
# import < mach - o / arch . h >
2013-03-07 02:06:18 +04:00
# import < mach - o / dyld . h >
2013-02-28 21:17:30 +04:00
2013-07-17 02:34:42 +04:00
# if PLCRASH_FEATURE _UNWIND _COMPACT
2020-05-12 15:03:41 +03:00
# if TARGET_OS _MAC && ( ! TARGET_OS _IPHONE || TARGET_OS _MACCATALYST )
2013-02-28 21:17:30 +04:00
# define TEST_BINARY @ "test.macosx"
2019-12-17 16:39:29 +03:00
# elif TARGET_OS _SIMULATOR
2013-02-28 21:17:30 +04:00
# define TEST_BINARY @ "test.sim"
# elif TARGET_OS _IPHONE
# define TEST_BINARY @ "test.ios"
# else
# error Unsupported target
# endif
2013-03-15 00:09:27 +04:00
/ * The base PC value hard coded in our test CFE data * /
2013-03-14 21:11:49 +04:00
# define BASE_PC 0
2013-03-15 00:09:27 +04:00
/ * PC to use for the compact - common test * /
2013-03-14 22:40:01 +04:00
# define PC_COMPACT _COMMON ( BASE_PC + 1 )
2013-03-15 00:09:27 +04:00
# define PC_COMPACT _COMMON _ENCODING ( UNWIND_X86 _64 _MODE _DWARF | PC_COMPACT _COMMON )
2013-03-13 03:09:51 +04:00
2013-03-15 00:09:27 +04:00
/ * PC to use for the compact - private test * /
2013-03-14 23:47:17 +04:00
# define PC_COMPACT _PRIVATE ( BASE_PC + 2 )
2013-03-15 00:09:27 +04:00
# define PC_COMPACT _PRIVATE _ENCODING ( UNWIND_X86 _64 _MODE _DWARF | PC_COMPACT _PRIVATE )
/ * PC to use for the regular - common test * /
# define PC_REGULAR ( BASE_PC + 10 )
# define PC_REGULAR _ENCODING ( UNWIND_X86 _64 _MODE _DWARF | PC_REGULAR )
2013-03-14 23:47:17 +04:00
2013-02-28 21:17:30 +04:00
/ * *
* @ internal
*
* This code tests compact frame unwinding .
* /
2013-05-22 20:49:14 +04:00
@ interface PLCrashAsyncCompactUnwindEncodingTests : PLCrashTestCase {
2013-02-28 21:17:30 +04:00
@ private
/ * * The parsed Mach - O file ( this will be a subset of _imageData ) * /
2013-03-01 01:21:42 +04:00
plcrash_async _macho _t _image ;
2013-03-14 21:11:49 +04:00
/ * * The mapped unwind data * /
plcrash_async _mobject _t _unwind _mobj ;
/ * * The CFE reader * /
plcrash_async _cfe _reader _t _reader ;
2013-02-28 21:17:30 +04:00
}
@ end
@ implementation PLCrashAsyncCompactUnwindEncodingTests
- ( void ) setUp {
2013-03-07 22:11:03 +04:00
/ *
* 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 .
* /
2013-02-28 21:17:30 +04:00
2013-05-23 21:17:26 +04:00
/ * Load and parse the Mach - o image . * /
2013-02-28 21:17:30 +04:00
plcrash_error _t err ;
2013-05-23 21:17:26 +04:00
NSData * mappedImage = [ self nativeBinaryFromTestResource : TEST_BINARY ] ;
2013-02-28 21:17:30 +04:00
2020-04-30 14:06:32 +03:00
err = plcrash_nasync _macho _init ( & _image , mach_task _self ( ) , [ TEST_BINARY UTF8String ] , ( pl_vm _address _t ) [ mappedImage bytes ] ) ;
2013-02-28 21:17:30 +04:00
STAssertEquals ( err , PLCRASH_ESUCCESS , @ "Failed to initialize Mach-O parser" ) ;
2013-03-14 21:11:49 +04:00
/ * Map the unwind section * /
err = plcrash_async _macho _map _section ( & _image , SEG_TEXT , "__unwind_info" , & _unwind _mobj ) ;
STAssertEquals ( err , PLCRASH_ESUCCESS , @ "Failed to map unwind info" ) ;
/ * Initialize the CFE reader * /
2013-09-23 23:04:39 +04:00
# if ! defined ( __i386 __ ) || ! defined ( __x86 _64 __ ) || ! defined ( __arm64 __ )
/ * CFE is currently only supported for x86 / x86 -64 / arm64 , but our target binaries are not architecture specific ;
* we fudge the type reported to the reader to allow us to test the reader on ARM32 anyway . * /
2013-05-06 22:51:55 +04:00
cpu_type _t cputype = CPU_TYPE _X86 ;
# else
2013-03-14 21:11:49 +04:00
cpu_type _t cputype = _image . byteorder -> swap32 ( _image . header . cputype ) ;
2013-05-06 22:51:55 +04:00
# endif
2013-03-14 21:11:49 +04:00
err = plcrash_async _cfe _reader _init ( & _reader , & _unwind _mobj , cputype ) ;
STAssertEquals ( err , PLCRASH_ESUCCESS , @ "Failed to initialize CFE reader" ) ;
2013-02-28 21:17:30 +04:00
}
- ( void ) tearDown {
2019-10-18 17:24:15 +03:00
plcrash_nasync _macho _free ( & _image ) ;
2013-03-14 21:11:49 +04:00
plcrash_async _mobject _free ( & _unwind _mobj ) ;
plcrash_async _cfe _reader _free ( & _reader ) ;
2013-02-28 21:17:30 +04:00
}
2013-04-24 21:09:56 +04:00
# define EXTRACT_BITS ( value , mask ) ( ( value > > __builtin _ctz ( mask ) ) & ( ( ( 1 < < __builtin _popcount ( mask ) ) ) -1 ) )
2013-04-26 01:34:20 +04:00
# define INSERT_BITS ( bits , mask ) ( ( bits < < __builtin _ctz ( mask ) ) & mask )
2013-04-24 21:09:56 +04:00
2013-05-11 01:06:43 +04:00
/ * *
* Test handling of NULL encoding .
* /
- ( void ) testX86DecodeNULLEncoding {
plcrash_async _cfe _entry _t entry ;
STAssertEquals ( plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 , 0 x0 ) , PLCRASH_ESUCCESS , @ "Should return NOTFOUND for NULL encoding" ) ;
STAssertEquals ( plcrash_async _cfe _entry _type ( & entry ) , PLCRASH_ASYNC _CFE _ENTRY _TYPE _NONE , @ "Incorrect CFE type" ) ;
2013-10-17 23:34:55 +04:00
STAssertEquals ( ( plcrash_regnum _t ) PLCRASH_REG _INVALID , plcrash_async _cfe _entry _return _address _register ( & entry ) , @ "Return address register set" ) ;
2013-05-11 01:06:43 +04:00
}
2013-05-01 19:23:42 +04:00
/ * *
* Test handling of sparse register lists . These are only supported for the frame encodings ; the 10 - bit packed
* encoding format does not support sparse lists .
*
* It ' s unclear as to whether these actually ever occur in the wild .
* /
- ( void ) testX86SparseRegisterDecoding {
plcrash_async _cfe _entry _t entry ;
/ * x86 handling * /
const uint32_t encoded_regs = UNWIND_X86 _REG _ESI | ( UNWIND_X86 _REG _EDX < < 3 ) | ( UNWIND_X86 _REG _ECX < < 9 ) ;
uint32_t encoding = UNWIND_X86 _MODE _EBP _FRAME | INSERT_BITS ( encoded_regs , UNWIND_X86 _EBP _FRAME _REGISTERS ) ;
plcrash_error _t res = plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 , encoding ) ;
STAssertEquals ( res , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
/ * Extract the registers . Up to 5 may be encoded * /
2013-05-01 21:20:13 +04:00
plcrash_regnum _t expected_reg [ ] = {
2013-05-01 19:23:42 +04:00
PLCRASH_X86 _ESI ,
PLCRASH_X86 _EDX ,
PLCRASH_REG _INVALID ,
PLCRASH_X86 _ECX
} ;
uint32_t reg_count = plcrash_async _cfe _entry _register _count ( & entry ) ;
STAssertEquals ( reg_count , ( uint32_t ) ( sizeof ( expected_reg ) / sizeof ( expected_reg [ 0 ] ) ) , @ "Incorrect register count extracted" ) ;
2013-05-01 21:20:13 +04:00
plcrash_regnum _t reg [ reg_count ] ;
2013-05-01 19:23:42 +04:00
plcrash_async _cfe _entry _register _list ( & entry , reg ) ;
for ( uint32_t i = 0 ; i < reg_count ; i + + ) {
STAssertEquals ( reg [ i ] , expected_reg [ i ] , @ "Incorrect register value extracted for position %" PRId32 , i ) ;
}
plcrash_async _cfe _entry _free ( & entry ) ;
}
2013-04-24 21:09:56 +04:00
/ * *
* Decode an x86 EBP frame encoding .
* /
- ( void ) testX86DecodeFrame {
2013-04-30 23:52:52 +04:00
2013-04-24 21:09:56 +04:00
/ * Create a frame encoding , with registers saved at ebp -1020 bytes * /
const uint32_t encoded_reg _ebp _offset = 1020 ;
const uint32_t encoded_regs = UNWIND_X86 _REG _ESI |
( UNWIND_X86 _REG _EDX < < 3 ) |
( UNWIND_X86 _REG _ECX < < 6 ) ;
uint32_t encoding = UNWIND_X86 _MODE _EBP _FRAME |
INSERT_BITS ( encoded_reg _ebp _offset / 4 , UNWIND_X86 _EBP _FRAME _OFFSET ) |
INSERT_BITS ( encoded_regs , UNWIND_X86 _EBP _FRAME _REGISTERS ) ;
2013-05-01 01:03:40 +04:00
/ * Try decoding it * /
2013-04-30 23:52:52 +04:00
plcrash_async _cfe _entry _t entry ;
plcrash_error _t res = plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 , encoding ) ;
STAssertEquals ( res , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
2013-05-01 01:03:40 +04:00
STAssertEquals ( PLCRASH_ASYNC _CFE _ENTRY _TYPE _FRAME _PTR , plcrash_async _cfe _entry _type ( & entry ) , @ "Incorrect entry type" ) ;
2013-04-30 23:52:52 +04:00
2020-04-30 18:59:12 +03:00
uint32_t reg_ebp _offset = ( uint32_t ) plcrash_async _cfe _entry _stack _offset ( & entry ) ;
2013-04-30 23:52:52 +04:00
uint32_t reg_count = plcrash_async _cfe _entry _register _count ( & entry ) ;
2013-05-14 23:45:17 +04:00
STAssertEquals ( reg_ebp _offset , - encoded_reg _ebp _offset , @ "Incorrect offset extracted" ) ;
2013-04-30 23:52:52 +04:00
STAssertEquals ( reg_count , ( uint32_t ) 3 , @ "Incorrect register count extracted" ) ;
2013-10-17 23:34:55 +04:00
/ * Verify the return address register value * /
STAssertEquals ( ( plcrash_regnum _t ) PLCRASH_REG _INVALID , plcrash_async _cfe _entry _return _address _register ( & entry ) , @ "Return address register set" ) ;
2013-04-24 21:09:56 +04:00
/ * Extract the registers . Up to 5 may be encoded * /
2013-05-01 21:20:13 +04:00
plcrash_regnum _t expected_reg [ ] = {
2013-04-30 23:52:52 +04:00
PLCRASH_X86 _ESI ,
PLCRASH_X86 _EDX ,
PLCRASH_X86 _ECX
2013-04-24 21:09:56 +04:00
} ;
2013-05-01 21:20:13 +04:00
plcrash_regnum _t reg [ reg_count ] ;
2013-04-30 23:52:52 +04:00
plcrash_async _cfe _entry _register _list ( & entry , reg ) ;
for ( uint32_t i = 0 ; i < 3 ; i + + ) {
STAssertEquals ( reg [ i ] , expected_reg [ i ] , @ "Incorrect register value extracted for position %" PRId32 , i ) ;
2013-04-24 21:09:56 +04:00
}
2013-05-01 21:42:22 +04:00
plcrash_async _cfe _entry _free ( & entry ) ;
2013-04-24 21:09:56 +04:00
}
2013-04-29 22:08:50 +04:00
- ( void ) verifyFramelessRegDecode : ( uint32_t ) permutedRegisters
count : ( uint32_t ) count
2013-04-30 21:16:07 +04:00
expectedRegisters : ( const uint32_t [ PLCRASH_ASYNC _CFE _SAVED _REGISTER _MAX ] ) expectedRegisters
2013-04-29 22:08:50 +04:00
{
/ * Verify that our encoder generates the same result * /
2013-04-30 21:16:07 +04:00
STAssertEquals ( permutedRegisters , plcrash_async _cfe _register _encode ( expectedRegisters , count ) , @ "Incorrect internal encoding for count %" PRId32 , count ) ;
2013-04-29 22:08:50 +04:00
/ * Extract and verify the registers * /
uint32_t regs [ count ] ;
2013-10-29 21:07:19 +04:00
STAssertEquals ( PLCRASH_ESUCCESS , plcrash_async _cfe _register _decode ( permutedRegisters , count , regs ) , @ "Register decode returned an error" ) ;
2013-04-29 22:08:50 +04:00
for ( uint32_t i = 0 ; i < count ; i + + ) {
STAssertEquals ( regs [ i ] , expectedRegisters [ i ] , @ "Incorrect register value extracted for position %" PRId32 , i ) ;
}
}
2013-04-26 01:34:20 +04:00
/ * *
2013-05-01 01:03:40 +04:00
* Decode an x86 immediate ' frameless ' encoding .
2013-04-26 01:34:20 +04:00
* /
2013-05-01 01:03:40 +04:00
- ( void ) testX86DecodeFramelessImmediate {
2013-04-26 01:34:20 +04:00
/ * Create a frame encoding , with registers saved at ebp -1020 bytes * /
const uint32_t encoded_stack _size = 1020 ;
2013-05-01 01:03:40 +04:00
const uint32_t encoded_regs [ ] = { UNWIND_X86 _REG _ESI , UNWIND_X86 _REG _EDX , UNWIND_X86 _REG _ECX } ;
const uint32_t encoded_regs _count = sizeof ( encoded_regs ) / sizeof ( encoded_regs [ 0 ] ) ;
const uint32_t encoded_regs _permutation = plcrash_async _cfe _register _encode ( encoded_regs , encoded_regs _count ) ;
2013-04-26 01:34:20 +04:00
uint32_t encoding = UNWIND_X86 _MODE _STACK _IMMD |
INSERT_BITS ( encoded_stack _size / 4 , UNWIND_X86 _FRAMELESS _STACK _SIZE ) |
INSERT_BITS ( encoded_regs _count , UNWIND_X86 _FRAMELESS _STACK _REG _COUNT ) |
2013-05-01 01:03:40 +04:00
INSERT_BITS ( encoded_regs _permutation , UNWIND_X86 _FRAMELESS _STACK _REG _PERMUTATION ) ;
/ * Try decoding it * /
plcrash_async _cfe _entry _t entry ;
plcrash_error _t res = plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 , encoding ) ;
STAssertEquals ( res , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
STAssertEquals ( PLCRASH_ASYNC _CFE _ENTRY _TYPE _FRAMELESS _IMMD , plcrash_async _cfe _entry _type ( & entry ) , @ "Incorrect entry type" ) ;
2013-04-26 01:34:20 +04:00
2020-04-30 18:59:12 +03:00
uint32_t stack_size = ( uint32_t ) plcrash_async _cfe _entry _stack _offset ( & entry ) ;
2013-05-01 01:03:40 +04:00
uint32_t reg_count = plcrash_async _cfe _entry _register _count ( & entry ) ;
2013-04-26 01:34:20 +04:00
STAssertEquals ( stack_size , encoded_stack _size , @ "Incorrect stack size decoded" ) ;
STAssertEquals ( reg_count , encoded_regs _count , @ "Incorrect register count decoded" ) ;
2013-10-17 04:41:11 +04:00
/ * Verify the return address register value * /
STAssertEquals ( ( plcrash_regnum _t ) PLCRASH_REG _INVALID , plcrash_async _cfe _entry _return _address _register ( & entry ) , @ "Return address register set" ) ;
2013-04-26 01:34:20 +04:00
2013-05-01 01:03:40 +04:00
/ * Verify the register decoding * /
2013-05-01 21:20:13 +04:00
plcrash_regnum _t reg [ reg_count ] ;
2013-05-01 01:03:40 +04:00
plcrash_async _cfe _entry _register _list ( & entry , reg ) ;
2013-05-01 21:20:13 +04:00
const plcrash_regnum _t expected_regs [ ] = { PLCRASH_X86 _ESI , PLCRASH_X86 _EDX , PLCRASH_X86 _ECX } ;
2013-05-01 01:03:40 +04:00
for ( uint32_t i = 0 ; i < 3 ; i + + ) {
STAssertEquals ( reg [ i ] , expected_regs [ i ] , @ "Incorrect register value extracted for position %" PRId32 , i ) ;
}
2013-05-01 21:42:22 +04:00
plcrash_async _cfe _entry _free ( & entry ) ;
2013-05-01 01:03:40 +04:00
}
/ * *
* Decode an x86 indirect ' frameless ' encoding .
* /
- ( void ) testX86DecodeFramelessIndirect {
2013-07-04 01:36:43 +04:00
/ * Create a frame encoding , with registers saved at ebp -24 bytes * /
const uint32_t encoded_stack _size = 20 ;
2013-05-01 01:03:40 +04:00
const uint32_t encoded_regs [ ] = { UNWIND_X86 _REG _ESI , UNWIND_X86 _REG _EDX , UNWIND_X86 _REG _ECX } ;
const uint32_t encoded_regs _count = sizeof ( encoded_regs ) / sizeof ( encoded_regs [ 0 ] ) ;
const uint32_t encoded_regs _permutation = plcrash_async _cfe _register _encode ( encoded_regs , encoded_regs _count ) ;
2013-07-04 01:36:43 +04:00
const uint32_t encoded_stack _adjust = 4 ;
2013-05-01 01:03:40 +04:00
uint32_t encoding = UNWIND_X86 _MODE _STACK _IND |
2013-07-04 01:36:43 +04:00
INSERT_BITS ( encoded_stack _size , UNWIND_X86 _FRAMELESS _STACK _SIZE ) |
INSERT_BITS ( encoded_regs _count , UNWIND_X86 _FRAMELESS _STACK _REG _COUNT ) |
INSERT_BITS ( encoded_regs _permutation , UNWIND_X86 _FRAMELESS _STACK _REG _PERMUTATION ) |
INSERT_BITS ( encoded_stack _adjust / 4 , UNWIND_X86 _FRAMELESS _STACK _ADJUST ) ;
2013-05-01 01:03:40 +04:00
/ * Try decoding it * /
plcrash_async _cfe _entry _t entry ;
plcrash_error _t res = plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 , encoding ) ;
STAssertEquals ( res , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
STAssertEquals ( PLCRASH_ASYNC _CFE _ENTRY _TYPE _FRAMELESS _INDIRECT , plcrash_async _cfe _entry _type ( & entry ) , @ "Incorrect entry type" ) ;
2013-07-04 01:36:43 +04:00
2020-04-30 18:59:12 +03:00
uint32_t stack_size = ( uint32_t ) plcrash_async _cfe _entry _stack _offset ( & entry ) ;
2013-05-01 01:03:40 +04:00
uint32_t reg_count = plcrash_async _cfe _entry _register _count ( & entry ) ;
2013-07-04 01:36:43 +04:00
uint32_t stack_adjust = plcrash_async _cfe _entry _stack _adjustment ( & entry ) ;
2013-05-01 01:03:40 +04:00
STAssertEquals ( stack_size , encoded_stack _size , @ "Incorrect stack size decoded" ) ;
STAssertEquals ( reg_count , encoded_regs _count , @ "Incorrect register count decoded" ) ;
2013-07-04 01:36:43 +04:00
STAssertEquals ( stack_adjust , encoded_stack _adjust , @ "Incorrect stack adjustment decoded" ) ;
2013-10-17 04:41:11 +04:00
/ * Verify the return address register value * /
STAssertEquals ( ( plcrash_regnum _t ) PLCRASH_REG _INVALID , plcrash_async _cfe _entry _return _address _register ( & entry ) , @ "Return address register set" ) ;
2013-07-04 01:36:43 +04:00
2013-05-01 01:03:40 +04:00
/ * Verify the register decoding * /
2013-05-01 21:20:13 +04:00
plcrash_regnum _t reg [ reg_count ] ;
2013-05-01 01:03:40 +04:00
plcrash_async _cfe _entry _register _list ( & entry , reg ) ;
2013-05-01 21:20:13 +04:00
const plcrash_regnum _t expected_regs [ ] = { PLCRASH_X86 _ESI , PLCRASH_X86 _EDX , PLCRASH_X86 _ECX } ;
2013-05-01 01:03:40 +04:00
for ( uint32_t i = 0 ; i < 3 ; i + + ) {
STAssertEquals ( reg [ i ] , expected_regs [ i ] , @ "Incorrect register value extracted for position %" PRId32 , i ) ;
}
2013-05-01 21:42:22 +04:00
plcrash_async _cfe _entry _free ( & entry ) ;
2013-04-26 01:34:20 +04:00
}
2013-05-01 01:09:58 +04:00
/ * *
* Decode an x86 DWARF encoding .
* /
- ( void ) testX86DecodeDWARF {
/ * Create a frame encoding , with registers saved at ebp -1020 bytes * /
const uint32_t encoded_dwarf _offset = 1020 ;
uint32_t encoding = UNWIND_X86 _MODE _DWARF |
INSERT_BITS ( encoded_dwarf _offset , UNWIND_X86 _DWARF _SECTION _OFFSET ) ;
/ * Try decoding it * /
plcrash_async _cfe _entry _t entry ;
plcrash_error _t res = plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 , encoding ) ;
STAssertEquals ( res , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
STAssertEquals ( PLCRASH_ASYNC _CFE _ENTRY _TYPE _DWARF , plcrash_async _cfe _entry _type ( & entry ) , @ "Incorrect entry type" ) ;
2013-10-17 23:34:55 +04:00
STAssertEquals ( ( plcrash_regnum _t ) PLCRASH_REG _INVALID , plcrash_async _cfe _entry _return _address _register ( & entry ) , @ "Return address register set" ) ;
2020-04-30 18:59:12 +03:00
uint32_t dwarf_offset = ( uint32_t ) plcrash_async _cfe _entry _stack _offset ( & entry ) ;
2013-05-01 01:09:58 +04:00
STAssertEquals ( dwarf_offset , encoded_dwarf _offset , @ "Incorrect dwarf offset decoded" ) ;
2013-05-01 21:42:22 +04:00
plcrash_async _cfe _entry _free ( & entry ) ;
2013-05-01 01:09:58 +04:00
}
2013-05-11 01:06:43 +04:00
/ * *
* Test handling of NULL encoding .
* /
- ( void ) testX86_64DecodeNULLEncoding {
plcrash_async _cfe _entry _t entry ;
2013-10-17 23:34:55 +04:00
STAssertEquals ( plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 _64 , 0 x0 ) , PLCRASH_ESUCCESS , @ "Should return success for NULL encoding" ) ;
2013-05-11 01:06:43 +04:00
STAssertEquals ( plcrash_async _cfe _entry _type ( & entry ) , PLCRASH_ASYNC _CFE _ENTRY _TYPE _NONE , @ "Incorrect CFE type" ) ;
2013-10-17 23:34:55 +04:00
STAssertEquals ( ( plcrash_regnum _t ) PLCRASH_REG _INVALID , plcrash_async _cfe _entry _return _address _register ( & entry ) , @ "Return address register set" ) ;
2013-05-11 01:06:43 +04:00
}
2013-05-01 19:23:42 +04:00
/ * *
* Test handling of sparse register lists . These are only supported for the frame encodings ; the 10 - bit packed
* encoding format does not support sparse lists .
*
* It ' s unclear as to whether these actually ever occur in the wild .
* /
- ( void ) testX86_64SparseRegisterDecoding {
plcrash_async _cfe _entry _t entry ;
/ * x86 handling * /
const uint32_t encoded_regs = UNWIND_X86 _64 _REG _RBX | ( UNWIND_X86 _64 _REG _R12 < < 3 ) | ( UNWIND_X86 _64 _REG _R13 < < 9 ) ;
uint32_t encoding = UNWIND_X86 _64 _MODE _RBP _FRAME | INSERT_BITS ( encoded_regs , UNWIND_X86 _64 _RBP _FRAME _REGISTERS ) ;
plcrash_error _t res = plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 _64 , encoding ) ;
STAssertEquals ( res , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
/ * Extract the registers . Up to 5 may be encoded * /
2013-05-01 21:20:13 +04:00
plcrash_regnum _t expected_reg [ ] = {
2013-05-01 19:23:42 +04:00
PLCRASH_X86 _64 _RBX ,
PLCRASH_X86 _64 _R12 ,
PLCRASH_REG _INVALID ,
PLCRASH_X86 _64 _R13
} ;
uint32_t reg_count = plcrash_async _cfe _entry _register _count ( & entry ) ;
STAssertEquals ( reg_count , ( uint32_t ) ( sizeof ( expected_reg ) / sizeof ( expected_reg [ 0 ] ) ) , @ "Incorrect register count extracted" ) ;
2013-05-01 21:20:13 +04:00
plcrash_regnum _t reg [ reg_count ] ;
2013-05-01 19:23:42 +04:00
plcrash_async _cfe _entry _register _list ( & entry , reg ) ;
for ( uint32_t i = 0 ; i < reg_count ; i + + ) {
STAssertEquals ( reg [ i ] , expected_reg [ i ] , @ "Incorrect register value extracted for position %" PRId32 , i ) ;
}
plcrash_async _cfe _entry _free ( & entry ) ;
}
2013-04-26 01:34:20 +04:00
/ * *
2013-05-01 01:27:46 +04:00
* Decode an x86 -64 RBP frame encoding .
2013-04-26 01:34:20 +04:00
* /
2013-05-01 01:27:46 +04:00
- ( void ) testX86_64DecodeFrame {
/ * Create a frame encoding , with registers saved at rbp -1020 bytes * /
const uint32_t encoded_reg _rbp _offset = 1016 ;
const uint32_t encoded_regs = UNWIND_X86 _64 _REG _R12 |
( UNWIND_X86 _64 _REG _R13 < < 3 ) |
( UNWIND_X86 _64 _REG _R14 < < 6 ) ;
uint32_t encoding = UNWIND_X86 _64 _MODE _RBP _FRAME |
INSERT_BITS ( encoded_reg _rbp _offset / 8 , UNWIND_X86 _64 _RBP _FRAME _OFFSET ) |
INSERT_BITS ( encoded_regs , UNWIND_X86 _64 _RBP _FRAME _REGISTERS ) ;
/ * Try decoding it * /
plcrash_async _cfe _entry _t entry ;
plcrash_error _t res = plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 _64 , encoding ) ;
STAssertEquals ( res , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
STAssertEquals ( PLCRASH_ASYNC _CFE _ENTRY _TYPE _FRAME _PTR , plcrash_async _cfe _entry _type ( & entry ) , @ "Incorrect entry type" ) ;
2020-04-30 18:59:12 +03:00
uint32_t reg_ebp _offset = ( uint32_t ) plcrash_async _cfe _entry _stack _offset ( & entry ) ;
2013-05-01 01:27:46 +04:00
uint32_t reg_count = plcrash_async _cfe _entry _register _count ( & entry ) ;
2013-05-14 23:45:17 +04:00
STAssertEquals ( reg_ebp _offset , - encoded_reg _rbp _offset , @ "Incorrect offset extracted" ) ;
2013-05-01 01:27:46 +04:00
STAssertEquals ( reg_count , ( uint32_t ) 3 , @ "Incorrect register count extracted" ) ;
2013-10-17 04:41:11 +04:00
2013-10-17 23:34:55 +04:00
/ * Verify the return address register value * /
STAssertEquals ( ( plcrash_regnum _t ) PLCRASH_REG _INVALID , plcrash_async _cfe _entry _return _address _register ( & entry ) , @ "Return address register set" ) ;
2013-05-01 01:27:46 +04:00
/ * Extract the registers . Up to 5 may be encoded * /
2013-05-01 21:20:13 +04:00
plcrash_regnum _t expected_reg [ ] = {
2013-05-01 01:27:46 +04:00
PLCRASH_X86 _64 _R12 ,
PLCRASH_X86 _64 _R13 ,
PLCRASH_X86 _64 _R14
2013-04-26 01:34:20 +04:00
} ;
2013-05-01 21:20:13 +04:00
plcrash_regnum _t reg [ reg_count ] ;
2013-05-01 01:27:46 +04:00
plcrash_async _cfe _entry _register _list ( & entry , reg ) ;
for ( uint32_t i = 0 ; i < 3 ; i + + ) {
STAssertEquals ( reg [ i ] , expected_reg [ i ] , @ "Incorrect register value extracted for position %" PRId32 , i ) ;
}
2013-05-01 21:42:22 +04:00
plcrash_async _cfe _entry _free ( & entry ) ;
2013-05-01 01:27:46 +04:00
}
2013-04-26 01:34:20 +04:00
2013-05-01 01:27:46 +04:00
/ * *
* Decode an x86 -64 immediate ' frameless ' encoding .
* /
- ( void ) testX86_64DecodeFramelessImmediate {
/ * Create a frame encoding , with registers saved at ebp -1020 bytes * /
const uint32_t encoded_stack _size = 1016 ;
const uint32_t encoded_regs [ ] = { UNWIND_X86 _64 _REG _R12 , UNWIND_X86 _64 _REG _R13 , UNWIND_X86 _64 _REG _R14 } ;
const uint32_t encoded_regs _count = sizeof ( encoded_regs ) / sizeof ( encoded_regs [ 0 ] ) ;
const uint32_t encoded_regs _permutation = plcrash_async _cfe _register _encode ( encoded_regs , encoded_regs _count ) ;
uint32_t encoding = UNWIND_X86 _64 _MODE _STACK _IMMD |
INSERT_BITS ( encoded_stack _size / 8 , UNWIND_X86 _64 _FRAMELESS _STACK _SIZE ) |
INSERT_BITS ( encoded_regs _count , UNWIND_X86 _64 _FRAMELESS _STACK _REG _COUNT ) |
INSERT_BITS ( encoded_regs _permutation , UNWIND_X86 _64 _FRAMELESS _STACK _REG _PERMUTATION ) ;
/ * Try decoding it * /
plcrash_async _cfe _entry _t entry ;
plcrash_error _t res = plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 _64 , encoding ) ;
STAssertEquals ( res , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
STAssertEquals ( PLCRASH_ASYNC _CFE _ENTRY _TYPE _FRAMELESS _IMMD , plcrash_async _cfe _entry _type ( & entry ) , @ "Incorrect entry type" ) ;
2020-04-30 18:59:12 +03:00
uint32_t stack_size = ( uint32_t ) plcrash_async _cfe _entry _stack _offset ( & entry ) ;
2013-05-01 01:27:46 +04:00
uint32_t reg_count = plcrash_async _cfe _entry _register _count ( & entry ) ;
2013-04-26 01:34:20 +04:00
STAssertEquals ( stack_size , encoded_stack _size , @ "Incorrect stack size decoded" ) ;
2013-05-01 01:27:46 +04:00
STAssertEquals ( reg_count , encoded_regs _count , @ "Incorrect register count decoded" ) ;
2013-10-17 04:41:11 +04:00
/ * Verify the return address register value * /
STAssertEquals ( ( plcrash_regnum _t ) PLCRASH_REG _INVALID , plcrash_async _cfe _entry _return _address _register ( & entry ) , @ "Return address register set" ) ;
2013-05-01 01:27:46 +04:00
/ * Verify the register decoding * /
2013-05-01 21:20:13 +04:00
plcrash_regnum _t reg [ reg_count ] ;
2013-05-01 01:27:46 +04:00
plcrash_async _cfe _entry _register _list ( & entry , reg ) ;
2013-05-01 21:20:13 +04:00
const plcrash_regnum _t expected_regs [ ] = { PLCRASH_X86 _64 _R12 , PLCRASH_X86 _64 _R13 , PLCRASH_X86 _64 _R14 } ;
2013-05-01 01:27:46 +04:00
for ( uint32_t i = 0 ; i < 3 ; i + + ) {
STAssertEquals ( reg [ i ] , expected_regs [ i ] , @ "Incorrect register value extracted for position %" PRId32 , i ) ;
}
2013-05-01 21:42:22 +04:00
plcrash_async _cfe _entry _free ( & entry ) ;
2013-05-01 01:27:46 +04:00
}
/ * *
* Decode an x86 -64 indirect ' frameless ' encoding .
* /
- ( void ) testX86_64DecodeFramelessIndirect {
2013-07-04 01:36:43 +04:00
/ * Create a frame encoding , with registers saved at ebp -24 bytes * /
const uint32_t encoded_stack _size = 20 ;
2013-05-01 01:27:46 +04:00
const uint32_t encoded_regs [ ] = { UNWIND_X86 _64 _REG _R12 , UNWIND_X86 _64 _REG _R13 , UNWIND_X86 _64 _REG _R14 } ;
const uint32_t encoded_regs _count = sizeof ( encoded_regs ) / sizeof ( encoded_regs [ 0 ] ) ;
const uint32_t encoded_regs _permutation = plcrash_async _cfe _register _encode ( encoded_regs , encoded_regs _count ) ;
uint32_t encoding = UNWIND_X86 _64 _MODE _STACK _IND |
2013-07-04 01:36:43 +04:00
INSERT_BITS ( encoded_stack _size , UNWIND_X86 _64 _FRAMELESS _STACK _SIZE ) |
INSERT_BITS ( encoded_regs _count , UNWIND_X86 _64 _FRAMELESS _STACK _REG _COUNT ) |
INSERT_BITS ( encoded_regs _permutation , UNWIND_X86 _64 _FRAMELESS _STACK _REG _PERMUTATION ) ;
2013-05-01 01:27:46 +04:00
/ * Try decoding it * /
plcrash_async _cfe _entry _t entry ;
plcrash_error _t res = plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 _64 , encoding ) ;
STAssertEquals ( res , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
STAssertEquals ( PLCRASH_ASYNC _CFE _ENTRY _TYPE _FRAMELESS _INDIRECT , plcrash_async _cfe _entry _type ( & entry ) , @ "Incorrect entry type" ) ;
2020-04-30 18:59:12 +03:00
uint32_t stack_size = ( uint32_t ) plcrash_async _cfe _entry _stack _offset ( & entry ) ;
2013-05-01 01:27:46 +04:00
uint32_t reg_count = plcrash_async _cfe _entry _register _count ( & entry ) ;
STAssertEquals ( stack_size , encoded_stack _size , @ "Incorrect stack size decoded" ) ;
STAssertEquals ( reg_count , encoded_regs _count , @ "Incorrect register count decoded" ) ;
2013-10-17 23:34:55 +04:00
/ * Verify the return address register value * /
STAssertEquals ( ( plcrash_regnum _t ) PLCRASH_REG _INVALID , plcrash_async _cfe _entry _return _address _register ( & entry ) , @ "Return address register set" ) ;
2013-05-01 01:27:46 +04:00
/ * Verify the register decoding * /
2013-05-01 21:20:13 +04:00
plcrash_regnum _t reg [ reg_count ] ;
2013-05-01 01:27:46 +04:00
plcrash_async _cfe _entry _register _list ( & entry , reg ) ;
2013-05-01 21:20:13 +04:00
const plcrash_regnum _t expected_regs [ ] = { PLCRASH_X86 _64 _R12 , PLCRASH_X86 _64 _R13 , PLCRASH_X86 _64 _R14 } ;
2013-05-01 01:27:46 +04:00
for ( uint32_t i = 0 ; i < 3 ; i + + ) {
STAssertEquals ( reg [ i ] , expected_regs [ i ] , @ "Incorrect register value extracted for position %" PRId32 , i ) ;
}
2013-05-01 21:42:22 +04:00
plcrash_async _cfe _entry _free ( & entry ) ;
2013-05-01 01:27:46 +04:00
}
2013-04-26 01:34:20 +04:00
2013-05-01 01:27:46 +04:00
/ * *
* Decode an x86 -64 DWARF encoding .
* /
- ( void ) testX86_64DecodeDWARF {
/ * Create a frame encoding , with registers saved at ebp -1020 bytes * /
const uint32_t encoded_dwarf _offset = 1016 ;
uint32_t encoding = UNWIND_X86 _64 _MODE _DWARF |
INSERT_BITS ( encoded_dwarf _offset , UNWIND_X86 _64 _DWARF _SECTION _OFFSET ) ;
/ * Try decoding it * /
plcrash_async _cfe _entry _t entry ;
plcrash_error _t res = plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 _64 , encoding ) ;
STAssertEquals ( res , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
STAssertEquals ( PLCRASH_ASYNC _CFE _ENTRY _TYPE _DWARF , plcrash_async _cfe _entry _type ( & entry ) , @ "Incorrect entry type" ) ;
2013-10-17 23:34:55 +04:00
STAssertEquals ( ( plcrash_regnum _t ) PLCRASH_REG _INVALID , plcrash_async _cfe _entry _return _address _register ( & entry ) , @ "Return address register set" ) ;
2013-05-01 01:27:46 +04:00
2020-04-30 18:59:12 +03:00
uint32_t dwarf_offset = ( uint32_t ) plcrash_async _cfe _entry _stack _offset ( & entry ) ;
2013-05-01 01:27:46 +04:00
STAssertEquals ( dwarf_offset , encoded_dwarf _offset , @ "Incorrect dwarf offset decoded" ) ;
2013-09-27 02:04:48 +04:00
plcrash_async _cfe _entry _free ( & entry ) ;
}
/ * *
* Decode an ARM64 FP frame encoding .
* /
- ( void ) testARM64DecodeFrame {
/ * Create a frame encoding * /
uint32_t encoding = UNWIND_ARM64 _MODE _FRAME |
UNWIND_ARM64 _FRAME _X21 _X22 _PAIR |
UNWIND_ARM64 _FRAME _X25 _X26 _PAIR ;
/ * Try decoding it * /
plcrash_async _cfe _entry _t entry ;
plcrash_error _t res = plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _ARM64 , encoding ) ;
STAssertEquals ( res , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
STAssertEquals ( PLCRASH_ASYNC _CFE _ENTRY _TYPE _FRAME _PTR , plcrash_async _cfe _entry _type ( & entry ) , @ "Incorrect entry type" ) ;
2020-04-30 18:59:12 +03:00
int32_t reg_offset = ( uint32_t ) plcrash_async _cfe _entry _stack _offset ( & entry ) ;
2013-09-27 02:04:48 +04:00
uint32_t reg_count = plcrash_async _cfe _entry _register _count ( & entry ) ;
STAssertEquals ( reg_count , ( uint32_t ) 4 , @ "Incorrect register count extracted" ) ;
2013-10-07 22:46:40 +04:00
STAssertEquals ( reg_offset , ( int32_t ) -32 , @ "Incorrect register offset extracted (wanted -32, got %" PRId32 ")" , reg_offset ) ;
2013-10-17 23:34:55 +04:00
/ * Verify the return address register value * /
STAssertEquals ( ( plcrash_regnum _t ) PLCRASH_REG _INVALID , plcrash_async _cfe _entry _return _address _register ( & entry ) , @ "Return address register set" ) ;
2013-09-27 02:04:48 +04:00
/ * Extract the registers . * /
plcrash_regnum _t expected_reg [ ] = {
2013-10-08 01:59:51 +04:00
PLCRASH_ARM64 _X26 ,
PLCRASH_ARM64 _X25 ,
2013-09-27 02:04:48 +04:00
PLCRASH_ARM64 _X22 ,
2013-10-07 22:46:40 +04:00
PLCRASH_ARM64 _X21 ,
2013-09-27 02:04:48 +04:00
} ;
plcrash_regnum _t reg [ reg_count ] ;
plcrash_async _cfe _entry _register _list ( & entry , reg ) ;
for ( uint32_t i = 0 ; i < ( sizeof ( expected_reg ) / sizeof ( expected_reg [ 0 ] ) ) ; i + + ) {
STAssertEquals ( reg [ i ] , expected_reg [ i ] , @ "Incorrect register value extracted for position %" PRId32 , i ) ;
}
plcrash_async _cfe _entry _free ( & entry ) ;
}
/ * *
2013-10-17 04:41:11 +04:00
* Decode an ARM64 ' frameless ' encoding .
2013-09-27 02:04:48 +04:00
* /
2013-10-17 04:41:11 +04:00
- ( void ) testARM64DecodeFrameless {
2013-09-27 02:04:48 +04:00
/ * Create a frame encoding , with registers saved at sp + 1008 bytes * /
const uint32_t encoded_stack _size = 1008 ;
uint32_t encoding = UNWIND_ARM64 _MODE _FRAMELESS |
INSERT_BITS ( ( encoded_stack _size / 16 ) , UNWIND_ARM64 _FRAMELESS _STACK _SIZE _MASK ) |
UNWIND_ARM64 _FRAME _X25 _X26 _PAIR |
UNWIND_ARM64 _FRAME _X27 _X28 _PAIR ;
uint32_t encoded_regs _count = 4 ;
/ * Try decoding it * /
plcrash_async _cfe _entry _t entry ;
plcrash_error _t res = plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _ARM64 , encoding ) ;
STAssertEquals ( res , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
STAssertEquals ( PLCRASH_ASYNC _CFE _ENTRY _TYPE _FRAMELESS _IMMD , plcrash_async _cfe _entry _type ( & entry ) , @ "Incorrect entry type" ) ;
2020-04-30 18:59:12 +03:00
uint32_t stack_size = ( uint32_t ) plcrash_async _cfe _entry _stack _offset ( & entry ) ;
2013-09-27 02:04:48 +04:00
uint32_t reg_count = plcrash_async _cfe _entry _register _count ( & entry ) ;
STAssertEquals ( stack_size , encoded_stack _size , @ "Incorrect stack size decoded" ) ;
STAssertEquals ( reg_count , encoded_regs _count , @ "Incorrect register count decoded" ) ;
2013-10-17 04:41:11 +04:00
/ * Verify the return address register value * /
2013-10-17 23:49:11 +04:00
STAssertEquals ( ( plcrash_regnum _t ) PLCRASH_ARM64 _LR , plcrash_async _cfe _entry _return _address _register ( & entry ) , @ "Incorrect return address register set" ) ;
2013-10-17 04:41:11 +04:00
2013-09-27 02:04:48 +04:00
/ * Verify the register decoding * /
plcrash_regnum _t reg [ reg_count ] ;
plcrash_async _cfe _entry _register _list ( & entry , reg ) ;
plcrash_regnum _t expected_reg [ ] = {
2013-10-07 22:46:40 +04:00
PLCRASH_ARM64 _X28 ,
2013-09-27 02:04:48 +04:00
PLCRASH_ARM64 _X27 ,
2013-10-08 01:59:51 +04:00
PLCRASH_ARM64 _X26 ,
PLCRASH_ARM64 _X25 ,
2013-09-27 02:04:48 +04:00
} ;
for ( uint32_t i = 0 ; i < ( sizeof ( expected_reg ) / sizeof ( expected_reg [ 0 ] ) ) ; i + + ) {
STAssertEquals ( reg [ i ] , expected_reg [ i ] , @ "Incorrect register value extracted for position %" PRId32 , i ) ;
}
plcrash_async _cfe _entry _free ( & entry ) ;
}
/ * *
* Decode an ARM64 DWARF encoding .
* /
- ( void ) testARM64DecodeDWARF {
/ * Create a frame encoding * /
const uint32_t encoded_dwarf _offset = 1020 ;
uint32_t encoding = UNWIND_ARM64 _MODE _DWARF |
INSERT_BITS ( encoded_dwarf _offset , UNWIND_ARM64 _DWARF _SECTION _OFFSET ) ;
/ * Try decoding it * /
plcrash_async _cfe _entry _t entry ;
plcrash_error _t res = plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _ARM64 , encoding ) ;
STAssertEquals ( res , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
STAssertEquals ( PLCRASH_ASYNC _CFE _ENTRY _TYPE _DWARF , plcrash_async _cfe _entry _type ( & entry ) , @ "Incorrect entry type" ) ;
2013-10-17 23:34:55 +04:00
STAssertEquals ( ( plcrash_regnum _t ) PLCRASH_REG _INVALID , plcrash_async _cfe _entry _return _address _register ( & entry ) , @ "Return address register set" ) ;
2020-04-30 18:59:12 +03:00
uint32_t dwarf_offset = ( uint32_t ) plcrash_async _cfe _entry _stack _offset ( & entry ) ;
2013-09-27 02:04:48 +04:00
STAssertEquals ( dwarf_offset , encoded_dwarf _offset , @ "Incorrect dwarf offset decoded" ) ;
2013-05-01 21:42:22 +04:00
plcrash_async _cfe _entry _free ( & entry ) ;
2013-04-26 01:34:20 +04:00
}
2013-07-07 04:51:08 +04:00
/ * *
* Test decoding of a single non - zero permuted register .
*
* An implementation bug in plcrash_async _cfe _register _decode ( ) would always result in the last register element
* of a 1 - length register list being set to 0.
* /
- ( void ) testPermutedRegisterEncodeOneNonZero {
const uint32_t expected [ ] = { UNWIND_X86 _REG _ESI } ;
uint32_t decoded [ sizeof ( expected ) / sizeof ( expected [ 0 ] ) ] ;
uint32_t encoded = plcrash_async _cfe _register _encode ( expected , 1 ) ;
2013-10-29 21:07:19 +04:00
STAssertEquals ( PLCRASH_ESUCCESS , plcrash_async _cfe _register _decode ( encoded , 1 , decoded ) , @ "Decode returned an error" ) ;
2013-07-07 04:51:08 +04:00
STAssertEquals ( expected [ 0 ] , decoded [ 0 ] , @ "Failed to decode register" ) ;
}
2013-10-29 21:07:19 +04:00
/ * *
* Test passing an invalid count to plcrash_async _cfe _register _decode ( )
* /
- ( void ) testPermuttedRegisterDecodeInvalidCount {
uint32_t registers [ PLCRASH_ASYNC _CFE _PERMUTATION _REGISTER _MAX + 1 ] ;
STAssertNotEquals ( PLCRASH_ESUCCESS , plcrash_async _cfe _register _decode ( 0 , PLCRASH_ASYNC _CFE _PERMUTATION _REGISTER _MAX + 1 , registers ) , @ "Decoding of a too-large count did not return an error" ) ;
}
2013-04-29 22:08:50 +04:00
/ * *
* Verify encoding + decoding of permuted frameless registers , verifying all supported lengths . The test cases were
* all extracted from code generated by clang .
* /
- ( void ) testPermutedRegisterEncoding {
# define PL_EXBIT ( v ) EXTRACT_BITS ( v , UNWIND_X86 _64 _FRAMELESS _STACK _REG _PERMUTATION )
/ * 1 item * /
{
2013-04-30 21:16:07 +04:00
const uint32_t expected [ PLCRASH_ASYNC _CFE _SAVED _REGISTER _MAX ] = { UNWIND_X86 _64 _REG _RBX } ;
2013-04-29 22:08:50 +04:00
[ self verifyFramelessRegDecode : PL_EXBIT ( 0 x02020400 ) count : 1 expectedRegisters : expected ] ;
}
/ * 2 items * /
{
2013-04-30 21:16:07 +04:00
const uint32_t expected [ PLCRASH_ASYNC _CFE _SAVED _REGISTER _MAX ] = {
2013-04-29 22:08:50 +04:00
UNWIND_X86 _64 _REG _R15 ,
UNWIND_X86 _64 _REG _R14
} ;
[ self verifyFramelessRegDecode : PL_EXBIT ( 0 x02030817 ) count : 2 expectedRegisters : expected ] ;
}
/ * 3 items * /
{
2013-04-30 21:16:07 +04:00
const uint32_t expected [ PLCRASH_ASYNC _CFE _SAVED _REGISTER _MAX ] = {
2013-04-29 22:08:50 +04:00
UNWIND_X86 _64 _REG _RBX ,
UNWIND_X86 _64 _REG _R14 ,
UNWIND_X86 _64 _REG _R15
} ;
[ self verifyFramelessRegDecode : PL_EXBIT ( 0 x02040C0A ) count : 3 expectedRegisters : expected ] ;
}
/ * 4 items * /
{
2013-04-30 21:16:07 +04:00
const uint32_t expected [ PLCRASH_ASYNC _CFE _SAVED _REGISTER _MAX ] = {
2013-04-29 22:08:50 +04:00
UNWIND_X86 _64 _REG _RBX ,
UNWIND_X86 _64 _REG _R12 ,
UNWIND_X86 _64 _REG _R14 ,
UNWIND_X86 _64 _REG _R15
} ;
[ self verifyFramelessRegDecode : PL_EXBIT ( 0 x02051004 ) count : 4 expectedRegisters : expected ] ;
}
/ * 5 items * /
{
2013-04-30 21:16:07 +04:00
const uint32_t expected [ PLCRASH_ASYNC _CFE _SAVED _REGISTER _MAX ] = {
2013-04-29 22:08:50 +04:00
UNWIND_X86 _64 _REG _RBX ,
UNWIND_X86 _64 _REG _R12 ,
UNWIND_X86 _64 _REG _R13 ,
UNWIND_X86 _64 _REG _R14 ,
UNWIND_X86 _64 _REG _R15
} ;
[ self verifyFramelessRegDecode : PL_EXBIT ( 0 x02071800 ) count : 5 expectedRegisters : expected ] ;
}
/ * 6 items * /
{
2013-04-30 21:16:07 +04:00
const uint32_t expected [ PLCRASH_ASYNC _CFE _SAVED _REGISTER _MAX ] = {
2013-04-29 22:08:50 +04:00
UNWIND_X86 _64 _REG _RBX ,
UNWIND_X86 _64 _REG _R12 ,
UNWIND_X86 _64 _REG _R13 ,
UNWIND_X86 _64 _REG _R14 ,
UNWIND_X86 _64 _REG _R15 ,
UNWIND_X86 _64 _REG _RBP
} ;
[ self verifyFramelessRegDecode : PL_EXBIT ( 0 x02071800 ) count : 6 expectedRegisters : expected ] ;
}
# undef PL_EXBIT
}
2013-04-26 01:34:20 +04:00
2013-02-28 23:26:16 +04:00
/ * *
2013-03-14 21:11:49 +04:00
* Test reading of a PC , compressed , with a common encoding .
2013-02-28 23:26:16 +04:00
* /
2013-03-14 21:11:49 +04:00
- ( void ) testReadCompressedCommonEncoding {
2013-05-15 23:40:20 +04:00
pl_vm _address _t function_base ;
2013-02-28 23:26:16 +04:00
plcrash_error _t err ;
2013-03-14 23:26:28 +04:00
uint32_t encoding ;
2013-05-15 23:40:20 +04:00
err = plcrash_async _cfe _reader _find _pc ( & _reader , PC_COMPACT _COMMON , & function_base , & encoding ) ;
2013-03-14 21:11:49 +04:00
STAssertEquals ( PLCRASH_ESUCCESS , err , @ "Failed to locate CFE entry" ) ;
2013-05-15 23:40:20 +04:00
STAssertEquals ( function_base , ( pl_vm _address _t ) PC_COMPACT _COMMON , @ "Incorrect function base returned" ) ;
2013-03-14 23:26:28 +04:00
STAssertEquals ( encoding , ( uint32_t ) PC_COMPACT _COMMON _ENCODING , @ "Incorrect encoding returned" ) ;
2013-02-28 21:17:30 +04:00
}
2013-03-14 23:47:17 +04:00
/ * *
2013-03-14 23:49:21 +04:00
* Test reading of a PC , compressed , with a private encoding .
2013-03-14 23:47:17 +04:00
* /
- ( void ) testReadCompressedEncoding {
2013-05-15 23:40:20 +04:00
pl_vm _address _t function_base ;
2013-03-14 23:47:17 +04:00
plcrash_error _t err ;
uint32_t encoding ;
2013-05-15 23:40:20 +04:00
err = plcrash_async _cfe _reader _find _pc ( & _reader , PC_COMPACT _PRIVATE , & function_base , & encoding ) ;
2013-03-14 23:47:17 +04:00
STAssertEquals ( PLCRASH_ESUCCESS , err , @ "Failed to locate CFE entry" ) ;
2013-05-15 23:40:20 +04:00
STAssertEquals ( function_base , ( pl_vm _address _t ) PC_COMPACT _PRIVATE , @ "Incorrect function base returned" ) ;
2013-03-14 23:47:17 +04:00
STAssertEquals ( encoding , ( uint32_t ) PC_COMPACT _PRIVATE _ENCODING , @ "Incorrect encoding returned" ) ;
}
2013-03-15 00:09:27 +04:00
/ * *
* Test reading of a PC , regular , with a common encoding .
* /
- ( void ) testReadRegularEncoding {
2013-05-15 23:40:20 +04:00
pl_vm _address _t function_base ;
2013-03-15 00:09:27 +04:00
plcrash_error _t err ;
uint32_t encoding ;
2013-05-15 23:40:20 +04:00
err = plcrash_async _cfe _reader _find _pc ( & _reader , PC_REGULAR , & function_base , & encoding ) ;
2013-03-15 00:09:27 +04:00
STAssertEquals ( PLCRASH_ESUCCESS , err , @ "Failed to locate CFE entry" ) ;
2013-05-15 23:40:20 +04:00
STAssertEquals ( function_base , ( pl_vm _address _t ) PC_REGULAR , @ "Incorrect function base returned" ) ;
2013-03-15 00:09:27 +04:00
STAssertEquals ( encoding , ( uint32_t ) PC_REGULAR _ENCODING , @ "Incorrect encoding returned" ) ;
}
2013-10-17 22:58:01 +04:00
/ *
* The following tests can only be run with ARM64 thread state support .
* /
# if PLCRASH_ASYNC _THREAD _ARM _SUPPORT
- ( void ) testARM64_ApplyFramePTRState {
plcrash_async _cfe _entry _t entry ;
plcrash_async _thread _state _t ts ;
/ * Set up a faux frame * /
uint64_t stackframe [ ] = {
12 , // x22
13 , // x21
14 , // x20
15 , // x19
1 , // fp
2 , // lr
} ;
/ * Create a frame encoding . * /
uint32_t encoding = UNWIND_ARM64 _MODE _FRAME |
UNWIND_ARM64 _FRAME _X19 _X20 _PAIR |
UNWIND_ARM64 _FRAME _X21 _X22 _PAIR ;
STAssertEquals ( PLCRASH_ESUCCESS , plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _ARM64 , encoding ) , @ "Failed to initialize CFE entry" ) ;
/ * Initialize default thread state * /
2022-09-20 17:53:03 +03:00
plcrash_greg _t stack_addr = ( plcrash_greg _t ) & stackframe [ 4 ] ; // fp
2013-10-17 22:58:01 +04:00
STAssertEquals ( plcrash_async _thread _state _init ( & ts , CPU_TYPE _ARM64 ) , PLCRASH_ESUCCESS , @ "Failed to initialize thread state" ) ;
plcrash_async _thread _state _set _reg ( & ts , PLCRASH_REG _FP , stack_addr ) ;
/ * Apply ! * /
plcrash_async _thread _state _t nts ;
plcrash_error _t err = plcrash_async _cfe _entry _apply ( mach_task _self ( ) , 0 x0 , & ts , & entry , & nts ) ;
STAssertEquals ( err , PLCRASH_ESUCCESS , @ "Failed to apply state to thread" ) ;
/ * Verify ! * /
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_ARM64 _SP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_ARM64 _FP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_ARM64 _PC ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_ARM64 _X19 ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_ARM64 _X20 ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_ARM64 _X21 ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_ARM64 _X22 ) , @ "Missing expected register" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_ARM64 _SP ) , ( plcrash_greg _t ) stack_addr + ( 16 ) , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_ARM64 _FP ) , ( plcrash_greg _t ) 1 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_ARM64 _PC ) , ( plcrash_greg _t ) 2 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_ARM64 _X19 ) , ( plcrash_greg _t ) 15 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_ARM64 _X20 ) , ( plcrash_greg _t ) 14 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_ARM64 _X21 ) , ( plcrash_greg _t ) 13 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_ARM64 _X22 ) , ( plcrash_greg _t ) 12 , @ "Incorrect register value" ) ;
plcrash_async _cfe _entry _free ( & entry ) ;
}
/ * *
* Apply an ARM64 frameless encoding .
* /
- ( void ) testARM64_ApplyFramelessPTRState {
plcrash_async _cfe _entry _t entry ;
plcrash_async _thread _state _t ts ;
/ * Set up a faux frame * /
uint64_t stackframe [ ] = {
0 , // padding to exercise stack size computation
0 , // padding
12 , // x22
13 , // x21
14 , // x20
15 , // x19
} ;
/ * Create a frame encoding . * /
/ * Create a frame encoding , with registers saved at ( restored sp ) -32 bytes * /
const uint32_t encoded_stack _size = sizeof ( stackframe ) ;
uint32_t encoding = UNWIND_ARM64 _MODE _FRAMELESS |
INSERT_BITS ( encoded_stack _size / 16 , UNWIND_ARM64 _FRAMELESS _STACK _SIZE _MASK ) |
UNWIND_ARM64 _FRAME _X19 _X20 _PAIR |
UNWIND_ARM64 _FRAME _X21 _X22 _PAIR ;
STAssertEquals ( plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _ARM64 , encoding ) , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
/ * Initialize default thread state * /
STAssertEquals ( plcrash_async _thread _state _init ( & ts , CPU_TYPE _ARM64 ) , PLCRASH_ESUCCESS , @ "Failed to initialize thread state" ) ;
2022-09-20 17:53:03 +03:00
plcrash_async _thread _state _set _reg ( & ts , PLCRASH_REG _SP , ( plcrash_greg _t ) & stackframe ) ;
2013-10-17 22:58:01 +04:00
plcrash_async _thread _state _set _reg ( & ts , PLCRASH_ARM64 _LR , 2 ) ;
/ * Apply * /
plcrash_async _thread _state _t nts ;
plcrash_error _t err = plcrash_async _cfe _entry _apply ( mach_task _self ( ) , 0 x0 , & ts , & entry , & nts ) ;
STAssertEquals ( err , PLCRASH_ESUCCESS , @ "Failed to apply state to thread" ) ;
/ * Verify * /
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_ARM64 _SP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_ARM64 _PC ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_ARM64 _X19 ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_ARM64 _X20 ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_ARM64 _X21 ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_ARM64 _X22 ) , @ "Missing expected register" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_ARM64 _SP ) , ( ( plcrash_greg _t ) & stackframe ) + encoded_stack _size , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_ARM64 _PC ) , ( plcrash_greg _t ) 2 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_ARM64 _X19 ) , ( plcrash_greg _t ) 15 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_ARM64 _X20 ) , ( plcrash_greg _t ) 14 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_ARM64 _X21 ) , ( plcrash_greg _t ) 13 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_ARM64 _X22 ) , ( plcrash_greg _t ) 12 , @ "Incorrect register value" ) ;
plcrash_async _cfe _entry _free ( & entry ) ;
}
# endif
2013-05-14 01:03:50 +04:00
2013-05-14 23:45:17 +04:00
/ *
2013-10-17 04:41:11 +04:00
* The iOS SDK does not provide the thread state APIs necessary
* to perform the x86 tests on ARM
2013-05-14 23:45:17 +04:00
* /
# if PLCRASH_ASYNC _THREAD _X86 _SUPPORT
- ( void ) testx86_64 _ApplyFramePTRState {
2013-05-14 01:03:50 +04:00
plcrash_async _cfe _entry _t entry ;
plcrash_async _thread _state _t ts ;
2013-05-14 23:45:17 +04:00
/ * Set up a faux frame * /
uint64_t stackframe [ ] = {
12 , // r12
13 , // r13
0 , // sparse slot
14 , // r14
1 , // rbp
2 , // ret addr
} ;
/ * Create a frame encoding , with registers saved at rbp -32 bytes . We insert
* a sparse slot to test the sparse handling * /
const uint32_t encoded_reg _rbp _offset = 32 ;
2013-05-14 01:03:50 +04:00
const uint32_t encoded_regs = UNWIND_X86 _64 _REG _R12 |
2013-05-14 23:45:17 +04:00
( UNWIND_X86 _64 _REG _R13 < < 3 ) |
0 < < 6 / * SPARSE * / |
( UNWIND_X86 _64 _REG _R14 < < 9 ) ;
2013-05-14 01:03:50 +04:00
uint32_t encoding = UNWIND_X86 _64 _MODE _RBP _FRAME |
INSERT_BITS ( encoded_reg _rbp _offset / 8 , UNWIND_X86 _64 _RBP _FRAME _OFFSET ) |
INSERT_BITS ( encoded_regs , UNWIND_X86 _64 _RBP _FRAME _REGISTERS ) ;
STAssertEquals ( PLCRASH_ESUCCESS , plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 _64 , encoding ) , @ "Failed to initialize CFE entry" ) ;
/ * Initialize default thread state * /
2020-04-30 14:06:32 +03:00
plcrash_greg _t stack_addr = ( plcrash_greg _t ) & stackframe [ 4 ] ; // rbp
2013-05-14 23:45:17 +04:00
STAssertEquals ( plcrash_async _thread _state _init ( & ts , CPU_TYPE _X86 _64 ) , PLCRASH_ESUCCESS , @ "Failed to initialize thread state" ) ;
plcrash_async _thread _state _set _reg ( & ts , PLCRASH_REG _FP , stack_addr ) ;
/ * Apply ! * /
plcrash_async _thread _state _t nts ;
2013-05-15 23:40:20 +04:00
plcrash_error _t err = plcrash_async _cfe _entry _apply ( mach_task _self ( ) , 0 x0 , & ts , & entry , & nts ) ;
2013-05-14 23:45:17 +04:00
STAssertEquals ( err , PLCRASH_ESUCCESS , @ "Failed to apply state to thread" ) ;
/ * Verify ! * /
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _RSP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _RBP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _RIP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _R12 ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _R13 ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _R14 ) , @ "Missing expected register" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _RSP ) , ( plcrash_greg _t ) stack_addr + ( 16 ) , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _RBP ) , ( plcrash_greg _t ) 1 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _RIP ) , ( plcrash_greg _t ) 2 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _R12 ) , ( plcrash_greg _t ) 12 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _R13 ) , ( plcrash_greg _t ) 13 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _R14 ) , ( plcrash_greg _t ) 14 , @ "Incorrect register value" ) ;
2013-05-15 18:50:31 +04:00
plcrash_async _cfe _entry _free ( & entry ) ;
2013-05-14 23:45:17 +04:00
}
/ * This test requires storing local pointers to the host ' s stack in 32 - bit x86 ' s thread state ; it can only be run on a 32 - bit host ,
* as the 64 - bit stack pointers may exceed the UINT32_MAX . * /
# ifndef __LP64 __
- ( void ) testx86_32 _ApplyFramePTRState {
plcrash_async _cfe _entry _t entry ;
plcrash_async _thread _state _t ts ;
/ * Set up a faux frame * /
uint32_t stackframe [ ] = {
12 , // ebx
13 , // ecx
0 , // sparse slot
14 , // edi
1 , // ebp
2 , // ret addr
} ;
/ * Create a frame encoding , with registers saved at ebp -16 bytes . We insert
* a sparse slot to test the sparse handling * /
const uint32_t encoded_reg _ebp _offset = 16 ;
const uint32_t encoded_regs = UNWIND_X86 _REG _EBX |
( UNWIND_X86 _REG _ECX < < 3 ) |
0 < < 6 / * SPARSE * / |
( UNWIND_X86 _REG _EDI < < 9 ) ;
uint32_t encoding = UNWIND_X86 _MODE _EBP _FRAME |
INSERT_BITS ( encoded_reg _ebp _offset / 4 , UNWIND_X86 _EBP _FRAME _OFFSET ) |
INSERT_BITS ( encoded_regs , UNWIND_X86 _EBP _FRAME _REGISTERS ) ;
STAssertEquals ( PLCRASH_ESUCCESS , plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 , encoding ) , @ "Failed to initialize CFE entry" ) ;
/ * Initialize default thread state * /
plcrash_greg _t stack_addr = & stackframe [ 4 ] ; // ebp
STAssertEquals ( plcrash_async _thread _state _init ( & ts , CPU_TYPE _X86 ) , PLCRASH_ESUCCESS , @ "Failed to initialize thread state" ) ;
plcrash_async _thread _state _set _reg ( & ts , PLCRASH_REG _FP , stack_addr ) ;
2013-05-14 01:03:50 +04:00
/ * Apply ! * /
plcrash_async _thread _state _t nts ;
2013-05-15 23:40:20 +04:00
plcrash_error _t err = plcrash_async _cfe _entry _apply ( mach_task _self ( ) , 0 x0 , & ts , & entry , & nts ) ;
2013-05-14 01:03:50 +04:00
STAssertEquals ( err , PLCRASH_ESUCCESS , @ "Failed to apply state to thread" ) ;
2013-05-14 23:45:17 +04:00
/ * Verify ! * /
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _ESP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _EBP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _EIP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _EBX ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _ECX ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _EDI ) , @ "Missing expected register" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _ESP ) , ( plcrash_greg _t ) stack_addr + ( 8 ) , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _EBP ) , ( plcrash_greg _t ) 1 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _EIP ) , ( plcrash_greg _t ) 2 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _EBX ) , ( plcrash_greg _t ) 12 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _ECX ) , ( plcrash_greg _t ) 13 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _EDI ) , ( plcrash_greg _t ) 14 , @ "Incorrect register value" ) ;
2013-05-15 18:50:31 +04:00
plcrash_async _cfe _entry _free ( & entry ) ;
2013-05-14 01:03:50 +04:00
}
2013-05-14 23:45:17 +04:00
# endif / * ! __LP64 __ * /
2013-05-15 18:50:31 +04:00
/ * *
* Apply an x86 -64 immediate ' frameless ' encoding .
* /
- ( void ) testX86_64 _ApplyFramePTRState _IMD {
plcrash_async _cfe _entry _t entry ;
plcrash_async _thread _state _t ts ;
/ * Set up a faux frame * /
2013-05-15 22:02:37 +04:00
uint64_t stackframe [ ] = {
2013-05-15 18:50:31 +04:00
10 , // rbp
12 , // r12
13 , // r13
14 , // r14
2013-07-04 00:06:32 +04:00
2013-05-15 18:50:31 +04:00
2 , // ret addr
} ;
/ * Create a frame encoding , with registers saved at esp -32 bytes * /
2013-07-04 00:06:32 +04:00
const uint32_t encoded_stack _size = 40 ;
2013-05-15 18:50:31 +04:00
const uint32_t encoded_regs [ ] = { UNWIND_X86 _64 _REG _RBP , UNWIND_X86 _64 _REG _R12 , UNWIND_X86 _64 _REG _R13 , UNWIND_X86 _64 _REG _R14 } ;
const uint32_t encoded_regs _count = sizeof ( encoded_regs ) / sizeof ( encoded_regs [ 0 ] ) ;
const uint32_t encoded_regs _permutation = plcrash_async _cfe _register _encode ( encoded_regs , encoded_regs _count ) ;
uint32_t encoding = UNWIND_X86 _64 _MODE _STACK _IMMD |
INSERT_BITS ( encoded_stack _size / 8 , UNWIND_X86 _64 _FRAMELESS _STACK _SIZE ) |
INSERT_BITS ( encoded_regs _count , UNWIND_X86 _64 _FRAMELESS _STACK _REG _COUNT ) |
INSERT_BITS ( encoded_regs _permutation , UNWIND_X86 _64 _FRAMELESS _STACK _REG _PERMUTATION ) ;
STAssertEquals ( plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 _64 , encoding ) , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
/ * Initialize default thread state * /
STAssertEquals ( plcrash_async _thread _state _init ( & ts , CPU_TYPE _X86 _64 ) , PLCRASH_ESUCCESS , @ "Failed to initialize thread state" ) ;
2020-04-30 14:06:32 +03:00
plcrash_async _thread _state _set _reg ( & ts , PLCRASH_REG _SP , ( plcrash_greg _t ) & stackframe ) ;
2013-05-15 18:50:31 +04:00
/ * Apply * /
plcrash_async _thread _state _t nts ;
2013-05-15 23:40:20 +04:00
plcrash_error _t err = plcrash_async _cfe _entry _apply ( mach_task _self ( ) , 0 x0 , & ts , & entry , & nts ) ;
STAssertEquals ( err , PLCRASH_ESUCCESS , @ "Failed to apply state to thread" ) ;
/ * Verify * /
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _RSP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _RIP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _RBP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _R12 ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _R13 ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _R14 ) , @ "Missing expected register" ) ;
2013-07-04 00:34:34 +04:00
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _RSP ) , ( plcrash_greg _t ) & stackframe [ 5 ] , @ "Incorrect register value" ) ;
2013-05-15 23:40:20 +04:00
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _RIP ) , ( plcrash_greg _t ) 2 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _RBP ) , ( plcrash_greg _t ) 10 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _R12 ) , ( plcrash_greg _t ) 12 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _R13 ) , ( plcrash_greg _t ) 13 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _R14 ) , ( plcrash_greg _t ) 14 , @ "Incorrect register value" ) ;
plcrash_async _cfe _entry _free ( & entry ) ;
}
/ * *
* Apply an x86 -64 indirect ' frameless ' encoding .
* /
- ( void ) testX86_64 _ApplyFramePTRState _IND {
plcrash_async _cfe _entry _t entry ;
plcrash_async _thread _state _t ts ;
/ * Set up a faux frame * /
uint64_t stackframe [ ] = {
10 , // rbp
12 , // r12
13 , // r13
14 , // r14
2 , // ret addr
} ;
/ * Create a frame encoding * /
const uint32_t encoded_stack _size = 128 ;
const uint32_t encoded_regs [ ] = { UNWIND_X86 _64 _REG _RBP , UNWIND_X86 _64 _REG _R12 , UNWIND_X86 _64 _REG _R13 , UNWIND_X86 _64 _REG _R14 } ;
const uint32_t encoded_regs _count = sizeof ( encoded_regs ) / sizeof ( encoded_regs [ 0 ] ) ;
const uint32_t encoded_regs _permutation = plcrash_async _cfe _register _encode ( encoded_regs , encoded_regs _count ) ;
/ * Indirect address target * /
2013-07-04 01:36:43 +04:00
uint32_t indirect_encoded _stack _size = 32 ;
uint32_t encoded_stack _adjust = 8 ;
2013-05-15 23:40:20 +04:00
pl_vm _address _t function_address = ( ( pl_vm _address _t ) & indirect_encoded _stack _size ) - encoded_stack _size ;
uint32_t encoding = UNWIND_X86 _64 _MODE _STACK _IND |
2013-07-04 01:36:43 +04:00
INSERT_BITS ( encoded_stack _size , UNWIND_X86 _64 _FRAMELESS _STACK _SIZE ) |
INSERT_BITS ( encoded_regs _count , UNWIND_X86 _64 _FRAMELESS _STACK _REG _COUNT ) |
INSERT_BITS ( encoded_regs _permutation , UNWIND_X86 _64 _FRAMELESS _STACK _REG _PERMUTATION ) |
INSERT_BITS ( encoded_stack _adjust / 8 , UNWIND_X86 _64 _FRAMELESS _STACK _ADJUST ) ;
2013-05-15 23:40:20 +04:00
STAssertEquals ( plcrash_async _cfe _entry _init ( & entry , CPU_TYPE _X86 _64 , encoding ) , PLCRASH_ESUCCESS , @ "Failed to decode entry" ) ;
/ * Initialize default thread state * /
STAssertEquals ( plcrash_async _thread _state _init ( & ts , CPU_TYPE _X86 _64 ) , PLCRASH_ESUCCESS , @ "Failed to initialize thread state" ) ;
2020-04-30 14:06:32 +03:00
plcrash_async _thread _state _set _reg ( & ts , PLCRASH_REG _SP , ( plcrash_greg _t ) & stackframe ) ;
2013-05-15 23:40:20 +04:00
/ * Apply * /
plcrash_async _thread _state _t nts ;
plcrash_error _t err = plcrash_async _cfe _entry _apply ( mach_task _self ( ) , function_address , & ts , & entry , & nts ) ;
2013-05-15 18:50:31 +04:00
STAssertEquals ( err , PLCRASH_ESUCCESS , @ "Failed to apply state to thread" ) ;
/ * Verify * /
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _RSP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _RIP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _RBP ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _R12 ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _R13 ) , @ "Missing expected register" ) ;
STAssertTrue ( plcrash_async _thread _state _has _reg ( & nts , PLCRASH_X86 _64 _R14 ) , @ "Missing expected register" ) ;
2013-07-04 00:34:34 +04:00
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _RSP ) , ( plcrash_greg _t ) & stackframe [ 5 ] , @ "Incorrect register value" ) ;
2013-05-15 18:50:31 +04:00
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _RIP ) , ( plcrash_greg _t ) 2 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _RBP ) , ( plcrash_greg _t ) 10 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _R12 ) , ( plcrash_greg _t ) 12 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _R13 ) , ( plcrash_greg _t ) 13 , @ "Incorrect register value" ) ;
STAssertEquals ( plcrash_async _thread _state _get _reg ( & nts , PLCRASH_X86 _64 _R14 ) , ( plcrash_greg _t ) 14 , @ "Incorrect register value" ) ;
plcrash_async _cfe _entry _free ( & entry ) ;
}
2013-05-14 23:45:17 +04:00
# endif / * PLCRASH_ASYNC _THREAD _X86 _SUPPORT * /
2013-05-14 01:03:50 +04:00
2013-02-28 21:17:30 +04:00
@ end
2013-07-17 02:34:42 +04:00
2013-07-23 00:33:40 +04:00
# endif / * PLCRASH_FEATURE _UNWIND _COMPACT * /