2020-11-27 12:06:56 +00:00
|
|
|
%{
|
|
|
|
// (C) Copyright IBM Corp. 2020
|
|
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
|
|
|
|
|
|
#include <byteswap.h>
|
|
|
|
#include <elfutils/libdw.h>
|
|
|
|
#include <elfutils/libdwfl.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"
|
|
|
|
#include "platform.h"
|
|
|
|
#include "program.h"
|
|
|
|
%}
|
|
|
|
|
|
|
|
ppc64
|
|
|
|
%%
|
|
|
|
r0
|
|
|
|
r1
|
|
|
|
r2
|
|
|
|
r3
|
|
|
|
r4
|
|
|
|
r5
|
|
|
|
r6
|
|
|
|
r7
|
|
|
|
r8
|
|
|
|
r9
|
|
|
|
r10
|
|
|
|
r11
|
|
|
|
r12
|
|
|
|
r13
|
|
|
|
r14
|
|
|
|
r15
|
|
|
|
r16
|
|
|
|
r17
|
|
|
|
r18
|
|
|
|
r19
|
|
|
|
r20
|
|
|
|
r21
|
|
|
|
r22
|
|
|
|
r23
|
|
|
|
r24
|
|
|
|
r25
|
|
|
|
r26
|
|
|
|
r27
|
|
|
|
r28
|
|
|
|
r29
|
|
|
|
r30
|
|
|
|
r31
|
|
|
|
f0
|
|
|
|
f1
|
|
|
|
f2
|
|
|
|
f3
|
|
|
|
f4
|
|
|
|
f5
|
|
|
|
f6
|
|
|
|
f7
|
|
|
|
f8
|
|
|
|
f9
|
|
|
|
f10
|
|
|
|
f11
|
|
|
|
f12
|
|
|
|
f13
|
|
|
|
f14
|
|
|
|
f15
|
|
|
|
f16
|
|
|
|
f17
|
|
|
|
f18
|
|
|
|
f19
|
|
|
|
f20
|
|
|
|
f21
|
|
|
|
f22
|
|
|
|
f23
|
|
|
|
f24
|
|
|
|
f25
|
|
|
|
f26
|
|
|
|
f27
|
|
|
|
f28
|
|
|
|
f29
|
|
|
|
f30
|
|
|
|
f31
|
|
|
|
# There are two numbering schemes for the remaining registers. The original
|
|
|
|
# definition appears to be "64-bit PowerPC ELF Application Binary Interface
|
|
|
|
# Supplement" [1]. The GNU toolchain instead uses its own that was later
|
|
|
|
# codified in "Power Architecture 64-Bit ELF V2 ABI Specification" [2]. We use
|
|
|
|
# the latter.
|
|
|
|
#
|
|
|
|
# What the ABI calls the link register (register 65) is used as the DWARF CFI
|
|
|
|
# return_address_register column in practice, which is actually the program
|
|
|
|
# counter. We omit it to avoid confusion.
|
|
|
|
#
|
|
|
|
# 1: https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html
|
|
|
|
# 2: https://openpowerfoundation.org/?resource_lib=64-bit-elf-v2-abi-specification-power-architecture
|
|
|
|
cr0, 68
|
|
|
|
cr1
|
|
|
|
cr2
|
|
|
|
cr3
|
|
|
|
cr4
|
|
|
|
cr5
|
|
|
|
cr6
|
|
|
|
cr7
|
|
|
|
%%
|
|
|
|
|
|
|
|
static struct drgn_error *
|
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
|
|
|
set_initial_registers_from_struct_ppc64(struct drgn_program *prog,
|
|
|
|
Dwfl_Thread *thread, const void *regs,
|
|
|
|
size_t size, bool linux_kernel_prstatus,
|
2020-11-27 12:06:56 +00:00
|
|
|
bool linux_kernel_switched_out)
|
|
|
|
{
|
|
|
|
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
|
|
|
|
2020-11-27 12:06:56 +00:00
|
|
|
Dwarf_Word dwarf_regs[32];
|
|
|
|
|
|
|
|
#define READ_REGISTER(n) ({ \
|
|
|
|
uint64_t reg; \
|
|
|
|
memcpy(®, (uint64_t *)regs + (n), sizeof(reg)); \
|
|
|
|
bswap ? bswap_64(reg) : reg; \
|
|
|
|
})
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The NT_PRSTATUS note in Linux kernel vmcores is odd. Since Linux
|
|
|
|
* kernel commit d16a58f8854b ("powerpc: Improve ppc_save_regs()") (in
|
|
|
|
* v5.7), the saved stack pointer (r1) is for the caller of the program
|
|
|
|
* counter saved in nip. Before that, the saved nip is set to the same
|
|
|
|
* as the link register. So, use the link register instead of nip.
|
|
|
|
*/
|
|
|
|
uint64_t nip = READ_REGISTER(32);
|
|
|
|
uint64_t link = READ_REGISTER(36);
|
|
|
|
if (linux_kernel_prstatus) {
|
|
|
|
dwfl_thread_state_register_pc(thread, link);
|
|
|
|
} else {
|
|
|
|
dwfl_thread_state_register_pc(thread, nip);
|
|
|
|
/*
|
|
|
|
* Switched out tasks in the Linux kernel don't save the link
|
|
|
|
* register.
|
|
|
|
*/
|
|
|
|
if (!linux_kernel_switched_out) {
|
|
|
|
dwarf_regs[0] = link;
|
|
|
|
if (!dwfl_thread_state_registers(thread, 65, 1,
|
|
|
|
dwarf_regs))
|
|
|
|
return drgn_error_libdwfl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Switched out tasks in the Linux kernel only save the callee-saved
|
|
|
|
* general purpose registers (14-31).
|
|
|
|
*/
|
|
|
|
int min_gpr = linux_kernel_switched_out ? 14 : 0;
|
|
|
|
for (int i = min_gpr; i < 32; i++)
|
|
|
|
dwarf_regs[i] = READ_REGISTER(i);
|
|
|
|
if (!dwfl_thread_state_registers(thread, min_gpr, 32 - min_gpr,
|
|
|
|
dwarf_regs))
|
|
|
|
return drgn_error_libdwfl();
|
|
|
|
|
|
|
|
/* cr0 - cr7 */
|
|
|
|
uint64_t ccr = READ_REGISTER(38);
|
|
|
|
for (int i = 0; i < 8; i++)
|
2021-02-17 08:45:14 +00:00
|
|
|
dwarf_regs[i] = ccr & (UINT64_C(0xf) << (28 - 4 * i));
|
2020-11-27 12:06:56 +00:00
|
|
|
if (!dwfl_thread_state_registers(thread, 68, 8, dwarf_regs))
|
|
|
|
return drgn_error_libdwfl();
|
|
|
|
|
|
|
|
#undef READ_REGISTER
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct drgn_error *
|
|
|
|
pt_regs_set_initial_registers_ppc64(Dwfl_Thread *thread,
|
|
|
|
const struct drgn_object *obj)
|
|
|
|
{
|
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
|
|
|
return set_initial_registers_from_struct_ppc64(drgn_object_program(obj),
|
|
|
|
thread,
|
2020-11-27 12:06:56 +00:00
|
|
|
drgn_object_buffer(obj),
|
|
|
|
drgn_object_size(obj),
|
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
|
|
|
false, false);
|
2020-11-27 12:06:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct drgn_error *
|
|
|
|
prstatus_set_initial_registers_ppc64(struct drgn_program *prog,
|
|
|
|
Dwfl_Thread *thread, const void *prstatus,
|
|
|
|
size_t size)
|
|
|
|
{
|
|
|
|
if (size < 112) {
|
|
|
|
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
|
|
|
|
"NT_PRSTATUS is truncated");
|
|
|
|
}
|
|
|
|
bool is_linux_kernel = prog->flags & DRGN_PROGRAM_IS_LINUX_KERNEL;
|
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
|
|
|
return set_initial_registers_from_struct_ppc64(prog, thread,
|
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,
|
2020-11-27 12:06:56 +00:00
|
|
|
is_linux_kernel, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct drgn_error *
|
|
|
|
linux_kernel_set_initial_registers_ppc64(Dwfl_Thread *thread,
|
|
|
|
const struct drgn_object *task_obj)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
char regs[312];
|
|
|
|
err = drgn_program_read_memory(prog, regs, ksp + STACK_FRAME_OVERHEAD,
|
|
|
|
sizeof(regs), false);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
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
|
|
|
err = set_initial_registers_from_struct_ppc64(prog, thread, regs,
|
|
|
|
sizeof(regs), false,
|
|
|
|
true);
|
2020-11-27 12:06:56 +00:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* r1 */
|
|
|
|
Dwarf_Word dwarf_reg = ksp + SWITCH_FRAME_SIZE;
|
|
|
|
if (!dwfl_thread_state_registers(thread, 1, 1, &dwarf_reg)) {
|
|
|
|
err = drgn_error_libdwfl();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = NULL;
|
|
|
|
out:
|
|
|
|
drgn_object_deinit(&sp_obj);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct drgn_architecture_info arch_info_ppc64 = {
|
|
|
|
ARCHITECTURE_INFO,
|
|
|
|
.default_flags = (DRGN_PLATFORM_IS_64_BIT |
|
|
|
|
DRGN_PLATFORM_IS_LITTLE_ENDIAN),
|
|
|
|
.pt_regs_set_initial_registers = pt_regs_set_initial_registers_ppc64,
|
|
|
|
.prstatus_set_initial_registers = prstatus_set_initial_registers_ppc64,
|
|
|
|
.linux_kernel_set_initial_registers =
|
|
|
|
linux_kernel_set_initial_registers_ppc64,
|
|
|
|
};
|