1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26 /*
27 * Copyright (c) 2018, Joyent, Inc. All rights reserved.
28 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
29 * Copyright (c) 2013 by Delphix. All rights reserved.
30 * Copyright 2025 Oxide Computer Company
31 */
32
33 #include <sys/types.h>
34 #include <sys/reg.h>
35 #include <sys/privregs.h>
36 #include <sys/stack.h>
37 #include <sys/frame.h>
38
39 #include <mdb/mdb_target_impl.h>
40 #include <mdb/mdb_kreg_impl.h>
41 #include <mdb/mdb_debug.h>
42 #include <mdb/mdb_modapi.h>
43 #include <mdb/mdb_stack.h>
44 #include <mdb/mdb_isautil.h>
45 #include <mdb/mdb_amd64util.h>
46 #include <mdb/mdb_ctf.h>
47 #include <mdb/mdb_err.h>
48 #include <mdb/mdb.h>
49
50 #include <saveargs.h>
51
52 /*
53 * This array is used by the getareg and putareg entry points, and also by our
54 * register variable discipline.
55 */
56
57 const mdb_tgt_regdesc_t mdb_amd64_kregs[] = {
58 { "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT },
59 { "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT },
60 { "rdi", KREG_RDI, MDB_TGT_R_EXPORT },
61 { "edi", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
62 { "di", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
63 { "dil", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
64 { "rsi", KREG_RSI, MDB_TGT_R_EXPORT },
65 { "esi", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
66 { "si", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
67 { "sil", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
68 { "rdx", KREG_RDX, MDB_TGT_R_EXPORT },
69 { "edx", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
70 { "dx", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
71 { "dh", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
72 { "dl", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
73 { "rcx", KREG_RCX, MDB_TGT_R_EXPORT },
74 { "ecx", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
75 { "cx", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
76 { "ch", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
77 { "cl", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
78 { "r8", KREG_R8, MDB_TGT_R_EXPORT },
79 { "r8d", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
80 { "r8w", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
81 { "r8l", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
82 { "r9", KREG_R9, MDB_TGT_R_EXPORT },
83 { "r9d", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
84 { "r9w", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
85 { "r9l", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
86 { "rax", KREG_RAX, MDB_TGT_R_EXPORT },
87 { "eax", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
88 { "ax", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
89 { "ah", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
90 { "al", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
91 { "rbx", KREG_RBX, MDB_TGT_R_EXPORT },
92 { "ebx", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
93 { "bx", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
94 { "bh", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
95 { "bl", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
96 { "rbp", KREG_RBP, MDB_TGT_R_EXPORT },
97 { "ebp", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
98 { "bp", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
99 { "bpl", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
100 { "r10", KREG_R10, MDB_TGT_R_EXPORT },
101 { "r10d", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
102 { "r10w", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
103 { "r10l", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
104 { "r11", KREG_R11, MDB_TGT_R_EXPORT },
105 { "r11d", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
106 { "r11w", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
107 { "r11l", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
108 { "r12", KREG_R12, MDB_TGT_R_EXPORT },
109 { "r12d", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
110 { "r12w", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
111 { "r12l", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
112 { "r13", KREG_R13, MDB_TGT_R_EXPORT },
113 { "r13d", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
114 { "r13w", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
115 { "r13l", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
116 { "r14", KREG_R14, MDB_TGT_R_EXPORT },
117 { "r14d", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
118 { "r14w", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
119 { "r14l", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
120 { "r15", KREG_R15, MDB_TGT_R_EXPORT },
121 { "r15d", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
122 { "r15w", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
123 { "r15l", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
124 { "ds", KREG_DS, MDB_TGT_R_EXPORT },
125 { "es", KREG_ES, MDB_TGT_R_EXPORT },
126 { "fs", KREG_FS, MDB_TGT_R_EXPORT },
127 { "gs", KREG_GS, MDB_TGT_R_EXPORT },
128 { "trapno", KREG_TRAPNO, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
129 { "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
130 { "rip", KREG_RIP, MDB_TGT_R_EXPORT },
131 { "cs", KREG_CS, MDB_TGT_R_EXPORT },
132 { "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT },
133 { "eflags", KREG_RFLAGS, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
134 { "rsp", KREG_RSP, MDB_TGT_R_EXPORT },
135 { "esp", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
136 { "sp", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
137 { "spl", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
138 { "ss", KREG_SS, MDB_TGT_R_EXPORT },
139 { "gsbase", KREG_GSBASE, MDB_TGT_R_EXPORT },
140 { "kgsbase", KREG_KGSBASE, MDB_TGT_R_EXPORT },
141 { "cr2", KREG_CR2, MDB_TGT_R_EXPORT },
142 { "cr3", KREG_CR3, MDB_TGT_R_EXPORT },
143 { NULL, 0, 0 }
144 };
145
146 void
mdb_amd64_printregs(const mdb_tgt_gregset_t * gregs)147 mdb_amd64_printregs(const mdb_tgt_gregset_t *gregs)
148 {
149 const kreg_t *kregs = &gregs->kregs[0];
150 kreg_t rflags = kregs[KREG_RFLAGS];
151
152 #define GETREG2(x) ((uintptr_t)kregs[(x)]), ((uintptr_t)kregs[(x)])
153
154 mdb_printf("%%rax = 0x%0?p %15A %%r9 = 0x%0?p %A\n",
155 GETREG2(KREG_RAX), GETREG2(KREG_R9));
156 mdb_printf("%%rbx = 0x%0?p %15A %%r10 = 0x%0?p %A\n",
157 GETREG2(KREG_RBX), GETREG2(KREG_R10));
158 mdb_printf("%%rcx = 0x%0?p %15A %%r11 = 0x%0?p %A\n",
159 GETREG2(KREG_RCX), GETREG2(KREG_R11));
160 mdb_printf("%%rdx = 0x%0?p %15A %%r12 = 0x%0?p %A\n",
161 GETREG2(KREG_RDX), GETREG2(KREG_R12));
162 mdb_printf("%%rsi = 0x%0?p %15A %%r13 = 0x%0?p %A\n",
163 GETREG2(KREG_RSI), GETREG2(KREG_R13));
164 mdb_printf("%%rdi = 0x%0?p %15A %%r14 = 0x%0?p %A\n",
165 GETREG2(KREG_RDI), GETREG2(KREG_R14));
166 mdb_printf("%%r8 = 0x%0?p %15A %%r15 = 0x%0?p %A\n\n",
167 GETREG2(KREG_R8), GETREG2(KREG_R15));
168
169 mdb_printf("%%rip = 0x%0?p %A\n", GETREG2(KREG_RIP));
170 mdb_printf("%%rbp = 0x%0?p\n", kregs[KREG_RBP]);
171 mdb_printf("%%rsp = 0x%0?p\n", kregs[KREG_RSP]);
172
173 mdb_printf("%%rflags = 0x%08x\n", rflags);
174
175 mdb_printf(" id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
176 (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT,
177 (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT,
178 (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT,
179 (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT,
180 (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT,
181 (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT,
182 (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT,
183 (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT);
184
185 mdb_printf(" status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n",
186 (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of",
187 (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df",
188 (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if",
189 (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf",
190 (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf",
191 (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf",
192 (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af",
193 (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf",
194 (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf");
195
196 mdb_printf("%%cs = 0x%04x\t%%ds = 0x%04x\t"
197 "%%es = 0x%04x\t%%fs = 0x%04x\n", kregs[KREG_CS], kregs[KREG_DS],
198 kregs[KREG_ES], kregs[KREG_FS] & 0xffff);
199 mdb_printf("%%gs = 0x%04x\t%%gsbase = 0x%lx\t%%kgsbase = 0x%lx\n",
200 kregs[KREG_GS] & 0xffff, kregs[KREG_GSBASE], kregs[KREG_KGSBASE]);
201 mdb_printf("%%trapno = 0x%x\t%%err = 0x%x\t%%cr2 = 0x%lx\t"
202 "%%cr3 = 0x%lx\n", kregs[KREG_TRAPNO], kregs[KREG_ERR],
203 kregs[KREG_CR2], kregs[KREG_CR3]);
204 }
205
206 int
mdb_amd64_kvm_stack_iter(mdb_tgt_t * t,const mdb_tgt_gregset_t * gsp,mdb_tgt_stack_f * func,void * arg)207 mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
208 mdb_tgt_stack_f *func, void *arg)
209 {
210 mdb_tgt_gregset_t gregs;
211 kreg_t *kregs = &gregs.kregs[0];
212 int got_pc = (gsp->kregs[KREG_RIP] != 0);
213 uint_t argc, reg_argc;
214 long fr_argv[32];
215 int start_index; /* index to save_instr where to start comparison */
216 int err;
217 int i;
218
219 struct fr {
220 uintptr_t fr_savfp;
221 uintptr_t fr_savpc;
222 } fr;
223
224 uintptr_t fp = gsp->kregs[KREG_RBP];
225 uintptr_t pc = gsp->kregs[KREG_RIP];
226 uintptr_t lastfp = 0;
227
228 ssize_t size;
229 ssize_t insnsize;
230 uint8_t ins[SAVEARGS_INSN_SEQ_LEN];
231
232 GElf_Sym s;
233 mdb_syminfo_t sip;
234 mdb_ctf_funcinfo_t mfp;
235 int xpv_panic = 0;
236 int advance_tortoise = 1;
237 uintptr_t tortoise_fp = 0;
238 #ifndef _KMDB
239 int xp;
240
241 if ((mdb_readsym(&xp, sizeof (xp), "xpv_panicking") != -1) && (xp > 0))
242 xpv_panic = 1;
243 #endif
244
245 bcopy(gsp, &gregs, sizeof (gregs));
246
247 while (fp != 0) {
248 int args_style = 0;
249
250 if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &fr, sizeof (fr), fp) !=
251 sizeof (fr)) {
252 err = EMDB_NOMAP;
253 goto badfp;
254 }
255
256 if (tortoise_fp == 0) {
257 tortoise_fp = fp;
258 } else {
259 /*
260 * Advance tortoise_fp every other frame, so we detect
261 * cycles with Floyd's tortoise/hare.
262 */
263 if (advance_tortoise != 0) {
264 struct fr tfr;
265
266 if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &tfr,
267 sizeof (tfr), tortoise_fp) !=
268 sizeof (tfr)) {
269 err = EMDB_NOMAP;
270 goto badfp;
271 }
272
273 tortoise_fp = tfr.fr_savfp;
274 }
275
276 if (fp == tortoise_fp) {
277 err = EMDB_STKFRAME;
278 goto badfp;
279 }
280 }
281
282 advance_tortoise = !advance_tortoise;
283
284 if ((mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
285 NULL, 0, &s, &sip) == 0) &&
286 (mdb_ctf_func_info(&s, &sip, &mfp) == 0)) {
287 int return_type = mdb_ctf_type_kind(mfp.mtf_return);
288 mdb_ctf_id_t args_types[5];
289
290 argc = mfp.mtf_argc;
291
292 /*
293 * If the function returns a structure or union
294 * greater than 16 bytes in size %rdi contains the
295 * address in which to store the return value rather
296 * than for an argument.
297 */
298 if ((return_type == CTF_K_STRUCT ||
299 return_type == CTF_K_UNION) &&
300 mdb_ctf_type_size(mfp.mtf_return) > 16)
301 start_index = 1;
302 else
303 start_index = 0;
304
305 /*
306 * If any of the first 5 arguments are a structure
307 * less than 16 bytes in size, it will be passed
308 * spread across two argument registers, and we will
309 * not cope.
310 */
311 if (mdb_ctf_func_args(&mfp, 5, args_types) == CTF_ERR)
312 argc = 0;
313
314 for (i = 0; i < MIN(5, argc); i++) {
315 int t = mdb_ctf_type_kind(args_types[i]);
316
317 if (((t == CTF_K_STRUCT) ||
318 (t == CTF_K_UNION)) &&
319 mdb_ctf_type_size(args_types[i]) <= 16) {
320 argc = 0;
321 break;
322 }
323 }
324 } else {
325 argc = 0;
326 }
327
328 /*
329 * The number of instructions to search for argument saving is
330 * limited such that only instructions prior to %pc are
331 * considered such that we never read arguments from a
332 * function where the saving code has not in fact yet
333 * executed.
334 */
335 insnsize = MIN(MIN(s.st_size, SAVEARGS_INSN_SEQ_LEN),
336 pc - s.st_value);
337
338 if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, ins, insnsize,
339 s.st_value) != insnsize)
340 argc = 0;
341
342 if ((argc != 0) &&
343 ((args_style = saveargs_has_args(ins, insnsize, argc,
344 start_index)) != SAVEARGS_NO_ARGS)) {
345 /* Up to 6 arguments are passed via registers */
346 reg_argc = MIN((6 - start_index), mfp.mtf_argc);
347 size = reg_argc * sizeof (long);
348
349 /*
350 * If Studio pushed a structure return address as an
351 * argument, we need to read one more argument than
352 * actually exists (the addr) to make everything line
353 * up.
354 */
355 if (args_style == SAVEARGS_STRUCT_ARGS)
356 size += sizeof (long);
357
358 if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, fr_argv, size,
359 (fp - size)) != size)
360 return (-1); /* errno has been set for us */
361
362 /*
363 * Arrange the arguments in the right order for
364 * printing.
365 */
366 for (i = 0; i < (reg_argc / 2); i++) {
367 long t = fr_argv[i];
368
369 fr_argv[i] = fr_argv[reg_argc - i - 1];
370 fr_argv[reg_argc - i - 1] = t;
371 }
372
373 if (argc > reg_argc) {
374 size = MIN((argc - reg_argc) * sizeof (long),
375 sizeof (fr_argv) -
376 (reg_argc * sizeof (long)));
377
378 if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S,
379 &fr_argv[reg_argc], size,
380 fp + sizeof (fr)) != size)
381 return (-1); /* errno has been set */
382 }
383 } else {
384 argc = 0;
385 }
386
387 if (got_pc && func(arg, pc, argc, fr_argv, &gregs) != 0)
388 break;
389
390 kregs[KREG_RSP] = kregs[KREG_RBP];
391
392 lastfp = fp;
393 fp = fr.fr_savfp;
394 /*
395 * The Xen hypervisor marks a stack frame as belonging to
396 * an exception by inverting the bits of the pointer to
397 * that frame. We attempt to identify these frames by
398 * inverting the pointer and seeing if it is within 0xfff
399 * bytes of the last frame.
400 */
401 if (xpv_panic)
402 if ((fp != 0) && (fp < lastfp) &&
403 ((lastfp ^ ~fp) < 0xfff))
404 fp = ~fp;
405
406 kregs[KREG_RBP] = fp;
407 kregs[KREG_RIP] = pc = fr.fr_savpc;
408
409 got_pc = (pc != 0);
410 }
411
412 return (0);
413
414 badfp:
415 mdb_printf("%p [%s]", fp, mdb_strerror(err));
416 return (set_errno(err));
417 }
418
419 /*
420 * Determine the return address for the current frame. Typically this is the
421 * fr_savpc value from the current frame, but we also perform some special
422 * handling to see if we are stopped on one of the first two instructions of
423 * a typical function prologue, in which case %rbp will not be set up yet.
424 */
425 int
mdb_amd64_step_out(mdb_tgt_t * t,uintptr_t * p,kreg_t pc,kreg_t fp,kreg_t sp,mdb_instr_t curinstr)426 mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
427 mdb_instr_t curinstr)
428 {
429 struct frame fr;
430 GElf_Sym s;
431 char buf[1];
432
433 enum {
434 M_PUSHQ_RBP = 0x55, /* pushq %rbp */
435 M_REX_W = 0x48, /* REX prefix with only W set */
436 M_MOVL_RBP = 0x8b /* movq %rsp, %rbp with prefix */
437 };
438
439 if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
440 buf, 0, &s, NULL) == 0) {
441 if (pc == s.st_value && curinstr == M_PUSHQ_RBP)
442 fp = sp - 8;
443 else if (pc == s.st_value + 1 && curinstr == M_REX_W) {
444 if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &curinstr,
445 sizeof (curinstr), pc + 1) == sizeof (curinstr) &&
446 curinstr == M_MOVL_RBP)
447 fp = sp;
448 }
449 }
450
451 if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &fr, sizeof (fr), fp) ==
452 sizeof (fr)) {
453 *p = fr.fr_savpc;
454 return (0);
455 }
456
457 return (-1); /* errno is set for us */
458 }
459
460 /*ARGSUSED*/
461 int
mdb_amd64_next(mdb_tgt_t * t,uintptr_t * p,kreg_t pc,mdb_instr_t curinstr)462 mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
463 {
464 mdb_tgt_addr_t npc;
465 mdb_tgt_addr_t callpc;
466
467 enum {
468 M_CALL_REL = 0xe8, /* call near with relative displacement */
469 M_CALL_REG = 0xff, /* call near indirect or call far register */
470
471 M_REX_LO = 0x40,
472 M_REX_HI = 0x4f
473 };
474
475 /*
476 * If the opcode is a near call with relative displacement, assume the
477 * displacement is a rel32 from the next instruction.
478 */
479 if (curinstr == M_CALL_REL) {
480 *p = pc + sizeof (mdb_instr_t) + sizeof (uint32_t);
481 return (0);
482 }
483
484 /* Skip the rex prefix, if any */
485 callpc = pc;
486 while (curinstr >= M_REX_LO && curinstr <= M_REX_HI) {
487 if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &curinstr,
488 sizeof (curinstr), ++callpc) != sizeof (curinstr))
489 return (-1); /* errno is set for us */
490 }
491
492 if (curinstr != M_CALL_REG) {
493 /* It's not a call */
494 return (set_errno(EAGAIN));
495 }
496
497 npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT_I, pc);
498 if (npc == pc)
499 return (-1); /* errno is set for us */
500
501 *p = npc;
502 return (0);
503 }
504
505 int
mdb_amd64_kvm_frame(void * argp,uintptr_t pc,uint_t argc,const long * argv,const mdb_tgt_gregset_t * gregs)506 mdb_amd64_kvm_frame(void *argp, uintptr_t pc, uint_t argc, const long *argv,
507 const mdb_tgt_gregset_t *gregs)
508 {
509 mdb_stack_frame_hdl_t *hdl = argp;
510 uint64_t bp;
511
512 bp = gregs->kregs[KREG_RBP];
513 mdb_stack_frame(hdl, pc, bp, argc, argv);
514 return (0);
515 }
516
517 /*
518 * Check if the instruction immediately before the given program counter (pcp)
519 * is a CALL instruction on AMD64. Since x86-64 instructions are
520 * variable-length, we read the 8 bytes preceding the PC and look for specific
521 * call encodings at known offsets that would align with common call
522 * instruction lengths. Although x86 instructions can be up to 15 bytes long,
523 * for a CALL to reach that length would require a long sequence of prefixes.
524 * Of those, only the address-size prefix would affect where we need to look
525 * for the instruction, and such prefixes are extremely rare in real-world
526 * code.
527 */
528 boolean_t
mdb_amd64_prev_callcheck(uintptr_t pcp)529 mdb_amd64_prev_callcheck(uintptr_t pcp)
530 {
531 uint8_t buf[8];
532
533 /*
534 * Ensure we can read 8 bytes before the PC. This accommodates the
535 * largest call encoding we care about (far calls).
536 */
537 if (pcp < 8 || mdb_vread(buf, sizeof (buf), pcp - 8) != sizeof (buf))
538 return (B_FALSE);
539
540 /*
541 * Direct near call: CALL rel32
542 * Opcode: E8, followed by 4-byte PC-relative offset.
543 * Instruction is 5 bytes long; opcode is at buf[3].
544 */
545 if (buf[3] == 0xe8)
546 return (B_TRUE);
547
548 /*
549 * Indirect near call: CALL r/m64
550 * Opcode: FF /2 (i.e., reg field of ModR/M is 010).
551 *
552 * We're expecting the instruction to be exactly 2 bytes: FF 14,
553 * with opcode at buf[5] and ModR/M at buf[6].
554 *
555 * buf[6] == 0x14 means:
556 * - mod = 00 (no displacement)
557 * - reg = 010 (CALL)
558 * - r/m = 100 (SIB follows — typically [rsp])
559 *
560 * This form is common in PLT stubs like: CALL QWORD PTR [RSP]
561 *
562 * Other encodings of FF /2 are less plausible here:
563 * - mod = 01 - 8-bit displacement - unlikely for noreturn functions
564 * - mod = 10 - 32-bit displacement - would overlap with PC; invalid
565 * - mod = 00 with r/m != 100 - e.g., CALL RAX - would return to
566 * buf[7], not pcp
567 */
568 if (buf[5] == 0xff && buf[6] == 0x14)
569 return (B_TRUE);
570
571 /*
572 * Indirect RIP-relative call: CALL QWORD PTR [RIP + disp32]
573 * Encoding: FF 15 xx xx xx xx
574 * Instruction is 6 bytes long; opcode at buf[2], ModR/M at buf[3].
575 * Common in PLT thunks and PIC code.
576 */
577 if (buf[2] == 0xff && buf[3] == 0x15)
578 return (B_TRUE);
579
580 /*
581 * Far call (segment-based): CALL FAR ptr16:32
582 * Opcode: 9A, followed by 6-byte far pointer.
583 * Rare in modern 64-bit code but still valid.
584 * Instruction is 7 bytes; opcode at buf[0].
585 */
586 if (buf[0] == 0x9a)
587 return (B_TRUE);
588
589 return (B_FALSE);
590 }
591