10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52244Sdmick * Common Development and Distribution License (the "License").
62244Sdmick * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
212244Sdmick
220Sstevel@tonic-gate /*
233446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/reg.h>
310Sstevel@tonic-gate #include <sys/privregs.h>
320Sstevel@tonic-gate #include <sys/stack.h>
330Sstevel@tonic-gate #include <sys/frame.h>
340Sstevel@tonic-gate
350Sstevel@tonic-gate #include <mdb/mdb_target_impl.h>
360Sstevel@tonic-gate #include <mdb/mdb_kreg_impl.h>
370Sstevel@tonic-gate #include <mdb/mdb_debug.h>
380Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
390Sstevel@tonic-gate #include <mdb/mdb_amd64util.h>
40170Ssherrym #include <mdb/mdb_ctf.h>
410Sstevel@tonic-gate #include <mdb/mdb_err.h>
420Sstevel@tonic-gate #include <mdb/mdb.h>
430Sstevel@tonic-gate
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate * This array is used by the getareg and putareg entry points, and also by our
460Sstevel@tonic-gate * register variable discipline.
470Sstevel@tonic-gate */
480Sstevel@tonic-gate
490Sstevel@tonic-gate const mdb_tgt_regdesc_t mdb_amd64_kregs[] = {
500Sstevel@tonic-gate { "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT },
510Sstevel@tonic-gate { "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT },
520Sstevel@tonic-gate { "rdi", KREG_RDI, MDB_TGT_R_EXPORT },
530Sstevel@tonic-gate { "rsi", KREG_RSI, MDB_TGT_R_EXPORT },
540Sstevel@tonic-gate { "rdx", KREG_RDX, MDB_TGT_R_EXPORT },
550Sstevel@tonic-gate { "rcx", KREG_RCX, MDB_TGT_R_EXPORT },
560Sstevel@tonic-gate { "r8", KREG_R8, MDB_TGT_R_EXPORT },
570Sstevel@tonic-gate { "r9", KREG_R9, MDB_TGT_R_EXPORT },
580Sstevel@tonic-gate { "rax", KREG_RAX, MDB_TGT_R_EXPORT },
590Sstevel@tonic-gate { "rbx", KREG_RBX, MDB_TGT_R_EXPORT },
600Sstevel@tonic-gate { "rbp", KREG_RBP, MDB_TGT_R_EXPORT },
610Sstevel@tonic-gate { "r10", KREG_R10, MDB_TGT_R_EXPORT },
620Sstevel@tonic-gate { "r11", KREG_R11, MDB_TGT_R_EXPORT },
630Sstevel@tonic-gate { "r12", KREG_R12, MDB_TGT_R_EXPORT },
640Sstevel@tonic-gate { "r13", KREG_R13, MDB_TGT_R_EXPORT },
650Sstevel@tonic-gate { "r14", KREG_R14, MDB_TGT_R_EXPORT },
660Sstevel@tonic-gate { "r15", KREG_R15, MDB_TGT_R_EXPORT },
670Sstevel@tonic-gate { "ds", KREG_DS, MDB_TGT_R_EXPORT },
680Sstevel@tonic-gate { "es", KREG_ES, MDB_TGT_R_EXPORT },
690Sstevel@tonic-gate { "fs", KREG_FS, MDB_TGT_R_EXPORT },
700Sstevel@tonic-gate { "gs", KREG_GS, MDB_TGT_R_EXPORT },
710Sstevel@tonic-gate { "trapno", KREG_TRAPNO, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
720Sstevel@tonic-gate { "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
730Sstevel@tonic-gate { "rip", KREG_RIP, MDB_TGT_R_EXPORT },
740Sstevel@tonic-gate { "cs", KREG_CS, MDB_TGT_R_EXPORT },
750Sstevel@tonic-gate { "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT },
760Sstevel@tonic-gate { "rsp", KREG_RSP, MDB_TGT_R_EXPORT },
770Sstevel@tonic-gate { "ss", KREG_SS, MDB_TGT_R_EXPORT },
780Sstevel@tonic-gate { NULL, 0, 0 }
790Sstevel@tonic-gate };
800Sstevel@tonic-gate
810Sstevel@tonic-gate void
mdb_amd64_printregs(const mdb_tgt_gregset_t * gregs)820Sstevel@tonic-gate mdb_amd64_printregs(const mdb_tgt_gregset_t *gregs)
830Sstevel@tonic-gate {
840Sstevel@tonic-gate const kreg_t *kregs = &gregs->kregs[0];
850Sstevel@tonic-gate kreg_t rflags = kregs[KREG_RFLAGS];
860Sstevel@tonic-gate
870Sstevel@tonic-gate #define GETREG2(x) ((uintptr_t)kregs[(x)]), ((uintptr_t)kregs[(x)])
880Sstevel@tonic-gate
890Sstevel@tonic-gate mdb_printf("%%rax = 0x%0?p %15A %%r9 = 0x%0?p %A\n",
900Sstevel@tonic-gate GETREG2(KREG_RAX), GETREG2(KREG_R9));
910Sstevel@tonic-gate mdb_printf("%%rbx = 0x%0?p %15A %%r10 = 0x%0?p %A\n",
920Sstevel@tonic-gate GETREG2(KREG_RBX), GETREG2(KREG_R10));
930Sstevel@tonic-gate mdb_printf("%%rcx = 0x%0?p %15A %%r11 = 0x%0?p %A\n",
940Sstevel@tonic-gate GETREG2(KREG_RCX), GETREG2(KREG_R11));
950Sstevel@tonic-gate mdb_printf("%%rdx = 0x%0?p %15A %%r12 = 0x%0?p %A\n",
960Sstevel@tonic-gate GETREG2(KREG_RDX), GETREG2(KREG_R12));
970Sstevel@tonic-gate mdb_printf("%%rsi = 0x%0?p %15A %%r13 = 0x%0?p %A\n",
980Sstevel@tonic-gate GETREG2(KREG_RSI), GETREG2(KREG_R13));
990Sstevel@tonic-gate mdb_printf("%%rdi = 0x%0?p %15A %%r14 = 0x%0?p %A\n",
1000Sstevel@tonic-gate GETREG2(KREG_RDI), GETREG2(KREG_R14));
1010Sstevel@tonic-gate mdb_printf("%%r8 = 0x%0?p %15A %%r15 = 0x%0?p %A\n\n",
1020Sstevel@tonic-gate GETREG2(KREG_R8), GETREG2(KREG_R15));
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate mdb_printf("%%rip = 0x%0?p %A\n", GETREG2(KREG_RIP));
1050Sstevel@tonic-gate mdb_printf("%%rbp = 0x%0?p\n", kregs[KREG_RBP]);
1060Sstevel@tonic-gate mdb_printf("%%rsp = 0x%0?p\n", kregs[KREG_RSP]);
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate mdb_printf("%%rflags = 0x%08x\n", rflags);
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate mdb_printf(" id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
1110Sstevel@tonic-gate (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT,
1120Sstevel@tonic-gate (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT,
1130Sstevel@tonic-gate (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT,
1140Sstevel@tonic-gate (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT,
1150Sstevel@tonic-gate (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT,
1160Sstevel@tonic-gate (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT,
1170Sstevel@tonic-gate (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT,
1180Sstevel@tonic-gate (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT);
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate mdb_printf(" status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n",
1210Sstevel@tonic-gate (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of",
1220Sstevel@tonic-gate (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df",
1230Sstevel@tonic-gate (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if",
1240Sstevel@tonic-gate (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf",
1250Sstevel@tonic-gate (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf",
1260Sstevel@tonic-gate (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf",
1270Sstevel@tonic-gate (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af",
1280Sstevel@tonic-gate (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf",
1290Sstevel@tonic-gate (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf");
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate mdb_printf("%24s%%cs = 0x%04x\t%%ds = 0x%04x\t%%es = 0x%04x\n",
1320Sstevel@tonic-gate " ", kregs[KREG_CS], kregs[KREG_DS], kregs[KREG_ES]);
1330Sstevel@tonic-gate
1343446Smrj mdb_printf("%%trapno = 0x%x\t\t%%fs = 0x%04x\t%%gs = 0x%04x\n",
1353446Smrj kregs[KREG_TRAPNO], (kregs[KREG_FS] & 0xffff),
1363446Smrj (kregs[KREG_GS] & 0xffff));
1373446Smrj mdb_printf(" %%err = 0x%x\n", kregs[KREG_ERR]);
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate
140170Ssherrym /*
141170Ssherrym * Sun Studio 10 patch compiler and gcc 3.4.3 Sun branch implemented a
142170Ssherrym * "-save_args" option on amd64. When the option is specified, INTEGER
143170Ssherrym * type function arguments passed via registers will be saved on the stack
144170Ssherrym * immediately after %rbp, and will not be modified through out the life
145170Ssherrym * of the routine.
146170Ssherrym *
147170Ssherrym * +--------+
148170Ssherrym * %rbp --> | %rbp |
149170Ssherrym * +--------+
150170Ssherrym * -0x8(%rbp) | %rdi |
151170Ssherrym * +--------+
152170Ssherrym * -0x10(%rbp) | %rsi |
153170Ssherrym * +--------+
154170Ssherrym * -0x18(%rbp) | %rdx |
155170Ssherrym * +--------+
156170Ssherrym * -0x20(%rbp) | %rcx |
157170Ssherrym * +--------+
158170Ssherrym * -0x28(%rbp) | %r8 |
159170Ssherrym * +--------+
160170Ssherrym * -0x30(%rbp) | %r9 |
161170Ssherrym * +--------+
162170Ssherrym *
163170Ssherrym *
164170Ssherrym * For example, for the following function,
165170Ssherrym *
166170Ssherrym * void
167170Ssherrym * foo(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
168170Ssherrym * {
169170Ssherrym * ...
170170Ssherrym * }
171170Ssherrym *
172170Ssherrym * Disassembled code will look something like the following:
173170Ssherrym *
174170Ssherrym * pushq %rbp
175170Ssherrym * movq %rsp, %rbp
176170Ssherrym * subq $imm8, %rsp **
177170Ssherrym * movq %rdi, -0x8(%rbp)
178170Ssherrym * movq %rsi, -0x10(%rbp)
179170Ssherrym * movq %rdx, -0x18(%rbp)
180170Ssherrym * movq %rcx, -0x20(%rbp)
181170Ssherrym * movq %r8, -0x28(%rbp)
182170Ssherrym * movq %r9, -0x30(%rbp)
183170Ssherrym * ...
184170Ssherrym * or
185170Ssherrym * pushq %rbp
186170Ssherrym * movq %rsp, %rbp
187170Ssherrym * subq $imm8, %rsp **
188170Ssherrym * movq %r9, -0x30(%rbp)
189170Ssherrym * movq %r8, -0x28(%rbp)
190170Ssherrym * movq %rcx, -0x20(%rbp)
191170Ssherrym * movq %rdx, -0x18(%rbp)
192170Ssherrym * movq %rsi, -0x10(%rbp)
193170Ssherrym * movq %rdi, -0x8(%rbp)
194170Ssherrym * ...
195170Ssherrym *
196170Ssherrym * **: The space being reserved is in addition to what the current
197170Ssherrym * function prolog already reserves.
198170Ssherrym *
199170Ssherrym * If there are odd number of arguments to a function, additional space is
200170Ssherrym * reserved on the stack to maintain 16-byte alignment. For example,
201170Ssherrym *
202170Ssherrym * argc == 0: no argument saving.
203170Ssherrym * argc == 3: save 3, but space for 4 is reserved
204170Ssherrym * argc == 7: save 6.
205170Ssherrym */
206170Ssherrym
207170Ssherrym /*
208170Ssherrym * The longest instruction sequence in bytes before all 6 arguments are
209170Ssherrym * saved on the stack. This value depends on compiler implementation,
210170Ssherrym * therefore it should be examined periodically to guarantee accuracy.
211170Ssherrym */
212170Ssherrym #define SEQ_LEN 80
213170Ssherrym
214170Ssherrym /*
215170Ssherrym * Size of the instruction sequence arrays. It should correspond to
216170Ssherrym * the maximum number of arguments passed via registers.
217170Ssherrym */
218170Ssherrym #define INSTR_ARRAY_SIZE 6
219170Ssherrym
220170Ssherrym #define INSTR4(ins, off) \
221170Ssherrym (ins[(off)] + (ins[(off) + 1] << 8) + (ins[(off + 2)] << 16) + \
222170Ssherrym (ins[(off) + 3] << 24))
223170Ssherrym
224170Ssherrym /*
225170Ssherrym * Sun Studio 10 patch implementation saves %rdi first;
226170Ssherrym * GCC 3.4.3 Sun branch implementation saves them in reverse order.
227170Ssherrym */
228170Ssherrym static const uint32_t save_instr[INSTR_ARRAY_SIZE] = {
229170Ssherrym 0xf87d8948, /* movq %rdi, -0x8(%rbp) */
230170Ssherrym 0xf0758948, /* movq %rsi, -0x10(%rbp) */
231170Ssherrym 0xe8558948, /* movq %rdx, -0x18(%rbp) */
232170Ssherrym 0xe04d8948, /* movq %rcx, -0x20(%rbp) */
233170Ssherrym 0xd845894c, /* movq %r8, -0x28(%rbp) */
234170Ssherrym 0xd04d894c /* movq %r9, -0x30(%rbp) */
235170Ssherrym };
236170Ssherrym
237275Ssherrym static const uint32_t save_fp_instr[] = {
238170Ssherrym 0xe5894855, /* pushq %rbp; movq %rsp,%rbp, encoding 1 */
239275Ssherrym 0xec8b4855, /* pushq %rbp; movq %rsp,%rbp, encoding 2 */
240275Ssherrym 0xe58948cc, /* int $0x3; movq %rsp,%rbp, encoding 1 */
241275Ssherrym 0xec8b48cc, /* int $0x3; movq %rsp,%rbp, encoding 2 */
242275Ssherrym NULL
243170Ssherrym };
244170Ssherrym
245170Ssherrym /*
246170Ssherrym * Look for the above instruction sequences as indicators for register
247170Ssherrym * arguments being available on the stack.
248170Ssherrym */
249170Ssherrym static int
is_argsaved(mdb_tgt_t * t,uintptr_t fstart,uint64_t size,uint_t argc,int start_index)250170Ssherrym is_argsaved(mdb_tgt_t *t, uintptr_t fstart, uint64_t size, uint_t argc,
251170Ssherrym int start_index)
252170Ssherrym {
253170Ssherrym uint8_t ins[SEQ_LEN];
254170Ssherrym int i, j;
255170Ssherrym uint32_t n;
256170Ssherrym
257170Ssherrym size = MIN(size, SEQ_LEN);
258170Ssherrym argc = MIN((start_index + argc), INSTR_ARRAY_SIZE);
259170Ssherrym
260170Ssherrym if (mdb_tgt_vread(t, ins, size, fstart) != size)
261170Ssherrym return (0);
262170Ssherrym
263170Ssherrym /*
264170Ssherrym * Make sure framepointer has been saved.
265170Ssherrym */
266170Ssherrym n = INSTR4(ins, 0);
267275Ssherrym for (i = 0; save_fp_instr[i] != NULL; i++) {
268170Ssherrym if (n == save_fp_instr[i])
269170Ssherrym break;
270170Ssherrym }
271170Ssherrym
272275Ssherrym if (save_fp_instr[i] == NULL)
273170Ssherrym return (0);
274170Ssherrym
275170Ssherrym /*
276170Ssherrym * Compare against Sun Studio implementation
277170Ssherrym */
278170Ssherrym for (i = 8, j = start_index; i < size - 4; i++) {
279170Ssherrym n = INSTR4(ins, i);
280170Ssherrym
281170Ssherrym if (n == save_instr[j]) {
282170Ssherrym i += 3;
283170Ssherrym if (++j >= argc)
284170Ssherrym return (1);
285170Ssherrym }
286170Ssherrym }
287170Ssherrym
288170Ssherrym /*
289170Ssherrym * Compare against GCC implementation
290170Ssherrym */
291170Ssherrym for (i = 8, j = argc - 1; i < size - 4; i++) {
292170Ssherrym n = INSTR4(ins, i);
293170Ssherrym
294170Ssherrym if (n == save_instr[j]) {
295170Ssherrym i += 3;
296170Ssherrym if (--j < start_index)
297170Ssherrym return (1);
298170Ssherrym }
299170Ssherrym }
300170Ssherrym
301170Ssherrym return (0);
302170Ssherrym }
303170Ssherrym
304*5084Sjohnlev /*
305*5084Sjohnlev * We expect all proper Solaris core files to have STACK_ALIGN-aligned stacks.
306*5084Sjohnlev * Hence the name. However, if the core file resulted from a
307*5084Sjohnlev * hypervisor-initiated panic, the hypervisor's frames may only be 64-bit
308*5084Sjohnlev * aligned instead of 128.
309*5084Sjohnlev */
310*5084Sjohnlev static int
fp_is_aligned(uintptr_t fp,int xpv_panic)311*5084Sjohnlev fp_is_aligned(uintptr_t fp, int xpv_panic)
312*5084Sjohnlev {
313*5084Sjohnlev if (!xpv_panic && (fp & (STACK_ALIGN -1)))
314*5084Sjohnlev return (0);
315*5084Sjohnlev if ((fp & sizeof (uintptr_t) - 1))
316*5084Sjohnlev return (0);
317*5084Sjohnlev return (1);
318*5084Sjohnlev }
319*5084Sjohnlev
3200Sstevel@tonic-gate int
mdb_amd64_kvm_stack_iter(mdb_tgt_t * t,const mdb_tgt_gregset_t * gsp,mdb_tgt_stack_f * func,void * arg)3210Sstevel@tonic-gate mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
3220Sstevel@tonic-gate mdb_tgt_stack_f *func, void *arg)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate mdb_tgt_gregset_t gregs;
3250Sstevel@tonic-gate kreg_t *kregs = &gregs.kregs[0];
3260Sstevel@tonic-gate int got_pc = (gsp->kregs[KREG_RIP] != 0);
327170Ssherrym uint_t argc, reg_argc;
328170Ssherrym long fr_argv[32];
329170Ssherrym int start_index; /* index to save_instr where to start comparison */
330170Ssherrym int i;
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate struct {
3330Sstevel@tonic-gate uintptr_t fr_savfp;
3340Sstevel@tonic-gate uintptr_t fr_savpc;
3350Sstevel@tonic-gate } fr;
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate uintptr_t fp = gsp->kregs[KREG_RBP];
3380Sstevel@tonic-gate uintptr_t pc = gsp->kregs[KREG_RIP];
339*5084Sjohnlev uintptr_t lastfp, curpc;
340170Ssherrym
341170Ssherrym ssize_t size;
342170Ssherrym
343170Ssherrym GElf_Sym s;
344170Ssherrym mdb_syminfo_t sip;
345170Ssherrym mdb_ctf_funcinfo_t mfp;
346*5084Sjohnlev int xpv_panic = 0;
347*5084Sjohnlev #ifndef _KMDB
348*5084Sjohnlev int xp;
349*5084Sjohnlev
350*5084Sjohnlev if ((mdb_readsym(&xp, sizeof (xp), "xpv_panicking") != -1) && (xp > 0))
351*5084Sjohnlev xpv_panic = 1;
352*5084Sjohnlev #endif
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate bcopy(gsp, &gregs, sizeof (gregs));
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate while (fp != 0) {
3570Sstevel@tonic-gate
358170Ssherrym curpc = pc;
359170Ssherrym
360*5084Sjohnlev if (!fp_is_aligned(fp, xpv_panic))
3610Sstevel@tonic-gate return (set_errno(EMDB_STKALIGN));
3620Sstevel@tonic-gate
363170Ssherrym if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) != sizeof (fr))
364170Ssherrym return (-1); /* errno has been set for us */
365170Ssherrym
366170Ssherrym if ((mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
367170Ssherrym NULL, 0, &s, &sip) == 0) &&
368170Ssherrym (mdb_ctf_func_info(&s, &sip, &mfp) == 0)) {
369170Ssherrym int return_type = mdb_ctf_type_kind(mfp.mtf_return);
370170Ssherrym argc = mfp.mtf_argc;
371170Ssherrym /*
372170Ssherrym * If the function returns a structure or union,
373170Ssherrym * %rdi contains the address in which to store the
374170Ssherrym * return value rather than for an argument.
375170Ssherrym */
376170Ssherrym if (return_type == CTF_K_STRUCT ||
377170Ssherrym return_type == CTF_K_UNION)
378170Ssherrym start_index = 1;
379170Ssherrym else
380170Ssherrym start_index = 0;
381170Ssherrym } else {
382170Ssherrym argc = 0;
383170Ssherrym }
384170Ssherrym
385170Ssherrym if (argc != 0 && is_argsaved(t, s.st_value, s.st_size,
386170Ssherrym argc, start_index)) {
3870Sstevel@tonic-gate
388170Ssherrym /* Upto to 6 arguments are passed via registers */
389170Ssherrym reg_argc = MIN(6, mfp.mtf_argc);
390170Ssherrym size = reg_argc * sizeof (long);
391170Ssherrym
392170Ssherrym if (mdb_tgt_vread(t, fr_argv, size, (fp - size))
393170Ssherrym != size)
394170Ssherrym return (-1); /* errno has been set for us */
395170Ssherrym
396170Ssherrym /*
397170Ssherrym * Arrange the arguments in the right order for
398170Ssherrym * printing.
399170Ssherrym */
400170Ssherrym for (i = 0; i < (reg_argc >> 1); i++) {
401170Ssherrym long t = fr_argv[i];
402170Ssherrym
403170Ssherrym fr_argv[i] = fr_argv[reg_argc - i - 1];
404170Ssherrym fr_argv[reg_argc - i - 1] = t;
405170Ssherrym }
406170Ssherrym
407170Ssherrym if (argc > 6) {
408170Ssherrym size = (argc - 6) * sizeof (long);
409170Ssherrym if (mdb_tgt_vread(t, &fr_argv[6], size,
410170Ssherrym fp + sizeof (fr)) != size)
411170Ssherrym return (-1); /* errno has been set */
412170Ssherrym }
413170Ssherrym } else
414170Ssherrym argc = 0;
415170Ssherrym
416170Ssherrym if (got_pc && func(arg, pc, argc, fr_argv, &gregs) != 0)
4170Sstevel@tonic-gate break;
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate kregs[KREG_RSP] = kregs[KREG_RBP];
4200Sstevel@tonic-gate
421*5084Sjohnlev lastfp = fp;
422*5084Sjohnlev fp = fr.fr_savfp;
423*5084Sjohnlev /*
424*5084Sjohnlev * The Xen hypervisor marks a stack frame as belonging to
425*5084Sjohnlev * an exception by inverting the bits of the pointer to
426*5084Sjohnlev * that frame. We attempt to identify these frames by
427*5084Sjohnlev * inverting the pointer and seeing if it is within 0xfff
428*5084Sjohnlev * bytes of the last frame.
429*5084Sjohnlev */
430*5084Sjohnlev if (xpv_panic)
431*5084Sjohnlev if ((fp != 0) && (fp < lastfp) &&
432*5084Sjohnlev ((lastfp ^ ~fp) < 0xfff))
433*5084Sjohnlev fp = ~fp;
434*5084Sjohnlev
435*5084Sjohnlev kregs[KREG_RBP] = fp;
4360Sstevel@tonic-gate kregs[KREG_RIP] = pc = fr.fr_savpc;
4370Sstevel@tonic-gate
438170Ssherrym if (curpc == pc)
439170Ssherrym break;
440170Ssherrym
4410Sstevel@tonic-gate got_pc = (pc != 0);
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate
4440Sstevel@tonic-gate return (0);
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate /*
4480Sstevel@tonic-gate * Determine the return address for the current frame. Typically this is the
4490Sstevel@tonic-gate * fr_savpc value from the current frame, but we also perform some special
4500Sstevel@tonic-gate * handling to see if we are stopped on one of the first two instructions of
4510Sstevel@tonic-gate * a typical function prologue, in which case %rbp will not be set up yet.
4520Sstevel@tonic-gate */
4530Sstevel@tonic-gate 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)4540Sstevel@tonic-gate mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
4550Sstevel@tonic-gate mdb_instr_t curinstr)
4560Sstevel@tonic-gate {
4570Sstevel@tonic-gate struct frame fr;
4580Sstevel@tonic-gate GElf_Sym s;
4590Sstevel@tonic-gate char buf[1];
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate enum {
4620Sstevel@tonic-gate M_PUSHQ_RBP = 0x55, /* pushq %rbp */
4630Sstevel@tonic-gate M_REX_W = 0x48, /* REX prefix with only W set */
4640Sstevel@tonic-gate M_MOVL_RBP = 0x8b /* movq %rsp, %rbp with prefix */
4650Sstevel@tonic-gate };
4660Sstevel@tonic-gate
4670Sstevel@tonic-gate if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
4680Sstevel@tonic-gate buf, 0, &s, NULL) == 0) {
4690Sstevel@tonic-gate if (pc == s.st_value && curinstr == M_PUSHQ_RBP)
4700Sstevel@tonic-gate fp = sp - 8;
4710Sstevel@tonic-gate else if (pc == s.st_value + 1 && curinstr == M_REX_W) {
4720Sstevel@tonic-gate if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr),
4730Sstevel@tonic-gate pc + 1) == sizeof (curinstr) && curinstr ==
4740Sstevel@tonic-gate M_MOVL_RBP)
4750Sstevel@tonic-gate fp = sp;
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate
4790Sstevel@tonic-gate if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) {
4800Sstevel@tonic-gate *p = fr.fr_savpc;
4810Sstevel@tonic-gate return (0);
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate return (-1); /* errno is set for us */
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate /*ARGSUSED*/
4880Sstevel@tonic-gate int
mdb_amd64_next(mdb_tgt_t * t,uintptr_t * p,kreg_t pc,mdb_instr_t curinstr)4890Sstevel@tonic-gate mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
4900Sstevel@tonic-gate {
4910Sstevel@tonic-gate mdb_tgt_addr_t npc;
4922244Sdmick mdb_tgt_addr_t callpc;
4930Sstevel@tonic-gate
4940Sstevel@tonic-gate enum {
4950Sstevel@tonic-gate M_CALL_REL = 0xe8, /* call near with relative displacement */
4960Sstevel@tonic-gate M_CALL_REG = 0xff, /* call near indirect or call far register */
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate M_REX_LO = 0x40,
4990Sstevel@tonic-gate M_REX_HI = 0x4f
5000Sstevel@tonic-gate };
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate /*
5030Sstevel@tonic-gate * If the opcode is a near call with relative displacement, assume the
5040Sstevel@tonic-gate * displacement is a rel32 from the next instruction.
5050Sstevel@tonic-gate */
5060Sstevel@tonic-gate if (curinstr == M_CALL_REL) {
5070Sstevel@tonic-gate *p = pc + sizeof (mdb_instr_t) + sizeof (uint32_t);
5080Sstevel@tonic-gate return (0);
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate /* Skip the rex prefix, if any */
5122244Sdmick callpc = pc;
5132244Sdmick while (curinstr >= M_REX_LO && curinstr <= M_REX_HI) {
5142244Sdmick if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr), ++callpc) !=
5152244Sdmick sizeof (curinstr))
5162244Sdmick return (-1); /* errno is set for us */
5172244Sdmick }
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate if (curinstr != M_CALL_REG) {
5200Sstevel@tonic-gate /* It's not a call */
5210Sstevel@tonic-gate return (set_errno(EAGAIN));
5220Sstevel@tonic-gate }
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate if ((npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT, pc)) == pc)
5250Sstevel@tonic-gate return (-1); /* errno is set for us */
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate *p = npc;
5280Sstevel@tonic-gate return (0);
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate /*ARGSUSED*/
5320Sstevel@tonic-gate int
mdb_amd64_kvm_frame(void * arglim,uintptr_t pc,uint_t argc,const long * argv,const mdb_tgt_gregset_t * gregs)5330Sstevel@tonic-gate mdb_amd64_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
5340Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs)
5350Sstevel@tonic-gate {
5360Sstevel@tonic-gate argc = MIN(argc, (uintptr_t)arglim);
5370Sstevel@tonic-gate mdb_printf("%a(", pc);
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate if (argc != 0) {
5400Sstevel@tonic-gate mdb_printf("%lr", *argv++);
5410Sstevel@tonic-gate for (argc--; argc != 0; argc--)
5420Sstevel@tonic-gate mdb_printf(", %lr", *argv++);
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate
5450Sstevel@tonic-gate mdb_printf(")\n");
5460Sstevel@tonic-gate return (0);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate int
mdb_amd64_kvm_framev(void * arglim,uintptr_t pc,uint_t argc,const long * argv,const mdb_tgt_gregset_t * gregs)5500Sstevel@tonic-gate mdb_amd64_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
5510Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs)
5520Sstevel@tonic-gate {
553170Ssherrym /*
554170Ssherrym * Historically adb limited stack trace argument display to a fixed-
555170Ssherrym * size number of arguments since no symbolic debugging info existed.
556170Ssherrym * On amd64 we can detect the true number of saved arguments so only
557170Ssherrym * respect an arglim of zero; otherwise display the entire argv[].
558170Ssherrym */
559170Ssherrym if (arglim == 0)
560170Ssherrym argc = 0;
561170Ssherrym
5620Sstevel@tonic-gate mdb_printf("%0?lr %a(", gregs->kregs[KREG_RBP], pc);
5630Sstevel@tonic-gate
5640Sstevel@tonic-gate if (argc != 0) {
5650Sstevel@tonic-gate mdb_printf("%lr", *argv++);
5660Sstevel@tonic-gate for (argc--; argc != 0; argc--)
5670Sstevel@tonic-gate mdb_printf(", %lr", *argv++);
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate mdb_printf(")\n");
5710Sstevel@tonic-gate return (0);
5720Sstevel@tonic-gate }
573