xref: /titanic_41/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 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_err.h>
41 #include <mdb/mdb.h>
42 
43 /*
44  * This array is used by the getareg and putareg entry points, and also by our
45  * register variable discipline.
46  */
47 
48 const mdb_tgt_regdesc_t mdb_amd64_kregs[] = {
49 	{ "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT },
50 	{ "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT },
51 	{ "rdi", KREG_RDI, MDB_TGT_R_EXPORT },
52 	{ "rsi", KREG_RSI, MDB_TGT_R_EXPORT },
53 	{ "rdx", KREG_RDX, MDB_TGT_R_EXPORT },
54 	{ "rcx", KREG_RCX, MDB_TGT_R_EXPORT },
55 	{ "r8", KREG_R8, MDB_TGT_R_EXPORT },
56 	{ "r9", KREG_R9, MDB_TGT_R_EXPORT },
57 	{ "rax", KREG_RAX, MDB_TGT_R_EXPORT },
58 	{ "rbx", KREG_RBX, MDB_TGT_R_EXPORT },
59 	{ "rbp", KREG_RBP, MDB_TGT_R_EXPORT },
60 	{ "r10", KREG_R10, MDB_TGT_R_EXPORT },
61 	{ "r11", KREG_R11, MDB_TGT_R_EXPORT },
62 	{ "r12", KREG_R12, MDB_TGT_R_EXPORT },
63 	{ "r13", KREG_R13, MDB_TGT_R_EXPORT },
64 	{ "r14", KREG_R14, MDB_TGT_R_EXPORT },
65 	{ "r15", KREG_R15, MDB_TGT_R_EXPORT },
66 	{ "fsbase", KREG_FSBASE, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
67 	{ "gsbase", KREG_GSBASE, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
68 	{ "kgsbase", KREG_KGSBASE, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
69 	{ "ds", KREG_DS, MDB_TGT_R_EXPORT },
70 	{ "es", KREG_ES, MDB_TGT_R_EXPORT },
71 	{ "fs", KREG_FS, MDB_TGT_R_EXPORT },
72 	{ "gs", KREG_GS, MDB_TGT_R_EXPORT },
73 	{ "trapno", KREG_TRAPNO, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
74 	{ "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
75 	{ "rip", KREG_RIP, MDB_TGT_R_EXPORT },
76 	{ "cs", KREG_CS, MDB_TGT_R_EXPORT },
77 	{ "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT },
78 	{ "rsp", KREG_RSP, MDB_TGT_R_EXPORT },
79 	{ "ss", KREG_SS, MDB_TGT_R_EXPORT },
80 	{ NULL, 0, 0 }
81 };
82 
83 void
84 mdb_amd64_printregs(const mdb_tgt_gregset_t *gregs)
85 {
86 	const kreg_t *kregs = &gregs->kregs[0];
87 	kreg_t rflags = kregs[KREG_RFLAGS];
88 
89 #define	GETREG2(x) ((uintptr_t)kregs[(x)]), ((uintptr_t)kregs[(x)])
90 
91 	mdb_printf("%%rax = 0x%0?p %15A %%r9  = 0x%0?p %A\n",
92 	    GETREG2(KREG_RAX), GETREG2(KREG_R9));
93 	mdb_printf("%%rbx = 0x%0?p %15A %%r10 = 0x%0?p %A\n",
94 	    GETREG2(KREG_RBX), GETREG2(KREG_R10));
95 	mdb_printf("%%rcx = 0x%0?p %15A %%r11 = 0x%0?p %A\n",
96 	    GETREG2(KREG_RCX), GETREG2(KREG_R11));
97 	mdb_printf("%%rdx = 0x%0?p %15A %%r12 = 0x%0?p %A\n",
98 	    GETREG2(KREG_RDX), GETREG2(KREG_R12));
99 	mdb_printf("%%rsi = 0x%0?p %15A %%r13 = 0x%0?p %A\n",
100 	    GETREG2(KREG_RSI), GETREG2(KREG_R13));
101 	mdb_printf("%%rdi = 0x%0?p %15A %%r14 = 0x%0?p %A\n",
102 	    GETREG2(KREG_RDI), GETREG2(KREG_R14));
103 	mdb_printf("%%r8  = 0x%0?p %15A %%r15 = 0x%0?p %A\n\n",
104 	    GETREG2(KREG_R8), GETREG2(KREG_R15));
105 
106 	mdb_printf("%%rip = 0x%0?p %A\n", GETREG2(KREG_RIP));
107 	mdb_printf("%%rbp = 0x%0?p\n", kregs[KREG_RBP]);
108 	mdb_printf("%%rsp = 0x%0?p\n", kregs[KREG_RSP]);
109 
110 	mdb_printf("%%rflags = 0x%08x\n", rflags);
111 
112 	mdb_printf("  id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
113 	    (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT,
114 	    (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT,
115 	    (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT,
116 	    (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT,
117 	    (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT,
118 	    (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT,
119 	    (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT,
120 	    (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT);
121 
122 	mdb_printf("  status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n",
123 	    (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of",
124 	    (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df",
125 	    (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if",
126 	    (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf",
127 	    (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf",
128 	    (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf",
129 	    (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af",
130 	    (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf",
131 	    (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf");
132 
133 	mdb_printf("%24s%%cs = 0x%04x\t%%ds = 0x%04x\t%%es = 0x%04x\n",
134 	    " ", kregs[KREG_CS], kregs[KREG_DS], kregs[KREG_ES]);
135 
136 	mdb_printf("%%trapno = 0x%x\t\t%%fs = 0x%04x\tfsbase = 0x%0?p\n",
137 	    kregs[KREG_TRAPNO], (kregs[KREG_FS] & 0xffff), kregs[KREG_FSBASE]);
138 	mdb_printf("   %%err = 0x%x\t\t%%gs = 0x%04x\tgsbase = 0x%0?p\n",
139 	    kregs[KREG_ERR], (kregs[KREG_GS] & 0xffff), kregs[KREG_GSBASE]);
140 }
141 
142 int
143 mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
144     mdb_tgt_stack_f *func, void *arg)
145 {
146 	mdb_tgt_gregset_t gregs;
147 	kreg_t *kregs = &gregs.kregs[0];
148 	int got_pc = (gsp->kregs[KREG_RIP] != 0);
149 
150 	struct {
151 		uintptr_t fr_savfp;
152 		uintptr_t fr_savpc;
153 	} fr;
154 
155 	uintptr_t fp = gsp->kregs[KREG_RBP];
156 	uintptr_t pc = gsp->kregs[KREG_RIP];
157 
158 	bcopy(gsp, &gregs, sizeof (gregs));
159 
160 	while (fp != 0) {
161 
162 		if (fp & (STACK_ALIGN - 1))
163 			return (set_errno(EMDB_STKALIGN));
164 
165 		bzero(&fr, sizeof (fr));
166 		(void) mdb_tgt_vread(t, &fr, sizeof (fr), fp);
167 
168 		if (got_pc && func(arg, pc, 0, NULL, &gregs) != 0)
169 			break;
170 
171 		kregs[KREG_RSP] = kregs[KREG_RBP];
172 
173 		kregs[KREG_RBP] = fp = fr.fr_savfp;
174 		kregs[KREG_RIP] = pc = fr.fr_savpc;
175 
176 		got_pc = (pc != 0);
177 	}
178 
179 	return (0);
180 }
181 
182 /*
183  * Determine the return address for the current frame.  Typically this is the
184  * fr_savpc value from the current frame, but we also perform some special
185  * handling to see if we are stopped on one of the first two instructions of
186  * a typical function prologue, in which case %rbp will not be set up yet.
187  */
188 int
189 mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
190     mdb_instr_t curinstr)
191 {
192 	struct frame fr;
193 	GElf_Sym s;
194 	char buf[1];
195 
196 	enum {
197 		M_PUSHQ_RBP	= 0x55,	/* pushq %rbp */
198 		M_REX_W		= 0x48, /* REX prefix with only W set */
199 		M_MOVL_RBP	= 0x8b	/* movq %rsp, %rbp with prefix */
200 	};
201 
202 	if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
203 	    buf, 0, &s, NULL) == 0) {
204 		if (pc == s.st_value && curinstr == M_PUSHQ_RBP)
205 			fp = sp - 8;
206 		else if (pc == s.st_value + 1 && curinstr == M_REX_W) {
207 			if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr),
208 			    pc + 1) == sizeof (curinstr) && curinstr ==
209 			    M_MOVL_RBP)
210 				fp = sp;
211 		}
212 	}
213 
214 	if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) {
215 		*p = fr.fr_savpc;
216 		return (0);
217 	}
218 
219 	return (-1); /* errno is set for us */
220 }
221 
222 /*ARGSUSED*/
223 int
224 mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
225 {
226 	mdb_tgt_addr_t npc;
227 
228 	enum {
229 		M_CALL_REL = 0xe8, /* call near with relative displacement */
230 		M_CALL_REG = 0xff, /* call near indirect or call far register */
231 
232 		M_REX_LO = 0x40,
233 		M_REX_HI = 0x4f
234 	};
235 
236 	/*
237 	 * If the opcode is a near call with relative displacement, assume the
238 	 * displacement is a rel32 from the next instruction.
239 	 */
240 	if (curinstr == M_CALL_REL) {
241 		*p = pc + sizeof (mdb_instr_t) + sizeof (uint32_t);
242 		return (0);
243 	}
244 
245 	/* Skip the rex prefix, if any */
246 	if (curinstr >= M_REX_LO && curinstr <= M_REX_HI &&
247 	    mdb_tgt_vread(t, &curinstr, sizeof (curinstr), pc) !=
248 	    sizeof (curinstr))
249 		return (-1); /* errno is set for us */
250 
251 	if (curinstr != M_CALL_REG) {
252 		/* It's not a call */
253 		return (set_errno(EAGAIN));
254 	}
255 
256 	if ((npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT, pc)) == pc)
257 		return (-1); /* errno is set for us */
258 
259 	*p = npc;
260 	return (0);
261 }
262 
263 /*ARGSUSED*/
264 int
265 mdb_amd64_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
266     const mdb_tgt_gregset_t *gregs)
267 {
268 	argc = MIN(argc, (uintptr_t)arglim);
269 	mdb_printf("%a(", pc);
270 
271 	if (argc != 0) {
272 		mdb_printf("%lr", *argv++);
273 		for (argc--; argc != 0; argc--)
274 			mdb_printf(", %lr", *argv++);
275 	}
276 
277 	mdb_printf(")\n");
278 	return (0);
279 }
280 
281 int
282 mdb_amd64_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
283     const mdb_tgt_gregset_t *gregs)
284 {
285 	argc = MIN(argc, (uintptr_t)arglim);
286 	mdb_printf("%0?lr %a(", gregs->kregs[KREG_RBP], pc);
287 
288 	if (argc != 0) {
289 		mdb_printf("%lr", *argv++);
290 		for (argc--; argc != 0; argc--)
291 			mdb_printf(", %lr", *argv++);
292 	}
293 
294 	mdb_printf(")\n");
295 	return (0);
296 }
297