2020-11-27 12:06:56 +00:00
|
|
|
// (C) Copyright IBM Corp. 2020
|
2021-04-03 09:10:35 +01:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
2020-11-27 12:06:56 +00:00
|
|
|
|
|
|
|
#include <byteswap.h>
|
2021-02-23 22:31:01 +00:00
|
|
|
#include <string.h>
|
2020-11-27 12:06:56 +00:00
|
|
|
|
|
|
|
#include "drgn.h"
|
|
|
|
#include "error.h"
|
2021-01-20 23:59:14 +00:00
|
|
|
#include "platform.h" // IWYU pragma: associated
|
2020-11-27 12:06:56 +00:00
|
|
|
#include "program.h"
|
2021-03-10 09:51:33 +00:00
|
|
|
#include "register_state.h"
|
|
|
|
#include "serialize.h"
|
2020-11-27 12:06:56 +00:00
|
|
|
|
2022-06-11 16:32:24 +01:00
|
|
|
#include "arch_ppc64_defs.inc"
|
2020-11-27 12:06:56 +00:00
|
|
|
|
2021-04-02 23:56:41 +01:00
|
|
|
static const struct drgn_cfi_row default_dwarf_cfi_row_ppc64 = DRGN_CFI_ROW(
|
libdrgn: ppc64: fix DWARF link register confusion
The usage of the link register in DWARF is a little confusing. On entry
to a function, the link register contains the address that should be
returned to. However, for DWARF, the link register is usually used as
the CFI return_address_register, which means that in an unwound frame,
it will contain the same thing as the program counter. I initially
thought that this was a mistake, believing that the link register should
contain the _next_ return address. However, after a return (with the blr
instruction), the link register will indeed contain the same address as
the program counter. This is consistent with our documentation of
register values for function call frames: "the register values are the
values when control returns to this frame".
So, rename our internal "ra" register to "lr", expose it to the API, and
add a little more documentation to the ppc64 initial register code.
Fixes: 221a21870459 ("libdrgn: add powerpc stack trace support")
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2022-06-22 02:39:29 +01:00
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(lr)),
|
2021-04-02 23:56:41 +01:00
|
|
|
[DRGN_REGISTER_NUMBER(r1)] = { DRGN_CFI_RULE_CFA_PLUS_OFFSET },
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r14)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r15)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r16)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r17)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r18)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r19)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r20)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r21)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r22)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r23)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r24)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r25)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r26)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r27)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r28)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r29)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r30)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(r31)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(cr2)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(cr3)),
|
|
|
|
DRGN_CFI_SAME_VALUE_INIT(DRGN_REGISTER_NUMBER(cr4)),
|
|
|
|
);
|
|
|
|
|
2022-06-24 10:19:54 +01:00
|
|
|
// Unwind using the stack frame back chain. Note that leaf functions may not
|
|
|
|
// allocate a stack frame, so this may skip the caller of a leaf function. I
|
|
|
|
// don't know of a good way around that.
|
2020-11-27 12:06:56 +00:00
|
|
|
static struct drgn_error *
|
2021-03-10 09:51:33 +00:00
|
|
|
fallback_unwind_ppc64(struct drgn_program *prog,
|
|
|
|
struct drgn_register_state *regs,
|
|
|
|
struct drgn_register_state **ret)
|
|
|
|
{
|
|
|
|
struct drgn_error *err;
|
|
|
|
|
2022-06-24 09:50:51 +01:00
|
|
|
struct optional_uint64 r1 = drgn_register_state_get_u64(prog, regs, r1);
|
2022-06-24 10:19:54 +01:00
|
|
|
if (!r1.has_value)
|
2021-03-10 09:51:33 +00:00
|
|
|
return &drgn_stop;
|
|
|
|
|
2022-06-24 10:19:54 +01:00
|
|
|
// The stack pointer (r1) points to the lowest address of the stack
|
|
|
|
// frame (the stack grows downwards from high addresses to low
|
|
|
|
// addresses), which contains the caller's stack pointer.
|
|
|
|
uint64_t unwound_r1;
|
|
|
|
err = drgn_program_read_u64(prog, r1.value, false, &unwound_r1);
|
|
|
|
uint64_t saved_lr;
|
|
|
|
if (!err) {
|
|
|
|
if (unwound_r1 <= r1.value) {
|
|
|
|
// The unwound stack pointer is either 0, indicating the
|
|
|
|
// first stack frame, or invalid.
|
|
|
|
return &drgn_stop;
|
|
|
|
}
|
|
|
|
// The return address (the saved lr) is stored 16 bytes into the
|
|
|
|
// caller's stack frame.
|
|
|
|
err = drgn_program_read_memory(prog, &saved_lr, unwound_r1 + 16,
|
|
|
|
sizeof(saved_lr), false);
|
|
|
|
}
|
2021-03-10 09:51:33 +00:00
|
|
|
if (err) {
|
|
|
|
if (err->code == DRGN_ERROR_FAULT) {
|
|
|
|
drgn_error_destroy(err);
|
|
|
|
err = &drgn_stop;
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct drgn_register_state *unwound =
|
2022-06-24 10:19:54 +01:00
|
|
|
drgn_register_state_create(r1, false);
|
2021-03-10 09:51:33 +00:00
|
|
|
if (!unwound)
|
|
|
|
return &drgn_enomem;
|
2022-06-24 10:19:54 +01:00
|
|
|
drgn_register_state_set_from_buffer(unwound, lr, &saved_lr);
|
|
|
|
drgn_register_state_set_from_u64(prog, unwound, r1, unwound_r1);
|
|
|
|
drgn_register_state_set_pc_from_register(prog, unwound, lr);
|
2021-03-10 09:51:33 +00:00
|
|
|
*ret = unwound;
|
|
|
|
drgn_register_state_set_cfa(prog, regs, unwound_r1);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct drgn_error *
|
|
|
|
get_initial_registers_from_struct_ppc64(struct drgn_program *prog,
|
|
|
|
const void *buf, size_t size,
|
|
|
|
bool linux_kernel_prstatus,
|
|
|
|
bool linux_kernel_switched_out,
|
|
|
|
struct drgn_register_state **ret)
|
2020-11-27 12:06:56 +00:00
|
|
|
{
|
|
|
|
if (size < 312) {
|
|
|
|
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
|
|
|
|
"registers are truncated");
|
|
|
|
}
|
|
|
|
|
2021-02-23 22:06:41 +00:00
|
|
|
bool bswap = drgn_platform_bswap(&prog->platform);
|
Track byte order in scalar types instead of objects
Currently, reference objects and buffer value objects have a byte order.
However, this doesn't always make sense for a couple of reasons:
- Byte order is only meaningful for scalars. What does it mean for a
struct to be big endian? A struct doesn't have a most or least
significant byte; its scalar members do.
- The DWARF specification allows either types or variables to have a
byte order (DW_AT_endianity). The only producer I could find that uses
this is GCC for the scalar_storage_order type attribute, and it only
uses it for base types, not variables. GDB only seems to use to check
it for base types, as well.
So, remove the byte order from objects, and move it to integer, boolean,
floating-point, and pointer types. This model makes more sense, and it
means that we can get the binary representation of any object now.
The only downside is that we can no longer support a bit offset for
non-scalars, but as far as I can tell, nothing needs that.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-02-18 00:13:23 +00:00
|
|
|
|
2021-03-10 09:51:33 +00:00
|
|
|
struct drgn_register_state *regs =
|
|
|
|
drgn_register_state_create(cr7, true);
|
|
|
|
if (!regs)
|
|
|
|
return &drgn_enomem;
|
2020-11-27 12:06:56 +00:00
|
|
|
|
|
|
|
/*
|
2021-03-10 09:51:33 +00:00
|
|
|
* In most cases, nip (word 32) contains the program counter. But, the
|
|
|
|
* NT_PRSTATUS note in Linux kernel vmcores is odd, and the saved stack
|
|
|
|
* pointer (r1) is for the program counter in the link register (word
|
|
|
|
* 36).
|
2020-11-27 12:06:56 +00:00
|
|
|
*/
|
2021-03-10 09:51:33 +00:00
|
|
|
uint64_t pc;
|
|
|
|
memcpy(&pc, (uint64_t *)buf + (linux_kernel_prstatus ? 36 : 32),
|
|
|
|
sizeof(pc));
|
|
|
|
if (bswap)
|
|
|
|
pc = bswap_64(pc);
|
|
|
|
drgn_register_state_set_pc(prog, regs, pc);
|
|
|
|
|
libdrgn: ppc64: fix DWARF link register confusion
The usage of the link register in DWARF is a little confusing. On entry
to a function, the link register contains the address that should be
returned to. However, for DWARF, the link register is usually used as
the CFI return_address_register, which means that in an unwound frame,
it will contain the same thing as the program counter. I initially
thought that this was a mistake, believing that the link register should
contain the _next_ return address. However, after a return (with the blr
instruction), the link register will indeed contain the same address as
the program counter. This is consistent with our documentation of
register values for function call frames: "the register values are the
values when control returns to this frame".
So, rename our internal "ra" register to "lr", expose it to the API, and
add a little more documentation to the ppc64 initial register code.
Fixes: 221a21870459 ("libdrgn: add powerpc stack trace support")
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2022-06-22 02:39:29 +01:00
|
|
|
// Switched out tasks in the Linux kernel only save r14-r31, nip, and
|
|
|
|
// ccr.
|
2021-03-10 09:51:33 +00:00
|
|
|
if (!linux_kernel_switched_out) {
|
|
|
|
if (!linux_kernel_prstatus) {
|
libdrgn: ppc64: fix DWARF link register confusion
The usage of the link register in DWARF is a little confusing. On entry
to a function, the link register contains the address that should be
returned to. However, for DWARF, the link register is usually used as
the CFI return_address_register, which means that in an unwound frame,
it will contain the same thing as the program counter. I initially
thought that this was a mistake, believing that the link register should
contain the _next_ return address. However, after a return (with the blr
instruction), the link register will indeed contain the same address as
the program counter. This is consistent with our documentation of
register values for function call frames: "the register values are the
values when control returns to this frame".
So, rename our internal "ra" register to "lr", expose it to the API, and
add a little more documentation to the ppc64 initial register code.
Fixes: 221a21870459 ("libdrgn: add powerpc stack trace support")
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2022-06-22 02:39:29 +01:00
|
|
|
drgn_register_state_set_from_buffer(regs, lr,
|
2021-03-10 09:51:33 +00:00
|
|
|
(uint64_t *)buf + 36);
|
2020-11-27 12:06:56 +00:00
|
|
|
}
|
2021-03-10 09:51:33 +00:00
|
|
|
drgn_register_state_set_range_from_buffer(regs, r0, r13, buf);
|
2020-11-27 12:06:56 +00:00
|
|
|
}
|
2021-03-10 09:51:33 +00:00
|
|
|
drgn_register_state_set_range_from_buffer(regs, r14, r31,
|
|
|
|
(uint64_t *)buf + 14);
|
2020-11-27 12:06:56 +00:00
|
|
|
|
2021-03-10 09:51:33 +00:00
|
|
|
uint64_t ccr;
|
|
|
|
memcpy(&ccr, (uint64_t *)regs + 38, sizeof(ccr));
|
|
|
|
uint64_t cr[8];
|
|
|
|
if (bswap) {
|
|
|
|
for (int i = 0; i < 8; i += 2) {
|
|
|
|
cr[i] = ccr & (UINT64_C(0xf) << (36 + 4 * i));
|
|
|
|
cr[i + 1] = ccr & (UINT64_C(0xf) << (32 + 4 * i));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
cr[i] = ccr & (UINT64_C(0xf) << (28 - 4 * i));
|
|
|
|
}
|
|
|
|
drgn_register_state_set_range_from_buffer(regs, cr0, cr7, cr);
|
2020-11-27 12:06:56 +00:00
|
|
|
|
2021-03-10 09:51:33 +00:00
|
|
|
*ret = regs;
|
2020-11-27 12:06:56 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct drgn_error *
|
2021-03-10 09:51:33 +00:00
|
|
|
pt_regs_get_initial_registers_ppc64(const struct drgn_object *obj,
|
|
|
|
struct drgn_register_state **ret)
|
2020-11-27 12:06:56 +00:00
|
|
|
{
|
2021-03-10 09:51:33 +00:00
|
|
|
return get_initial_registers_from_struct_ppc64(drgn_object_program(obj),
|
2020-11-27 12:06:56 +00:00
|
|
|
drgn_object_buffer(obj),
|
|
|
|
drgn_object_size(obj),
|
2021-03-10 09:51:33 +00:00
|
|
|
false, false, ret);
|
2020-11-27 12:06:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct drgn_error *
|
2021-03-10 09:51:33 +00:00
|
|
|
prstatus_get_initial_registers_ppc64(struct drgn_program *prog,
|
|
|
|
const void *prstatus, size_t size,
|
|
|
|
struct drgn_register_state **ret)
|
2020-11-27 12:06:56 +00:00
|
|
|
{
|
|
|
|
if (size < 112) {
|
|
|
|
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
|
2021-03-10 09:51:33 +00:00
|
|
|
"NT_PRSTATUS is truncated");
|
2020-11-27 12:06:56 +00:00
|
|
|
}
|
|
|
|
bool is_linux_kernel = prog->flags & DRGN_PROGRAM_IS_LINUX_KERNEL;
|
2021-03-10 09:51:33 +00:00
|
|
|
return get_initial_registers_from_struct_ppc64(prog,
|
2020-11-27 12:06:56 +00:00
|
|
|
(char *)prstatus + 112,
|
Track byte order in scalar types instead of objects
Currently, reference objects and buffer value objects have a byte order.
However, this doesn't always make sense for a couple of reasons:
- Byte order is only meaningful for scalars. What does it mean for a
struct to be big endian? A struct doesn't have a most or least
significant byte; its scalar members do.
- The DWARF specification allows either types or variables to have a
byte order (DW_AT_endianity). The only producer I could find that uses
this is GCC for the scalar_storage_order type attribute, and it only
uses it for base types, not variables. GDB only seems to use to check
it for base types, as well.
So, remove the byte order from objects, and move it to integer, boolean,
floating-point, and pointer types. This model makes more sense, and it
means that we can get the binary representation of any object now.
The only downside is that we can no longer support a bit offset for
non-scalars, but as far as I can tell, nothing needs that.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-02-18 00:13:23 +00:00
|
|
|
size - 112,
|
2021-03-10 09:51:33 +00:00
|
|
|
is_linux_kernel, false,
|
|
|
|
ret);
|
2020-11-27 12:06:56 +00:00
|
|
|
}
|
|
|
|
|
libdrgn: ppc64: fix DWARF link register confusion
The usage of the link register in DWARF is a little confusing. On entry
to a function, the link register contains the address that should be
returned to. However, for DWARF, the link register is usually used as
the CFI return_address_register, which means that in an unwound frame,
it will contain the same thing as the program counter. I initially
thought that this was a mistake, believing that the link register should
contain the _next_ return address. However, after a return (with the blr
instruction), the link register will indeed contain the same address as
the program counter. This is consistent with our documentation of
register values for function call frames: "the register values are the
values when control returns to this frame".
So, rename our internal "ra" register to "lr", expose it to the API, and
add a little more documentation to the ppc64 initial register code.
Fixes: 221a21870459 ("libdrgn: add powerpc stack trace support")
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2022-06-22 02:39:29 +01:00
|
|
|
// The Linux kernel saves the callee-saved registers in a struct pt_regs on the
|
|
|
|
// thread's kernel stack. See _switch() in arch/powerpc/kernel/entry_64.S (as of
|
|
|
|
// Linux v5.19).
|
2020-11-27 12:06:56 +00:00
|
|
|
static struct drgn_error *
|
2021-03-10 09:51:33 +00:00
|
|
|
linux_kernel_get_initial_registers_ppc64(const struct drgn_object *task_obj,
|
|
|
|
struct drgn_register_state **ret)
|
|
|
|
|
2020-11-27 12:06:56 +00:00
|
|
|
{
|
|
|
|
static const uint64_t STACK_FRAME_OVERHEAD = 112;
|
|
|
|
static const uint64_t SWITCH_FRAME_SIZE = STACK_FRAME_OVERHEAD + 368;
|
|
|
|
|
|
|
|
struct drgn_error *err;
|
|
|
|
struct drgn_program *prog = drgn_object_program(task_obj);
|
|
|
|
|
|
|
|
struct drgn_object sp_obj;
|
|
|
|
drgn_object_init(&sp_obj, prog);
|
|
|
|
|
|
|
|
err = drgn_object_member_dereference(&sp_obj, task_obj, "thread");
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
err = drgn_object_member(&sp_obj, &sp_obj, "ksp");
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
uint64_t ksp;
|
|
|
|
err = drgn_object_read_unsigned(&sp_obj, &ksp);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2021-03-10 09:51:33 +00:00
|
|
|
char buf[312];
|
|
|
|
err = drgn_program_read_memory(prog, buf, ksp + STACK_FRAME_OVERHEAD,
|
|
|
|
sizeof(buf), false);
|
2020-11-27 12:06:56 +00:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2021-03-10 09:51:33 +00:00
|
|
|
err = get_initial_registers_from_struct_ppc64(prog, buf, sizeof(buf),
|
|
|
|
false, true, ret);
|
2020-11-27 12:06:56 +00:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2022-06-24 08:36:09 +01:00
|
|
|
drgn_register_state_set_from_u64(prog, *ret, r1,
|
|
|
|
ksp + SWITCH_FRAME_SIZE);
|
2020-11-27 12:06:56 +00:00
|
|
|
|
|
|
|
err = NULL;
|
|
|
|
out:
|
|
|
|
drgn_object_deinit(&sp_obj);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2021-12-02 10:38:31 +00:00
|
|
|
static struct drgn_error *
|
|
|
|
apply_elf_reloc_ppc64(const struct drgn_relocating_section *relocating,
|
|
|
|
uint64_t r_offset, uint32_t r_type,
|
|
|
|
const int64_t *r_addend, uint64_t sym_value)
|
|
|
|
{
|
|
|
|
switch (r_type) {
|
|
|
|
case R_PPC64_NONE:
|
|
|
|
return NULL;
|
|
|
|
case R_PPC64_ADDR32:
|
|
|
|
return drgn_reloc_add32(relocating, r_offset, r_addend,
|
|
|
|
sym_value);
|
|
|
|
case R_PPC64_REL32:
|
|
|
|
return drgn_reloc_add32(relocating, r_offset, r_addend,
|
|
|
|
sym_value
|
|
|
|
- (relocating->addr + r_offset));
|
|
|
|
case R_PPC64_ADDR64:
|
|
|
|
return drgn_reloc_add64(relocating, r_offset, r_addend,
|
|
|
|
sym_value);
|
|
|
|
case R_PPC64_REL64:
|
|
|
|
return drgn_reloc_add64(relocating, r_offset, r_addend,
|
|
|
|
sym_value
|
|
|
|
- (relocating->addr + r_offset));
|
|
|
|
default:
|
|
|
|
return DRGN_UNKNOWN_RELOCATION_TYPE(r_type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-27 12:06:56 +00:00
|
|
|
const struct drgn_architecture_info arch_info_ppc64 = {
|
libdrgn: define structure for storing processor register values
libdwfl stores registers in an array of uint64_t indexed by the DWARF
register number. This is suboptimal for a couple of reasons:
1. Although the DWARF specification states that registers should be
numbered for "optimal density", in practice this isn't the case. ABIs
include unused ranges of numbers and don't order registers based on
how likely they are to be known (e.g., caller-saved registers usually
aren't recovered while unwinding the stack, but they are often
numbered before callee-saved registers).
2. This precludes support for registers larger than 64 bits, like SSE
registers.
For our own unwinder, we want to store registers in an
architecture-specific format to solve both of these problems.
So, have each architecture define its layout with registers arranged for
space efficiency and convenience when parsing saved registers from core
dumps. Instead of generating an arch_foo.c file from arch_foo.c.in,
separately define the logical register order in an arch_foo.defs file,
and use it to generate an arch_foo.inc file that is included from
arch_foo.c. The layout is defined as a macro in arch_foo.c. While we're
here, drop some register definitions that aren't useful at the moment.
Then, define struct drgn_register_state to efficiently store registers
in the defined format.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-02-09 10:01:50 +00:00
|
|
|
.name = "ppc64",
|
|
|
|
.arch = DRGN_ARCH_PPC64,
|
2020-11-27 12:06:56 +00:00
|
|
|
.default_flags = (DRGN_PLATFORM_IS_64_BIT |
|
|
|
|
DRGN_PLATFORM_IS_LITTLE_ENDIAN),
|
libdrgn: define structure for storing processor register values
libdwfl stores registers in an array of uint64_t indexed by the DWARF
register number. This is suboptimal for a couple of reasons:
1. Although the DWARF specification states that registers should be
numbered for "optimal density", in practice this isn't the case. ABIs
include unused ranges of numbers and don't order registers based on
how likely they are to be known (e.g., caller-saved registers usually
aren't recovered while unwinding the stack, but they are often
numbered before callee-saved registers).
2. This precludes support for registers larger than 64 bits, like SSE
registers.
For our own unwinder, we want to store registers in an
architecture-specific format to solve both of these problems.
So, have each architecture define its layout with registers arranged for
space efficiency and convenience when parsing saved registers from core
dumps. Instead of generating an arch_foo.c file from arch_foo.c.in,
separately define the logical register order in an arch_foo.defs file,
and use it to generate an arch_foo.inc file that is included from
arch_foo.c. The layout is defined as a macro in arch_foo.c. While we're
here, drop some register definitions that aren't useful at the moment.
Then, define struct drgn_register_state to efficiently store registers
in the defined format.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-02-09 10:01:50 +00:00
|
|
|
DRGN_ARCHITECTURE_REGISTERS,
|
2021-04-02 23:56:41 +01:00
|
|
|
.default_dwarf_cfi_row = &default_dwarf_cfi_row_ppc64,
|
2021-03-10 09:51:33 +00:00
|
|
|
.fallback_unwind = fallback_unwind_ppc64,
|
|
|
|
.pt_regs_get_initial_registers = pt_regs_get_initial_registers_ppc64,
|
|
|
|
.prstatus_get_initial_registers = prstatus_get_initial_registers_ppc64,
|
|
|
|
.linux_kernel_get_initial_registers =
|
|
|
|
linux_kernel_get_initial_registers_ppc64,
|
2021-12-02 10:38:31 +00:00
|
|
|
.apply_elf_reloc = apply_elf_reloc_ppc64,
|
2020-11-27 12:06:56 +00:00
|
|
|
};
|