Skip to content

Commit e50c70f

Browse files
author
Delphix Engineering
committed
Merge branch 'refs/heads/upstream-HEAD' into repo-HEAD
2 parents 21b470b + a227d0d commit e50c70f

30 files changed

+936
-828
lines changed

libdrgn/arch_x86_64.c.in

Lines changed: 113 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -107,25 +107,76 @@ bnd2
107107
bnd3
108108
%%
109109

110-
static const struct drgn_frame_register frame_registers_x86_64[] = {
111-
{ DRGN_REGISTER_X86_64_rax, 8, 192, "ax", "rax", },
112-
{ DRGN_REGISTER_X86_64_rdx, 8, 208, "dx", "rdx", },
113-
{ DRGN_REGISTER_X86_64_rcx, 8, 200, "cx", "rcx", },
114-
{ DRGN_REGISTER_X86_64_rbx, 8, 152, "bx", "rbx", },
115-
{ DRGN_REGISTER_X86_64_rsi, 8, 216, "si", "rsi", },
116-
{ DRGN_REGISTER_X86_64_rdi, 8, 224, "di", "rdi", },
117-
{ DRGN_REGISTER_X86_64_rbp, 8, 144, "bp", "rbp", },
118-
{ DRGN_REGISTER_X86_64_rsp, 8, 264, "sp", "rsp", },
119-
{ DRGN_REGISTER_X86_64_r8, 8, 184, "r8", },
120-
{ DRGN_REGISTER_X86_64_r9, 8, 176, "r9", },
121-
{ DRGN_REGISTER_X86_64_r10, 8, 168, "r10", },
122-
{ DRGN_REGISTER_X86_64_r11, 8, 160, "r11", },
123-
{ DRGN_REGISTER_X86_64_r12, 8, 136, "r12", },
124-
{ DRGN_REGISTER_X86_64_r13, 8, 128, "r13", },
125-
{ DRGN_REGISTER_X86_64_r14, 8, 120, "r14", },
126-
{ DRGN_REGISTER_X86_64_r15, 8, 112, "r15", },
127-
{ DRGN_REGISTER_X86_64_rip, 8, 240, "ip", "rip", },
128-
};
110+
/*
111+
* The in-kernel struct pt_regs, UAPI struct pt_regs, elf_gregset_t, and struct
112+
* user_regs_struct all have the same layout.
113+
*/
114+
static struct drgn_error *
115+
set_initial_registers_from_struct_x86_64(Dwfl_Thread *thread, const void *regs,
116+
size_t size, bool bswap)
117+
{
118+
Dwarf_Word dwarf_regs[17];
119+
120+
if (size < 160) {
121+
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
122+
"registers are truncated");
123+
}
124+
125+
#define READ_REGISTER(n) ({ \
126+
uint64_t reg; \
127+
memcpy(&reg, (uint64_t *)regs + n, sizeof(reg)); \
128+
bswap ? bswap_64(reg) : reg; \
129+
})
130+
dwarf_regs[0] = READ_REGISTER(10); /* rax */
131+
dwarf_regs[1] = READ_REGISTER(12); /* rdx */
132+
dwarf_regs[2] = READ_REGISTER(11); /* rcx */
133+
dwarf_regs[3] = READ_REGISTER(5); /* rbx */
134+
dwarf_regs[4] = READ_REGISTER(13); /* rsi */
135+
dwarf_regs[5] = READ_REGISTER(14); /* rdi */
136+
dwarf_regs[6] = READ_REGISTER(4); /* rbp */
137+
dwarf_regs[7] = READ_REGISTER(19); /* rsp */
138+
dwarf_regs[8] = READ_REGISTER(9); /* r8 */
139+
dwarf_regs[9] = READ_REGISTER(8); /* r9 */
140+
dwarf_regs[10] = READ_REGISTER(7); /* r10 */
141+
dwarf_regs[11] = READ_REGISTER(6); /* r11 */
142+
dwarf_regs[12] = READ_REGISTER(3); /* r12 */
143+
dwarf_regs[13] = READ_REGISTER(2); /* r13 */
144+
dwarf_regs[14] = READ_REGISTER(1); /* r14 */
145+
dwarf_regs[15] = READ_REGISTER(0); /* r15 */
146+
dwarf_regs[16] = READ_REGISTER(16); /* rip */
147+
#undef READ_REGISTER
148+
149+
if (!dwfl_thread_state_registers(thread, 0, 17, dwarf_regs))
150+
return drgn_error_libdwfl();
151+
return NULL;
152+
}
153+
154+
static struct drgn_error *
155+
pt_regs_set_initial_registers_x86_64(Dwfl_Thread *thread,
156+
const struct drgn_object *obj)
157+
{
158+
bool bswap = (obj->value.little_endian !=
159+
(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__));
160+
return set_initial_registers_from_struct_x86_64(thread,
161+
drgn_object_buffer(obj),
162+
drgn_buffer_object_size(obj),
163+
bswap);
164+
}
165+
166+
static struct drgn_error *
167+
prstatus_set_initial_registers_x86_64(struct drgn_program *prog,
168+
Dwfl_Thread *thread, const void *prstatus,
169+
size_t size)
170+
{
171+
if (size < 112) {
172+
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
173+
"NT_PRSTATUS is truncated");
174+
}
175+
return set_initial_registers_from_struct_x86_64(thread,
176+
(char *)prstatus + 112,
177+
size - 112,
178+
drgn_program_bswap(prog));
179+
}
129180

