libdrgn: support getting register values from stack frames

Currently, the only information available from a stack frame is the
program counter. Eventually, we'd like to add support for getting
arguments and local variables, but that will require more work. In the
mean time, we can at least get the values of other registers. A
determined user can read the assembly for the code they're debugging and
derive the values of variables from the registers.
This commit is contained in:
Omar Sandoval 2019-10-18 02:42:51 -07:00
parent 4fb0e2e110
commit 0da60a41cd
5 changed files with 135 additions and 0 deletions

View File

@ -879,6 +879,23 @@ Stack Traces
:rtype: Symbol
.. method:: register(reg)
Get the value of the given register at this stack frame. The register
can be specified by name (e.g., ``'rax'``), number (see
:attr:`RegisterInfo.number`), or as a :class:`RegisterInfo`.
:param reg: Register to get.
:type reg: str, int, or RegisterInfo
:rtype: int
.. method:: registers()
Get the values of all available registers at this stack frame as a
dictionary with the register names as keys.
:rtype: dict[str, int]
.. _api-reference-types:
Types

View File

@ -2300,6 +2300,16 @@ uint64_t drgn_stack_frame_pc(struct drgn_stack_frame frame);
struct drgn_error *drgn_stack_frame_symbol(struct drgn_stack_frame frame,
struct drgn_symbol **ret);
/** Get the value of a register (by number) in a stack frame. */
struct drgn_error *drgn_stack_frame_register(struct drgn_stack_frame frame,
enum drgn_register_number regno,
uint64_t *ret);
/** Get the value of a register (by name) in a stack frame. */
struct drgn_error *
drgn_stack_frame_register_by_name(struct drgn_stack_frame frame,
const char *name, uint64_t *ret);
/**
* Get a stack trace for the thread represented by @p obj.
*

View File

@ -24,6 +24,15 @@ struct drgn_architecture_info {
struct drgn_object *);
};
static inline const struct drgn_register *
drgn_architecture_register_by_name(const struct drgn_architecture_info *arch,
const char *name)
{
if (!arch->register_by_name)
return NULL;
return arch->register_by_name(name);
}
extern const struct drgn_architecture_info arch_info_unknown;
extern const struct drgn_architecture_info arch_info_x86_64;

View File

@ -103,6 +103,72 @@ static PyObject *StackFrame_symbol(StackFrame *self)
return ret;
}
static PyObject *StackFrame_register(StackFrame *self, PyObject *arg)
{
struct drgn_error *err;
uint64_t value;
if (PyUnicode_Check(arg)) {
err = drgn_stack_frame_register_by_name(self->frame,
PyUnicode_AsUTF8(arg),
&value);
} else {
struct index_arg number = {};
if (PyObject_TypeCheck(arg, &Register_type))
arg = PyStructSequence_GET_ITEM(arg, 1);
if (!index_converter(arg, &number))
return NULL;
err = drgn_stack_frame_register(self->frame, number.value,
&value);
}
if (err)
return set_drgn_error(err);
return PyLong_FromUnsignedLongLong(value);
}
static PyObject *StackFrame_registers(StackFrame *self)
{
struct drgn_error *err;
PyObject *dict;
const struct drgn_platform *platform;
size_t num_registers, i;
dict = PyDict_New();
if (!dict)
return NULL;
platform = drgn_program_platform(&self->trace->prog->prog);
num_registers = drgn_platform_num_registers(platform);
for (i = 0; i < num_registers; i++) {
const struct drgn_register *reg;
uint64_t value;
PyObject *value_obj;
int ret;
reg = drgn_platform_register(platform, i);
err = drgn_stack_frame_register(self->frame,
drgn_register_number(reg),
&value);
if (err) {
drgn_error_destroy(err);
continue;
}
value_obj = PyLong_FromUnsignedLongLong(value);
if (!value_obj) {
Py_DECREF(dict);
return NULL;
}
ret = PyDict_SetItemString(dict, drgn_register_name(reg),
value_obj);
Py_DECREF(value_obj);
if (ret == -1) {
Py_DECREF(dict);
return NULL;
}
}
return dict;
}
static PyObject *StackFrame_get_pc(StackFrame *self, void *arg)
{
return PyLong_FromUnsignedLongLong(drgn_stack_frame_pc(self->frame));
@ -111,6 +177,10 @@ static PyObject *StackFrame_get_pc(StackFrame *self, void *arg)
static PyMethodDef StackFrame_methods[] = {
{"symbol", (PyCFunction)StackFrame_symbol, METH_NOARGS,
drgn_StackFrame_symbol_DOC},
{"register", (PyCFunction)StackFrame_register,
METH_O, drgn_StackFrame_register_DOC},
{"registers", (PyCFunction)StackFrame_registers,
METH_NOARGS, drgn_StackFrame_registers_DOC},
{},
};

View File

@ -1,6 +1,7 @@
// Copyright 2019 - Omar Sandoval
// SPDX-License-Identifier: GPL-3.0+
#include <dwarf.h>
#include <elfutils/libdwfl.h>
#include <endian.h>
#include <inttypes.h>
@ -110,6 +111,34 @@ drgn_stack_frame_symbol(struct drgn_stack_frame frame, struct drgn_symbol **ret)
ret);
}
LIBDRGN_PUBLIC struct drgn_error *
drgn_stack_frame_register(struct drgn_stack_frame frame,
enum drgn_register_number regno, uint64_t *ret)
{
const Dwarf_Op op = { .atom = DW_OP_regx, .number = regno, };
Dwarf_Addr value;
if (!dwfl_frame_eval_expr(frame.trace->frames[frame.i], &op, 1, &value))
return drgn_error_libdwfl();
*ret = value;
return NULL;
}
LIBDRGN_PUBLIC struct drgn_error *
drgn_stack_frame_register_by_name(struct drgn_stack_frame frame,
const char *name, uint64_t *ret)
{
const struct drgn_register *reg;
reg = drgn_architecture_register_by_name(frame.trace->prog->platform.arch,
name);
if (!reg) {
return drgn_error_format(DRGN_ERROR_LOOKUP,
"unknown register '%s'", name);
}
return drgn_stack_frame_register(frame, reg->number, ret);
}
static bool drgn_thread_memory_read(Dwfl *dwfl, Dwarf_Addr addr,
Dwarf_Word *result, void *dwfl_arg)
{