@@ -107,25 +107,76 @@ bnd2
107107bnd3
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(®, (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
130181static inline struct drgn_error *read_register(struct drgn_object *reg_obj,
131182 struct drgn_object *frame_obj,
206257
207258static struct drgn_error *
208259linux_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