xref: /illumos-gate/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/reg.h>
31 #include <sys/privregs.h>
32 #include <sys/stack.h>
33 #include <sys/frame.h>
34 
35 #include <mdb/mdb_target_impl.h>
36 #include <mdb/mdb_kreg_impl.h>
37 #include <mdb/mdb_debug.h>
38 #include <mdb/mdb_modapi.h>
39 #include <mdb/mdb_amd64util.h>
40 #include <mdb/mdb_ctf.h>
41 #include <mdb/mdb_err.h>
42 #include <mdb/mdb.h>
43 
44 /*
45  * This array is used by the getareg and putareg entry points, and also by our
46  * register variable discipline.
47  */
48 
49 const mdb_tgt_regdesc_t mdb_amd64_kregs[] = {
50 	{ "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT },
51 	{ "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT },
52 	{ "rdi", KREG_RDI, MDB_TGT_R_EXPORT },
53 	{ "rsi", KREG_RSI, MDB_TGT_R_EXPORT },
54 	{ "rdx", KREG_RDX, MDB_TGT_R_EXPORT },
55 	{ "rcx", KREG_RCX, MDB_TGT_R_EXPORT },
56 	{ "r8", KREG_R8, MDB_TGT_R_EXPORT },
57 	{ "r9", KREG_R9, MDB_TGT_R_EXPORT },
58 	{ "rax", KREG_RAX, MDB_TGT_R_EXPORT },
59 	{ "rbx", KREG_RBX, MDB_TGT_R_EXPORT },
60 	{ "rbp", KREG_RBP, MDB_TGT_R_EXPORT },
61 	{ "r10", KREG_R10, MDB_TGT_R_EXPORT },
62 	{ "r11", KREG_R11, MDB_TGT_R_EXPORT },
63 	{ "r12", KREG_R12, MDB_TGT_R_EXPORT },
64 	{ "r13", KREG_R13, MDB_TGT_R_EXPORT },
65 	{ "r14", KREG_R14, MDB_TGT_R_EXPORT },
66 	{ "r15", KREG_R15, MDB_TGT_R_EXPORT },
67 	{ "ds", KREG_DS, MDB_TGT_R_EXPORT },
68 	{ "es", KREG_ES, MDB_TGT_R_EXPORT },
69 	{ "fs", KREG_FS, MDB_TGT_R_EXPORT },
70 	{ "gs", KREG_GS, MDB_TGT_R_EXPORT },
71 	{ "trapno", KREG_TRAPNO, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
72 	{ "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
73 	{ "rip", KREG_RIP, MDB_TGT_R_EXPORT },
74 	{ "cs", KREG_CS, MDB_TGT_R_EXPORT },
75 	{ "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT },
76 	{ "rsp", KREG_RSP, MDB_TGT_R_EXPORT },
77 	{ "ss", KREG_SS, MDB_TGT_R_EXPORT },
78 	{ NULL, 0, 0 }
79 };
80 
81 void
82 mdb_amd64_printregs(const mdb_tgt_gregset_t *gregs)
83 {
84 	const kreg_t *kregs = &gregs->kregs[0];
85 	kreg_t rflags = kregs[KREG_RFLAGS];
86 
87 #define	GETREG2(x) ((uintptr_t)kregs[(x)]), ((uintptr_t)kregs[(x)])
88 
89 	mdb_printf("%%rax = 0x%0?p %15A %%r9  = 0x%0?p %A\n",
90 	    GETREG2(KREG_RAX), GETREG2(KREG_R9));
91 	mdb_printf("%%rbx = 0x%0?p %15A %%r10 = 0x%0?p %A\n",
92 	    GETREG2(KREG_RBX), GETREG2(KREG_R10));
93 	mdb_printf("%%rcx = 0x%0?p %15A %%r11 = 0x%0?p %A\n",
94 	    GETREG2(KREG_RCX), GETREG2(KREG_R11));
95 	mdb_printf("%%rdx = 0x%0?p %15A %%r12 = 0x%0?p %A\n",
96 	    GETREG2(KREG_RDX), GETREG2(KREG_R12));
97 	mdb_printf("%%rsi = 0x%0?p %15A %%r13 = 0x%0?p %A\n",
98 	    GETREG2(KREG_RSI), GETREG2(KREG_R13));
99 	mdb_printf("%%rdi = 0x%0?p %15A %%r14 = 0x%0?p %A\n",
100 	    GETREG2(KREG_RDI), GETREG2(KREG_R14));
101 	mdb_printf("%%r8  = 0x%0?p %15A %%r15 = 0x%0?p %A\n\n",
102 	    GETREG2(KREG_R8), GETREG2(KREG_R15));
103 
104 	mdb_printf("%%rip = 0x%0?p %A\n", GETREG2(KREG_RIP));
105 	mdb_printf("%%rbp = 0x%0?p\n", kregs[KREG_RBP]);
106 	mdb_printf("%%rsp = 0x%0?p\n", kregs[KREG_RSP]);
107 
108 	mdb_printf("%%rflags = 0x%08x\n", rflags);
109 
110 	mdb_printf("  id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
111 	    (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT,
112 	    (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT,
113 	    (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT,
114 	    (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT,
115 	    (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT,
116 	    (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT,
117 	    (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT,
118 	    (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT);
119 
120 	mdb_printf("  status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n",
121 	    (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of",
122 	    (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df",
123 	    (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if",
124 	    (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf",
125 	    (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf",
126 	    (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf",
127 	    (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af",
128 	    (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf",
129 	    (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf");
130 
131 	mdb_printf("%24s%%cs = 0x%04x\t%%ds = 0x%04x\t%%es = 0x%04x\n",
132 	    " ", kregs[KREG_CS], kregs[KREG_DS], kregs[KREG_ES]);
133 
134 	mdb_printf("%%trapno = 0x%x\t\t%%fs = 0x%04x\t%%gs = 0x%04x\n",
135 	    kregs[KREG_TRAPNO], (kregs[KREG_FS] & 0xffff),
136 	    (kregs[KREG_GS] & 0xffff));
137 	mdb_printf("   %%err = 0x%x\n", kregs[KREG_ERR]);
138 }
139 
140 /*
141  * Sun Studio 10 patch compiler and gcc 3.4.3 Sun branch implemented a
142  * "-save_args" option on amd64.  When the option is specified, INTEGER
143  * type function arguments passed via registers will be saved on the stack
144  * immediately after %rbp, and will not be modified through out the life
145  * of the routine.
146  *
147  *				+--------+
148  *		%rbp	-->     |  %rbp  |
149  *				+--------+
150  *		-0x8(%rbp)	|  %rdi  |
151  *				+--------+
152  *		-0x10(%rbp)	|  %rsi  |
153  *				+--------+
154  *		-0x18(%rbp)	|  %rdx  |
155  *				+--------+
156  *		-0x20(%rbp)	|  %rcx  |
157  *				+--------+
158  *		-0x28(%rbp)	|  %r8   |
159  *				+--------+
160  *		-0x30(%rbp)	|  %r9   |
161  *				+--------+
162  *
163  *
164  * For example, for the following function,
165  *
166  * void
167  * foo(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
168  * {
169  * ...
170  * }
171  *
172  * Disassembled code will look something like the following:
173  *
174  *     pushq	%rbp
175  *     movq	%rsp, %rbp
176  *     subq	$imm8, %rsp			**
177  *     movq	%rdi, -0x8(%rbp)
178  *     movq	%rsi, -0x10(%rbp)
179  *     movq	%rdx, -0x18(%rbp)
180  *     movq	%rcx, -0x20(%rbp)
181  *     movq	%r8, -0x28(%rbp)
182  *     movq	%r9, -0x30(%rbp)
183  *     ...
184  * or
185  *     pushq	%rbp
186  *     movq	%rsp, %rbp
187  *     subq	$imm8, %rsp			**
188  *     movq	%r9, -0x30(%rbp)
189  *     movq	%r8, -0x28(%rbp)
190  *     movq	%rcx, -0x20(%rbp)
191  *     movq	%rdx, -0x18(%rbp)
192  *     movq	%rsi, -0x10(%rbp)
193  *     movq	%rdi, -0x8(%rbp)
194  *     ...
195  *
196  * **: The space being reserved is in addition to what the current
197  *     function prolog already reserves.
198  *
199  * If there are odd number of arguments to a function, additional space is
200  * reserved on the stack to maintain 16-byte alignment.  For example,
201  *
202  *     argc == 0: no argument saving.
203  *     argc == 3: save 3, but space for 4 is reserved
204  *     argc == 7: save 6.
205  */
206 
207 /*
208  * The longest instruction sequence in bytes before all 6 arguments are
209  * saved on the stack.  This value depends on compiler implementation,
210  * therefore it should be examined periodically to guarantee accuracy.
211  */
212 #define	SEQ_LEN		80
213 
214 /*
215  * Size of the instruction sequence arrays.  It should correspond to
216  * the maximum number of arguments passed via registers.
217  */
218 #define	INSTR_ARRAY_SIZE	6
219 
220 #define	INSTR4(ins, off)	\
221 	(ins[(off)] + (ins[(off) + 1] << 8) + (ins[(off + 2)] << 16) + \
222 	(ins[(off) + 3] << 24))
223 
224 /*
225  * Sun Studio 10 patch implementation saves %rdi first;
226  * GCC 3.4.3 Sun branch implementation saves them in reverse order.
227  */
228 static const uint32_t save_instr[INSTR_ARRAY_SIZE] = {
229 	0xf87d8948,	/* movq %rdi, -0x8(%rbp) */
230 	0xf0758948,	/* movq %rsi, -0x10(%rbp) */
231 	0xe8558948,	/* movq %rdx, -0x18(%rbp) */
232 	0xe04d8948,	/* movq %rcx, -0x20(%rbp) */
233 	0xd845894c,	/* movq %r8, -0x28(%rbp) */
234 	0xd04d894c	/* movq %r9, -0x30(%rbp) */
235 };
236 
237 static const uint32_t save_fp_instr[] = {
238 	0xe5894855,	/* pushq %rbp; movq %rsp,%rbp, encoding 1 */
239 	0xec8b4855,	/* pushq %rbp; movq %rsp,%rbp, encoding 2 */
240 	0xe58948cc,	/* int $0x3; movq %rsp,%rbp, encoding 1 */
241 	0xec8b48cc,	/* int $0x3; movq %rsp,%rbp, encoding 2 */
242 	NULL
243 };
244 
245 /*
246  * Look for the above instruction sequences as indicators for register
247  * arguments being available on the stack.
248  */
249 static int
250 is_argsaved(mdb_tgt_t *t, uintptr_t fstart, uint64_t size, uint_t argc,
251     int start_index)
252 {
253 	uint8_t		ins[SEQ_LEN];
254 	int		i, j;
255 	uint32_t	n;
256 
257 	size = MIN(size, SEQ_LEN);
258 	argc = MIN((start_index + argc), INSTR_ARRAY_SIZE);
259 
260 	if (mdb_tgt_vread(t, ins, size, fstart) != size)
261 		return (0);
262 
263 	/*
264 	 * Make sure framepointer has been saved.
265 	 */
266 	n = INSTR4(ins, 0);
267 	for (i = 0; save_fp_instr[i] != NULL; i++) {
268 		if (n == save_fp_instr[i])
269 			break;
270 	}
271 
272 	if (save_fp_instr[i] == NULL)
273 		return (0);
274 
275 	/*
276 	 * Compare against Sun Studio implementation
277 	 */
278 	for (i = 8, j = start_index; i < size - 4; i++) {
279 		n = INSTR4(ins, i);
280 
281 		if (n == save_instr[j]) {
282 			i += 3;
283 			if (++j >= argc)
284 				return (1);
285 		}
286 	}
287 
288 	/*
289 	 * Compare against GCC implementation
290 	 */
291 	for (i = 8, j = argc - 1; i < size - 4; i++) {
292 		n = INSTR4(ins, i);
293 
294 		if (n == save_instr[j]) {
295 			i += 3;
296 			if (--j < start_index)
297 				return (1);
298 		}
299 	}
300 
301 	return (0);
302 }
303 
304 /*
305  * We expect all proper Solaris core files to have STACK_ALIGN-aligned stacks.
306  * Hence the name.  However, if the core file resulted from a
307  * hypervisor-initiated panic, the hypervisor's frames may only be 64-bit
308  * aligned instead of 128.
309  */
310 static int
311 fp_is_aligned(uintptr_t fp, int xpv_panic)
312 {
313 	if (!xpv_panic && (fp & (STACK_ALIGN -1)))
314 		return (0);
315 	if ((fp & sizeof (uintptr_t) - 1))
316 		return (0);
317 	return (1);
318 }
319 
320 int
321 mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
322     mdb_tgt_stack_f *func, void *arg)
323 {
324 	mdb_tgt_gregset_t gregs;
325 	kreg_t *kregs = &gregs.kregs[0];
326 	int got_pc = (gsp->kregs[KREG_RIP] != 0);
327 	uint_t argc, reg_argc;
328 	long fr_argv[32];
329 	int start_index; /* index to save_instr where to start comparison */
330 	int i;
331 
332 	struct {
333 		uintptr_t fr_savfp;
334 		uintptr_t fr_savpc;
335 	} fr;
336 
337 	uintptr_t fp = gsp->kregs[KREG_RBP];
338 	uintptr_t pc = gsp->kregs[KREG_RIP];
339 	uintptr_t lastfp, curpc;
340 
341 	ssize_t size;
342 
343 	GElf_Sym s;
344 	mdb_syminfo_t sip;
345 	mdb_ctf_funcinfo_t mfp;
346 	int xpv_panic = 0;
347 #ifndef	_KMDB
348 	int xp;
349 
350 	if ((mdb_readsym(&xp, sizeof (xp), "xpv_panicking") != -1) && (xp > 0))
351 		xpv_panic = 1;
352 #endif
353 
354 	bcopy(gsp, &gregs, sizeof (gregs));
355 
356 	while (fp != 0) {
357 
358 		curpc = pc;
359 
360 		if (!fp_is_aligned(fp, xpv_panic))
361 			return (set_errno(EMDB_STKALIGN));
362 
363 		if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) != sizeof (fr))
364 			return (-1);	/* errno has been set for us */
365 
366 		if ((mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
367 		    NULL, 0, &s, &sip) == 0) &&
368 		    (mdb_ctf_func_info(&s, &sip, &mfp) == 0)) {
369 			int return_type = mdb_ctf_type_kind(mfp.mtf_return);
370 			argc = mfp.mtf_argc;
371 			/*
372 			 * If the function returns a structure or union,
373 			 * %rdi contains the address in which to store the
374 			 * return value rather than for an argument.
375 			 */
376 			if (return_type == CTF_K_STRUCT ||
377 			    return_type == CTF_K_UNION)
378 				start_index = 1;
379 			else
380 				start_index = 0;
381 		} else {
382 			argc = 0;
383 		}
384 
385 		if (argc != 0 && is_argsaved(t, s.st_value, s.st_size,
386 		    argc, start_index)) {
387 
388 			/* Upto to 6 arguments are passed via registers */
389 			reg_argc = MIN(6, mfp.mtf_argc);
390 			size = reg_argc * sizeof (long);
391 
392 			if (mdb_tgt_vread(t, fr_argv, size, (fp - size))
393 			    != size)
394 				return (-1);	/* errno has been set for us */
395 
396 			/*
397 			 * Arrange the arguments in the right order for
398 			 * printing.
399 			 */
400 			for (i = 0; i < (reg_argc >> 1); i++) {
401 				long t = fr_argv[i];
402 
403 				fr_argv[i] = fr_argv[reg_argc - i - 1];
404 				fr_argv[reg_argc - i - 1] = t;
405 			}
406 
407 			if (argc > 6) {
408 				size = (argc - 6) * sizeof (long);
409 				if (mdb_tgt_vread(t, &fr_argv[6], size,
410 				    fp + sizeof (fr)) != size)
411 					return (-1); /* errno has been set */
412 			}
413 		} else
414 			argc = 0;
415 
416 		if (got_pc && func(arg, pc, argc, fr_argv, &gregs) != 0)
417 			break;
418 
419 		kregs[KREG_RSP] = kregs[KREG_RBP];
420 
421 		lastfp = fp;
422 		fp = fr.fr_savfp;
423 		/*
424 		 * The Xen hypervisor marks a stack frame as belonging to
425 		 * an exception by inverting the bits of the pointer to
426 		 * that frame.  We attempt to identify these frames by
427 		 * inverting the pointer and seeing if it is within 0xfff
428 		 * bytes of the last frame.
429 		 */
430 		if (xpv_panic)
431 			if ((fp != 0) && (fp < lastfp) &&
432 			    ((lastfp ^ ~fp) < 0xfff))
433 			fp = ~fp;
434 
435 		kregs[KREG_RBP] = fp;
436 		kregs[KREG_RIP] = pc = fr.fr_savpc;
437 
438 		if (curpc == pc)
439 			break;
440 
441 		got_pc = (pc != 0);
442 	}
443 
444 	return (0);
445 }
446 
447 /*
448  * Determine the return address for the current frame.  Typically this is the
449  * fr_savpc value from the current frame, but we also perform some special
450  * handling to see if we are stopped on one of the first two instructions of
451  * a typical function prologue, in which case %rbp will not be set up yet.
452  */
453 int
454 mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
455     mdb_instr_t curinstr)
456 {
457 	struct frame fr;
458 	GElf_Sym s;
459 	char buf[1];
460 
461 	enum {
462 		M_PUSHQ_RBP	= 0x55,	/* pushq %rbp */
463 		M_REX_W		= 0x48, /* REX prefix with only W set */
464 		M_MOVL_RBP	= 0x8b	/* movq %rsp, %rbp with prefix */
465 	};
466 
467 	if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
468 	    buf, 0, &s, NULL) == 0) {
469 		if (pc == s.st_value && curinstr == M_PUSHQ_RBP)
470 			fp = sp - 8;
471 		else if (pc == s.st_value + 1 && curinstr == M_REX_W) {
472 			if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr),
473 			    pc + 1) == sizeof (curinstr) && curinstr ==
474 			    M_MOVL_RBP)
475 				fp = sp;
476 		}
477 	}
478 
479 	if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) {
480 		*p = fr.fr_savpc;
481 		return (0);
482 	}
483 
484 	return (-1); /* errno is set for us */
485 }
486 
487 /*ARGSUSED*/
488 int
489 mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
490 {
491 	mdb_tgt_addr_t npc;
492 	mdb_tgt_addr_t callpc;
493 
494 	enum {
495 		M_CALL_REL = 0xe8, /* call near with relative displacement */
496 		M_CALL_REG = 0xff, /* call near indirect or call far register */
497 
498 		M_REX_LO = 0x40,
499 		M_REX_HI = 0x4f
500 	};
501 
502 	/*
503 	 * If the opcode is a near call with relative displacement, assume the
504 	 * displacement is a rel32 from the next instruction.
505 	 */
506 	if (curinstr == M_CALL_REL) {
507 		*p = pc + sizeof (mdb_instr_t) + sizeof (uint32_t);
508 		return (0);
509 	}
510 
511 	/* Skip the rex prefix, if any */
512 	callpc = pc;
513 	while (curinstr >= M_REX_LO && curinstr <= M_REX_HI) {
514 		if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr), ++callpc) !=
515 		    sizeof (curinstr))
516 			return (-1); /* errno is set for us */
517 	}
518 
519 	if (curinstr != M_CALL_REG) {
520 		/* It's not a call */
521 		return (set_errno(EAGAIN));
522 	}
523 
524 	if ((npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT, pc)) == pc)
525 		return (-1); /* errno is set for us */
526 
527 	*p = npc;
528 	return (0);
529 }
530 
531 /*ARGSUSED*/
532 int
533 mdb_amd64_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
534     const mdb_tgt_gregset_t *gregs)
535 {
536 	argc = MIN(argc, (uintptr_t)arglim);
537 	mdb_printf("%a(", pc);
538 
539 	if (argc != 0) {
540 		mdb_printf("%lr", *argv++);
541 		for (argc--; argc != 0; argc--)
542 			mdb_printf(", %lr", *argv++);
543 	}
544 
545 	mdb_printf(")\n");
546 	return (0);
547 }
548 
549 int
550 mdb_amd64_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
551     const mdb_tgt_gregset_t *gregs)
552 {
553 	/*
554 	 * Historically adb limited stack trace argument display to a fixed-
555 	 * size number of arguments since no symbolic debugging info existed.
556 	 * On amd64 we can detect the true number of saved arguments so only
557 	 * respect an arglim of zero; otherwise display the entire argv[].
558 	 */
559 	if (arglim == 0)
560 		argc = 0;
561 
562 	mdb_printf("%0?lr %a(", gregs->kregs[KREG_RBP], pc);
563 
564 	if (argc != 0) {
565 		mdb_printf("%lr", *argv++);
566 		for (argc--; argc != 0; argc--)
567 			mdb_printf(", %lr", *argv++);
568 	}
569 
570 	mdb_printf(")\n");
571 	return (0);
572 }
573