705 строки
22 KiB
C
705 строки
22 KiB
C
/*
|
|
* Author: Landon Fuller <landonf@plausiblelabs.com>
|
|
*
|
|
* Copyright (c) 2008-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.
|
|
*/
|
|
|
|
#include "PLCrashAsyncThread.h"
|
|
#include "PLCrashAsync.h"
|
|
|
|
#include <signal.h>
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
|
|
#define RETGEN(name, type, ts) {\
|
|
return (ts->x86_state. type . __ ## name); \
|
|
}
|
|
|
|
#define SETGEN(name, type, ts, regnum, value) {\
|
|
ts->valid_regs |= 1ULL<<regnum; \
|
|
(ts->x86_state. type . __ ## name) = value; \
|
|
break; \
|
|
}
|
|
|
|
#if defined(__i386__) || defined(__x86_64__)
|
|
|
|
/* Mapping of DWARF register numbers to PLCrashReporter register numbers. */
|
|
struct dwarf_register_table {
|
|
/** Standard register number. */
|
|
plcrash_regnum_t regnum;
|
|
|
|
/** DWARF register number. */
|
|
uint64_t dwarf_value;
|
|
};
|
|
|
|
|
|
/*
|
|
* i386 GP registers defined as callee-preserved, as per Apple's Mac OS X IA-32
|
|
* Function Call Guide
|
|
*/
|
|
static const plcrash_regnum_t x86_32_nonvolatile_registers[] = {
|
|
PLCRASH_X86_EBX,
|
|
PLCRASH_X86_EBP,
|
|
PLCRASH_X86_ESI,
|
|
PLCRASH_X86_EDI,
|
|
PLCRASH_X86_ESP
|
|
};
|
|
|
|
/*
|
|
* x86-64 GP registers defined as callee-preserved, as per System V Application Binary Interface,
|
|
* AMD64 Architecture Processor Supplement - Draft Version 0.99.6
|
|
*/
|
|
static const plcrash_regnum_t x86_64_nonvolatile_registers[] = {
|
|
PLCRASH_X86_64_RBX,
|
|
PLCRASH_X86_64_RSP,
|
|
PLCRASH_X86_64_RBP,
|
|
PLCRASH_X86_64_R12,
|
|
PLCRASH_X86_64_R13,
|
|
PLCRASH_X86_64_R14,
|
|
PLCRASH_X86_64_R15
|
|
};
|
|
|
|
/*
|
|
* i386 GCC eh_frame register mappings as defined by GCC and LLVM/clang. These mappings
|
|
* appear to have originally been defined by the SVR4 reference port C compiler,
|
|
* and then later implemented by GCC for its 80386 target.
|
|
*
|
|
* This set of registers defines the common intersection of the gcc/llvm implementations.
|
|
* It appears that LLVM implements a strict subset of the GCC-defined register set, but
|
|
* further investigation is warranted prior to expanding the set of defined DWARF registers.
|
|
*
|
|
* Note that not all registers defined by gcc/LLVM are currently supported by our
|
|
* thread-state API, and are not mapped.
|
|
*
|
|
* @warning These mappings are not accurate for use in DWARF debug_frame.
|
|
*/
|
|
static const struct dwarf_register_table x86_32_dwarf_table [] = {
|
|
{ PLCRASH_X86_EAX, 0 },
|
|
{ PLCRASH_X86_ECX, 1 },
|
|
{ PLCRASH_X86_EDX, 2 },
|
|
{ PLCRASH_X86_EBX, 3 },
|
|
{ PLCRASH_X86_EBP, 4 },
|
|
{ PLCRASH_X86_ESP, 5 },
|
|
{ PLCRASH_X86_ESI, 6 },
|
|
{ PLCRASH_X86_EDI, 7 },
|
|
{ PLCRASH_X86_EIP, 8 }
|
|
};
|
|
|
|
/*
|
|
* x86-64 DWARF register mappings as defined in the System V Application Binary Interface,
|
|
* AMD64 Architecture Processor Supplement - Draft Version 0.99.6
|
|
*
|
|
* Note that not all registers defined the AMD64 ABI are currently supported by our
|
|
* thread-state API, and are not mapped.
|
|
*/
|
|
static const struct dwarf_register_table x86_64_dwarf_table [] = {
|
|
{ PLCRASH_X86_64_RAX, 0 },
|
|
{ PLCRASH_X86_64_RDX, 1 },
|
|
{ PLCRASH_X86_64_RCX, 2 },
|
|
{ PLCRASH_X86_64_RBX, 3 },
|
|
{ PLCRASH_X86_64_RSI, 4 },
|
|
{ PLCRASH_X86_64_RDI, 5 },
|
|
{ PLCRASH_X86_64_RBP, 6 },
|
|
{ PLCRASH_X86_64_RSP, 7 },
|
|
|
|
{ PLCRASH_X86_64_R8, 8 },
|
|
{ PLCRASH_X86_64_R9, 9 },
|
|
{ PLCRASH_X86_64_R10, 10 },
|
|
{ PLCRASH_X86_64_R11, 11 },
|
|
{ PLCRASH_X86_64_R12, 12 },
|
|
{ PLCRASH_X86_64_R13, 13 },
|
|
{ PLCRASH_X86_64_R14, 14 },
|
|
{ PLCRASH_X86_64_R15, 15 },
|
|
|
|
{ PLCRASH_X86_64_RFLAGS, 49 },
|
|
|
|
{ PLCRASH_X86_64_CS, 51 },
|
|
{ PLCRASH_X86_64_FS, 54 },
|
|
{ PLCRASH_X86_64_GS, 55 }
|
|
};
|
|
|
|
static plcrash_greg_t plcrash_async_thread_state_get_reg_32 (const plcrash_async_thread_state_t *thread_state, plcrash_regnum_t regnum);
|
|
static plcrash_greg_t plcrash_async_thread_state_get_reg_64 (const plcrash_async_thread_state_t *thread_state, plcrash_regnum_t regnum);
|
|
|
|
static void plcrash_async_thread_state_set_reg_32 (plcrash_async_thread_state_t *cursor, plcrash_regnum_t regnum, plcrash_greg_t reg);
|
|
static void plcrash_async_thread_state_set_reg_64 (plcrash_async_thread_state_t *cursor, plcrash_regnum_t regnum, plcrash_greg_t reg);
|
|
|
|
static const char *plcrash_async_thread_state_get_regname_32 (plcrash_regnum_t regnum);
|
|
static const char *plcrash_async_thread_state_get_regname_64 (plcrash_regnum_t regnum);
|
|
|
|
plcrash_regnum_t plcrash_async_thread_state_map_dwarf_reg_32 (uint64_t dwarf_reg, plcrash_regnum_t *regnum);
|
|
plcrash_regnum_t plcrash_async_thread_state_map_dwarf_reg_64 (uint64_t dwarf_reg, plcrash_regnum_t *regnum);
|
|
|
|
// PLCrashAsyncThread API
|
|
plcrash_greg_t plcrash_async_thread_state_get_reg (const plcrash_async_thread_state_t *thread_state, plcrash_regnum_t regnum) {
|
|
if (thread_state->x86_state.thread.tsh.flavor == x86_THREAD_STATE32) {
|
|
return plcrash_async_thread_state_get_reg_32(thread_state, regnum);
|
|
} else {
|
|
return plcrash_async_thread_state_get_reg_64(thread_state, regnum);
|
|
}
|
|
}
|
|
|
|
// PLCrashAsyncThread API
|
|
void plcrash_async_thread_state_set_reg (plcrash_async_thread_state_t *thread_state, plcrash_regnum_t regnum, plcrash_greg_t reg) {
|
|
if (thread_state->x86_state.thread.tsh.flavor == x86_THREAD_STATE32) {
|
|
return plcrash_async_thread_state_set_reg_32(thread_state, regnum, reg);
|
|
} else {
|
|
return plcrash_async_thread_state_set_reg_64(thread_state, regnum, reg);
|
|
}
|
|
}
|
|
|
|
// PLCrashAsyncThread API
|
|
char const *plcrash_async_thread_state_get_reg_name (const plcrash_async_thread_state_t *thread_state, plcrash_regnum_t regnum) {
|
|
if (thread_state->x86_state.thread.tsh.flavor == x86_THREAD_STATE32) {
|
|
return plcrash_async_thread_state_get_regname_32(regnum);
|
|
} else {
|
|
return plcrash_async_thread_state_get_regname_64(regnum);
|
|
}
|
|
}
|
|
|
|
// PLCrashAsyncThread API
|
|
size_t plcrash_async_thread_state_get_reg_count (const plcrash_async_thread_state_t *thread_state) {
|
|
/* Last is an index value, so increment to get the count */
|
|
if (thread_state->x86_state.thread.tsh.flavor == x86_THREAD_STATE32) {
|
|
return PLCRASH_X86_LAST_REG+1;
|
|
} else {
|
|
return PLCRASH_X86_64_LAST_REG+1;
|
|
}
|
|
}
|
|
|
|
// PLCrashAsyncThread API
|
|
void plcrash_async_thread_state_clear_volatile_regs (plcrash_async_thread_state_t *thread_state) {
|
|
const plcrash_regnum_t *table;
|
|
size_t table_count = 0;
|
|
|
|
if (thread_state->x86_state.thread.tsh.flavor == x86_THREAD_STATE32) {
|
|
table = x86_32_nonvolatile_registers;
|
|
table_count = sizeof(x86_32_nonvolatile_registers) / sizeof(x86_32_nonvolatile_registers[0]);
|
|
} else {
|
|
table = x86_64_nonvolatile_registers;
|
|
table_count = sizeof(x86_64_nonvolatile_registers) / sizeof(x86_64_nonvolatile_registers[0]);
|
|
}
|
|
|
|
plcrash_regnum_t reg_count = (plcrash_regnum_t) plcrash_async_thread_state_get_reg_count(thread_state);
|
|
for (plcrash_regnum_t reg = 0; reg < reg_count; reg++) {
|
|
/* Skip unset registers */
|
|
if (!plcrash_async_thread_state_has_reg(thread_state, reg))
|
|
continue;
|
|
|
|
/* Check for the register in the preservation table */
|
|
bool preserved = false;
|
|
for (size_t i = 0; i < table_count; i++) {
|
|
if (table[i] == reg) {
|
|
preserved = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If not preserved, clear */
|
|
if (!preserved)
|
|
plcrash_async_thread_state_clear_reg(thread_state, reg);
|
|
}
|
|
}
|
|
|
|
// PLCrashAsyncThread API
|
|
bool plcrash_async_thread_state_map_dwarf_to_reg (const plcrash_async_thread_state_t *thread_state, uint64_t dwarf_reg, plcrash_regnum_t *regnum) {
|
|
const struct dwarf_register_table *table;
|
|
size_t table_count = 0;
|
|
|
|
if (thread_state->x86_state.thread.tsh.flavor == x86_THREAD_STATE32) {
|
|
table = x86_32_dwarf_table;
|
|
table_count = sizeof(x86_32_dwarf_table) / sizeof(x86_32_dwarf_table[0]);
|
|
} else {
|
|
table = x86_64_dwarf_table;
|
|
table_count = sizeof(x86_64_dwarf_table) / sizeof(x86_64_dwarf_table[0]);
|
|
}
|
|
|
|
for (size_t i = 0; i < table_count; i++) {
|
|
if (table[i].dwarf_value == dwarf_reg) {
|
|
*regnum = table[i].regnum;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/* Unknown DWARF register. */
|
|
return false;
|
|
}
|
|
|
|
// PLCrashAsyncThread API
|
|
bool plcrash_async_thread_state_map_reg_to_dwarf (plcrash_async_thread_state_t *thread_state, plcrash_regnum_t regnum, uint64_t *dwarf_reg) {
|
|
const struct dwarf_register_table *table;
|
|
size_t table_count = 0;
|
|
|
|
if (thread_state->x86_state.thread.tsh.flavor == x86_THREAD_STATE32) {
|
|
table = x86_32_dwarf_table;
|
|
table_count = sizeof(x86_32_dwarf_table) / sizeof(x86_32_dwarf_table[0]);
|
|
} else {
|
|
table = x86_64_dwarf_table;
|
|
table_count = sizeof(x86_64_dwarf_table) / sizeof(x86_64_dwarf_table[0]);
|
|
}
|
|
|
|
for (size_t i = 0; i < table_count; i++) {
|
|
if (table[i].regnum == regnum) {
|
|
*dwarf_reg = table[i].dwarf_value;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/* Unknown register. */
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
* 32-bit implementation of plcrash_async_thread_state_get_reg()
|
|
*/
|
|
static plcrash_greg_t plcrash_async_thread_state_get_reg_32 (const plcrash_async_thread_state_t *thread_state, plcrash_regnum_t regnum) {
|
|
const plcrash_async_thread_state_t *ts = thread_state;
|
|
|
|
/* All word-sized registers */
|
|
switch (regnum) {
|
|
case PLCRASH_X86_EAX:
|
|
RETGEN(eax, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_EDX:
|
|
RETGEN(edx, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_ECX:
|
|
RETGEN(ecx, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_EBX:
|
|
RETGEN(ebx, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_EBP:
|
|
RETGEN(ebp, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_ESI:
|
|
RETGEN(esi, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_EDI:
|
|
RETGEN(edi, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_ESP:
|
|
RETGEN(esp, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_EIP:
|
|
RETGEN(eip, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_EFLAGS:
|
|
RETGEN(eflags, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_TRAPNO:
|
|
RETGEN(trapno, exception.ues.es32, ts);
|
|
|
|
case PLCRASH_X86_CS:
|
|
RETGEN(cs, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_DS:
|
|
RETGEN(ds, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_ES:
|
|
RETGEN(es, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_FS:
|
|
RETGEN(fs, thread.uts.ts32, ts);
|
|
|
|
case PLCRASH_X86_GS:
|
|
RETGEN(gs, thread.uts.ts32, ts);
|
|
|
|
default:
|
|
// Unsupported register
|
|
__builtin_trap();
|
|
}
|
|
|
|
/* Shouldn't be reachable */
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
* 64-bit implementation of plcrash_async_thread_state_get_reg()
|
|
*/
|
|
static plcrash_greg_t plcrash_async_thread_state_get_reg_64 (const plcrash_async_thread_state_t *thread_state, plcrash_regnum_t regnum) {
|
|
const plcrash_async_thread_state_t *ts = thread_state;
|
|
|
|
switch (regnum) {
|
|
case PLCRASH_X86_64_RAX:
|
|
RETGEN(rax, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_RBX:
|
|
RETGEN(rbx, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_RCX:
|
|
RETGEN(rcx, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_RDX:
|
|
RETGEN(rdx, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_RDI:
|
|
RETGEN(rdi, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_RSI:
|
|
RETGEN(rsi, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_RBP:
|
|
RETGEN(rbp, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_RSP:
|
|
RETGEN(rsp, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_R8:
|
|
RETGEN(r8, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_R9:
|
|
RETGEN(r9, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_R10:
|
|
RETGEN(r10, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_R11:
|
|
RETGEN(r11, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_R12:
|
|
RETGEN(r12, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_R13:
|
|
RETGEN(r13, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_R14:
|
|
RETGEN(r14, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_R15:
|
|
RETGEN(r15, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_RIP:
|
|
RETGEN(rip, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_RFLAGS:
|
|
RETGEN(rflags, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_CS:
|
|
RETGEN(cs, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_FS:
|
|
RETGEN(fs, thread.uts.ts64, ts);
|
|
|
|
case PLCRASH_X86_64_GS:
|
|
RETGEN(gs, thread.uts.ts64, ts);
|
|
|
|
default:
|
|
// Unsupported register
|
|
__builtin_trap();
|
|
}
|
|
|
|
/* Should not be reachable */
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
* 32-bit implementation of plcrash_async_thread_state_set_reg()
|
|
*/
|
|
static void plcrash_async_thread_state_set_reg_32 (plcrash_async_thread_state_t *thread_state, plcrash_regnum_t regnum, plcrash_greg_t reg) {
|
|
plcrash_async_thread_state_t *ts = thread_state;
|
|
|
|
/* All word-sized registers */
|
|
switch (regnum) {
|
|
case PLCRASH_X86_EAX:
|
|
SETGEN(eax, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_EDX:
|
|
SETGEN(edx, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_ECX:
|
|
SETGEN(ecx, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_EBX:
|
|
SETGEN(ebx, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_EBP:
|
|
SETGEN(ebp, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_ESI:
|
|
SETGEN(esi, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_EDI:
|
|
SETGEN(edi, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_ESP:
|
|
SETGEN(esp, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_EIP:
|
|
SETGEN(eip, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_EFLAGS:
|
|
SETGEN(eflags, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_TRAPNO:
|
|
SETGEN(trapno, exception.ues.es32, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_CS:
|
|
SETGEN(cs, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_DS:
|
|
SETGEN(ds, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_ES:
|
|
SETGEN(es, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_FS:
|
|
SETGEN(fs, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
case PLCRASH_X86_GS:
|
|
SETGEN(gs, thread.uts.ts32, ts, regnum, (uint32_t)reg);
|
|
|
|
default:
|
|
// Unsupported register
|
|
__builtin_trap();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
* 64-bit implementation of plcrash_async_thread_state_set_reg()
|
|
*/
|
|
static void plcrash_async_thread_state_set_reg_64 (plcrash_async_thread_state_t *thread_state, plcrash_regnum_t regnum, plcrash_greg_t reg) {
|
|
plcrash_async_thread_state_t *ts = thread_state;
|
|
|
|
switch (regnum) {
|
|
case PLCRASH_X86_64_RAX:
|
|
SETGEN(rax, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_RBX:
|
|
SETGEN(rbx, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_RCX:
|
|
SETGEN(rcx, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_RDX:
|
|
SETGEN(rdx, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_RDI:
|
|
SETGEN(rdi, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_RSI:
|
|
SETGEN(rsi, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_RBP:
|
|
SETGEN(rbp, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_RSP:
|
|
SETGEN(rsp, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_R8:
|
|
SETGEN(r8, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_R9:
|
|
SETGEN(r9, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_R10:
|
|
SETGEN(r10, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_R11:
|
|
SETGEN(r11, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_R12:
|
|
SETGEN(r12, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_R13:
|
|
SETGEN(r13, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_R14:
|
|
SETGEN(r14, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_R15:
|
|
SETGEN(r15, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_RIP:
|
|
SETGEN(rip, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_RFLAGS:
|
|
SETGEN(rflags, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_CS:
|
|
SETGEN(cs, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_FS:
|
|
SETGEN(fs, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
case PLCRASH_X86_64_GS:
|
|
SETGEN(gs, thread.uts.ts64, ts, regnum, reg);
|
|
|
|
default:
|
|
// Unsupported register
|
|
__builtin_trap();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
* 32-bit implementation of plcrash_async_thread_state_get_regname()
|
|
*/
|
|
static char const *plcrash_async_thread_state_get_regname_32 (plcrash_regnum_t regnum) {
|
|
/* All word-sized registers */
|
|
switch (regnum) {
|
|
case PLCRASH_X86_EAX:
|
|
return "eax";
|
|
|
|
case PLCRASH_X86_EDX:
|
|
return "edx";
|
|
|
|
case PLCRASH_X86_ECX:
|
|
return "ecx";
|
|
|
|
case PLCRASH_X86_EBX:
|
|
return "ebx";
|
|
|
|
case PLCRASH_X86_EBP:
|
|
return "ebp";
|
|
|
|
case PLCRASH_X86_ESI:
|
|
return "esi";
|
|
|
|
case PLCRASH_X86_EDI:
|
|
return "edi";
|
|
|
|
case PLCRASH_X86_ESP:
|
|
return "esp";
|
|
|
|
case PLCRASH_X86_EIP:
|
|
return "eip";
|
|
|
|
case PLCRASH_X86_EFLAGS:
|
|
return "eflags";
|
|
|
|
case PLCRASH_X86_TRAPNO:
|
|
return "trapno";
|
|
|
|
case PLCRASH_X86_CS:
|
|
return "cs";
|
|
|
|
case PLCRASH_X86_DS:
|
|
return "ds";
|
|
|
|
case PLCRASH_X86_ES:
|
|
return "es";
|
|
|
|
case PLCRASH_X86_FS:
|
|
return "fs";
|
|
|
|
case PLCRASH_X86_GS:
|
|
return "gs";
|
|
|
|
default:
|
|
// Unsupported register
|
|
break;
|
|
}
|
|
|
|
/* Unsupported register is an implementation error (checked in unit tests) */
|
|
PLCF_DEBUG("Missing register name for register id: %d", regnum);
|
|
abort();
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
* 64-bit implementation of plcrash_async_thread_state_get_regname()
|
|
*/
|
|
static const char *plcrash_async_thread_state_get_regname_64 (plcrash_regnum_t regnum) {
|
|
switch (regnum) {
|
|
case PLCRASH_X86_64_RAX:
|
|
return "rax";
|
|
|
|
case PLCRASH_X86_64_RBX:
|
|
return "rbx";
|
|
|
|
case PLCRASH_X86_64_RCX:
|
|
return "rcx";
|
|
|
|
case PLCRASH_X86_64_RDX:
|
|
return "rdx";
|
|
|
|
case PLCRASH_X86_64_RDI:
|
|
return "rdi";
|
|
|
|
case PLCRASH_X86_64_RSI:
|
|
return "rsi";
|
|
|
|
case PLCRASH_X86_64_RBP:
|
|
return "rbp";
|
|
|
|
case PLCRASH_X86_64_RSP:
|
|
return "rsp";
|
|
|
|
case PLCRASH_X86_64_R8:
|
|
return "r8";
|
|
|
|
case PLCRASH_X86_64_R9:
|
|
return "r9";
|
|
|
|
case PLCRASH_X86_64_R10:
|
|
return "r10";
|
|
|
|
case PLCRASH_X86_64_R11:
|
|
return "r11";
|
|
|
|
case PLCRASH_X86_64_R12:
|
|
return "r12";
|
|
|
|
case PLCRASH_X86_64_R13:
|
|
return "r13";
|
|
|
|
case PLCRASH_X86_64_R14:
|
|
return "r14";
|
|
|
|
case PLCRASH_X86_64_R15:
|
|
return "r15";
|
|
|
|
case PLCRASH_X86_64_RIP:
|
|
return "rip";
|
|
|
|
case PLCRASH_X86_64_RFLAGS:
|
|
return "rflags";
|
|
|
|
case PLCRASH_X86_64_CS:
|
|
return "cs";
|
|
|
|
case PLCRASH_X86_64_FS:
|
|
return "fs";
|
|
|
|
case PLCRASH_X86_64_GS:
|
|
return "gs";
|
|
|
|
default:
|
|
// Unsupported register
|
|
break;
|
|
}
|
|
|
|
/* Unsupported register is an implementation error (checked in unit tests) */
|
|
PLCF_DEBUG("Missing register name for register id: %d", regnum);
|
|
abort();
|
|
}
|
|
|
|
#endif /* defined(__i386__) || defined(__x86_64__) */
|