130181
static inline struct drgn_error *read_register(struct drgn_object *reg_obj,
131182
struct drgn_object *frame_obj,
@@ -206,7 +257,9 @@ out:
206257

207258
static struct drgn_error *
208259
linux_kernel_set_initial_registers_x86_64(Dwfl_Thread *thread,
209-
const struct drgn_object *task_obj)
260+
const struct drgn_object *task_obj,
261+
const void *prstatus,
262+
size_t prstatus_size)
210263
{
211264
struct drgn_error *err;
212265
struct drgn_program *prog = task_obj->prog;
@@ -217,8 +270,44 @@ linux_kernel_set_initial_registers_x86_64(Dwfl_Thread *thread,
217270

218271
drgn_object_init(&sp_obj, prog);
219272

220-
/*
221-
*/
273+
if (prstatus) {
274+
/*
275+
* If the stack pointer in PRSTATUS is within this task's stack,
276+
* then we can use it. Otherwise, the task either wasn't running
277+
* or was in the middle of context switching. Either way, we
278+
* should use the saved registers instead.
279+
*/
280+
uint64_t thread_size;
281+
uint64_t stack;
282+
283+
err = linux_kernel_get_thread_size(prog, &thread_size);
284+
if (err)
285+
goto out;
286+
err = drgn_object_member_dereference(&sp_obj, task_obj,
287+
"stack");
288+
if (err)
289+
goto out;
290+
err = drgn_object_read_unsigned(&sp_obj, &stack);
291+
if (err)
292+
goto out;
293+
294+
if (prstatus_size < 272) {
295+
err = drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
296+
"registers are truncated");
297+
goto out;
298+
}
299+
memcpy(&sp, (char *)prstatus + 264, sizeof(sp));
300+
if (drgn_program_bswap(prog))
301+
sp = bswap_64(sp);
302+
if (sp > stack && sp <= stack + thread_size) {
303+
err = prstatus_set_initial_registers_x86_64(prog,
304+
thread,
305+
prstatus,
306+
prstatus_size);
307+
goto out;
308+
}
309+
}
310+
222311
err = drgn_object_member_dereference(&sp_obj, task_obj, "thread");
223312
if (err)
224313
goto out;
@@ -485,8 +574,8 @@ const struct drgn_architecture_info arch_info_x86_64 = {
485574
ARCHITECTURE_INFO,
486575
.default_flags = (DRGN_PLATFORM_IS_64_BIT |
487576
DRGN_PLATFORM_IS_LITTLE_ENDIAN),
488-
.frame_registers = frame_registers_x86_64,
489-
.num_frame_registers = ARRAY_SIZE(frame_registers_x86_64),
577+
.pt_regs_set_initial_registers = pt_regs_set_initial_registers_x86_64,
578+
.prstatus_set_initial_registers = prstatus_set_initial_registers_x86_64,
490579
.linux_kernel_set_initial_registers =
491580
linux_kernel_set_initial_registers_x86_64,
492581
.linux_kernel_get_page_offset = linux_kernel_get_page_offset_x86_64,

0 commit comments

Comments
 (0)