| @@ -1,1506 +1,1507 @@ | | | @@ -1,1506 +1,1507 @@ |
1 | /* $NetBSD: db_interface.c,v 1.119 2009/12/01 18:51:20 martin Exp $ */ | | 1 | /* $NetBSD: db_interface.c,v 1.120 2009/12/02 07:55:53 mrg Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1996-2002 Eduardo Horvath. All rights reserved. | | 4 | * Copyright (c) 1996-2002 Eduardo Horvath. All rights reserved. |
5 | * Mach Operating System | | 5 | * Mach Operating System |
6 | * Copyright (c) 1991,1990 Carnegie Mellon University | | 6 | * Copyright (c) 1991,1990 Carnegie Mellon University |
7 | * All Rights Reserved. | | 7 | * All Rights Reserved. |
8 | * | | 8 | * |
9 | * Permission to use, copy, modify and distribute this software and its | | 9 | * Permission to use, copy, modify and distribute this software and its |
10 | * documentation is hereby granted, provided that both the copyright | | 10 | * documentation is hereby granted, provided that both the copyright |
11 | * notice and this permission notice appear in all copies of the | | 11 | * notice and this permission notice appear in all copies of the |
12 | * software, derivative works or modified versions, and any portions | | 12 | * software, derivative works or modified versions, and any portions |
13 | * thereof, and that both notices appear in supporting documentation. | | 13 | * thereof, and that both notices appear in supporting documentation. |
14 | * | | 14 | * |
15 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | | 15 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" |
16 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | | 16 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR |
17 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | | 17 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. |
18 | * | | 18 | * |
19 | * Carnegie Mellon requests users of this software to return to | | 19 | * Carnegie Mellon requests users of this software to return to |
20 | * | | 20 | * |
21 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | | 21 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU |
22 | * School of Computer Science | | 22 | * School of Computer Science |
23 | * Carnegie Mellon University | | 23 | * Carnegie Mellon University |
24 | * Pittsburgh PA 15213-3890 | | 24 | * Pittsburgh PA 15213-3890 |
25 | * | | 25 | * |
26 | * any improvements or extensions that they make and grant Carnegie the | | 26 | * any improvements or extensions that they make and grant Carnegie the |
27 | * rights to redistribute these changes. | | 27 | * rights to redistribute these changes. |
28 | * | | 28 | * |
29 | * From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) | | 29 | * From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Interface to new debugger. | | 33 | * Interface to new debugger. |
34 | */ | | 34 | */ |
35 | | | 35 | |
36 | #include <sys/cdefs.h> | | 36 | #include <sys/cdefs.h> |
37 | __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.119 2009/12/01 18:51:20 martin Exp $"); | | 37 | __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.120 2009/12/02 07:55:53 mrg Exp $"); |
38 | | | 38 | |
39 | #include "opt_ddb.h" | | 39 | #include "opt_ddb.h" |
40 | #include "opt_multiprocessor.h" | | 40 | #include "opt_multiprocessor.h" |
41 | | | 41 | |
42 | #include <sys/param.h> | | 42 | #include <sys/param.h> |
43 | #include <sys/proc.h> | | 43 | #include <sys/proc.h> |
44 | #include <sys/reboot.h> | | 44 | #include <sys/reboot.h> |
45 | #include <sys/systm.h> | | 45 | #include <sys/systm.h> |
46 | #include <sys/atomic.h> | | 46 | #include <sys/atomic.h> |
47 | | | 47 | |
48 | #include <uvm/uvm_extern.h> | | 48 | #include <uvm/uvm_extern.h> |
49 | | | 49 | |
50 | #include <dev/cons.h> | | 50 | #include <dev/cons.h> |
51 | | | 51 | |
52 | #include <machine/db_machdep.h> | | 52 | #include <machine/db_machdep.h> |
53 | #include <ddb/db_command.h> | | 53 | #include <ddb/db_command.h> |
54 | #include <ddb/db_sym.h> | | 54 | #include <ddb/db_sym.h> |
55 | #include <ddb/db_variables.h> | | 55 | #include <ddb/db_variables.h> |
56 | #include <ddb/db_extern.h> | | 56 | #include <ddb/db_extern.h> |
57 | #include <ddb/db_access.h> | | 57 | #include <ddb/db_access.h> |
58 | #include <ddb/db_output.h> | | 58 | #include <ddb/db_output.h> |
59 | #include <ddb/db_interface.h> | | 59 | #include <ddb/db_interface.h> |
60 | #include <ddb/ddbvar.h> | | 60 | #include <ddb/ddbvar.h> |
61 | | | 61 | |
62 | #include <machine/instr.h> | | 62 | #include <machine/instr.h> |
63 | #include <machine/cpu.h> | | 63 | #include <machine/cpu.h> |
64 | #include <machine/promlib.h> | | 64 | #include <machine/promlib.h> |
65 | #include <machine/ctlreg.h> | | 65 | #include <machine/ctlreg.h> |
66 | #include <machine/pmap.h> | | 66 | #include <machine/pmap.h> |
67 | #include <machine/intr.h> | | 67 | #include <machine/intr.h> |
68 | | | 68 | |
69 | #include "fb.h" | | 69 | #include "fb.h" |
70 | | | 70 | |
71 | extern struct traptrace { | | 71 | extern struct traptrace { |
72 | unsigned short tl:3, /* Trap level */ | | 72 | unsigned short tl:3, /* Trap level */ |
73 | ns:4, /* PCB nsaved */ | | 73 | ns:4, /* PCB nsaved */ |
74 | tt:9; /* Trap type */ | | 74 | tt:9; /* Trap type */ |
75 | unsigned short pid; /* PID */ | | 75 | unsigned short pid; /* PID */ |
76 | u_int tstate; /* tstate */ | | 76 | u_int tstate; /* tstate */ |
77 | u_int tsp; /* sp */ | | 77 | u_int tsp; /* sp */ |
78 | u_int tpc; /* pc */ | | 78 | u_int tpc; /* pc */ |
79 | u_int tfault; /* MMU tag access */ | | 79 | u_int tfault; /* MMU tag access */ |
80 | } trap_trace[], trap_trace_end[]; | | 80 | } trap_trace[], trap_trace_end[]; |
81 | | | 81 | |
82 | /* | | 82 | /* |
83 | * Helpers for ddb variables. | | 83 | * Helpers for ddb variables. |
84 | */ | | 84 | */ |
85 | static uint64_t nil; | | 85 | static uint64_t nil; |
86 | | | 86 | |
87 | #ifdef MULTIPROCESSOR | | 87 | #ifdef MULTIPROCESSOR |
88 | #define pmap_ctx(PM) ((PM)->pm_ctx[cpu_number()]) | | 88 | #define pmap_ctx(PM) ((PM)->pm_ctx[cpu_number()]) |
89 | #else | | 89 | #else |
90 | #define pmap_ctx(PM) ((PM)->pm_ctx) | | 90 | #define pmap_ctx(PM) ((PM)->pm_ctx) |
91 | #endif | | 91 | #endif |
92 | | | 92 | |
93 | void fill_ddb_regs_from_tf(struct trapframe64 *tf); | | 93 | void fill_ddb_regs_from_tf(struct trapframe64 *tf); |
94 | void ddb_restore_state(void); | | 94 | void ddb_restore_state(void); |
95 | bool ddb_running_on_this_cpu(void); | | 95 | bool ddb_running_on_this_cpu(void); |
96 | | | 96 | |
97 | static int | | 97 | static int |
98 | db_sparc_charop(const struct db_variable *vp, db_expr_t *val, int opcode) | | 98 | db_sparc_charop(const struct db_variable *vp, db_expr_t *val, int opcode) |
99 | { | | 99 | { |
100 | char *regaddr = | | 100 | char *regaddr = |
101 | (char *)(((uint8_t *)DDB_REGS) + (size_t)vp->valuep); | | 101 | (char *)(((uint8_t *)DDB_REGS) + (size_t)vp->valuep); |
102 | | | 102 | |
103 | switch (opcode) { | | 103 | switch (opcode) { |
104 | case DB_VAR_GET: | | 104 | case DB_VAR_GET: |
105 | *val = *regaddr; | | 105 | *val = *regaddr; |
106 | break; | | 106 | break; |
107 | case DB_VAR_SET: | | 107 | case DB_VAR_SET: |
108 | *regaddr = *val; | | 108 | *regaddr = *val; |
109 | break; | | 109 | break; |
110 | #ifdef DIAGNOSTIC | | 110 | #ifdef DIAGNOSTIC |
111 | default: | | 111 | default: |
112 | printf("db_sparc_charop: opcode %d\n", opcode); | | 112 | printf("db_sparc_charop: opcode %d\n", opcode); |
113 | break; | | 113 | break; |
114 | #endif | | 114 | #endif |
115 | } | | 115 | } |
116 | | | 116 | |
117 | return 0; | | 117 | return 0; |
118 | } | | 118 | } |
119 | | | 119 | |
120 | #ifdef not_used | | 120 | #ifdef not_used |
121 | static int | | 121 | static int |
122 | db_sparc_shortop(const struct db_variable *vp, db_expr_t *val, int opcode) | | 122 | db_sparc_shortop(const struct db_variable *vp, db_expr_t *val, int opcode) |
123 | { | | 123 | { |
124 | short *regaddr = | | 124 | short *regaddr = |
125 | (short *)(((uint8_t *)DDB_REGS) + (size_t)vp->valuep); | | 125 | (short *)(((uint8_t *)DDB_REGS) + (size_t)vp->valuep); |
126 | | | 126 | |
127 | switch (opcode) { | | 127 | switch (opcode) { |
128 | case DB_VAR_GET: | | 128 | case DB_VAR_GET: |
129 | *val = *regaddr; | | 129 | *val = *regaddr; |
130 | break; | | 130 | break; |
131 | case DB_VAR_SET: | | 131 | case DB_VAR_SET: |
132 | *regaddr = *val; | | 132 | *regaddr = *val; |
133 | break; | | 133 | break; |
134 | #ifdef DIAGNOSTIC | | 134 | #ifdef DIAGNOSTIC |
135 | default: | | 135 | default: |
136 | printf("sparc_shortop: opcode %d\n", opcode); | | 136 | printf("sparc_shortop: opcode %d\n", opcode); |
137 | break; | | 137 | break; |
138 | #endif | | 138 | #endif |
139 | } | | 139 | } |
140 | | | 140 | |
141 | return 0; | | 141 | return 0; |
142 | } | | 142 | } |
143 | #endif | | 143 | #endif |
144 | | | 144 | |
145 | static int | | 145 | static int |
146 | db_sparc_intop(const struct db_variable *vp, db_expr_t *val, int opcode) | | 146 | db_sparc_intop(const struct db_variable *vp, db_expr_t *val, int opcode) |
147 | { | | 147 | { |
148 | int *regaddr = | | 148 | int *regaddr = |
149 | (int *)(((uint8_t *)DDB_REGS) + (size_t)vp->valuep); | | 149 | (int *)(((uint8_t *)DDB_REGS) + (size_t)vp->valuep); |
150 | | | 150 | |
151 | switch (opcode) { | | 151 | switch (opcode) { |
152 | case DB_VAR_GET: | | 152 | case DB_VAR_GET: |
153 | *val = *regaddr; | | 153 | *val = *regaddr; |
154 | break; | | 154 | break; |
155 | case DB_VAR_SET: | | 155 | case DB_VAR_SET: |
156 | *regaddr = *val; | | 156 | *regaddr = *val; |
157 | break; | | 157 | break; |
158 | #ifdef DIAGNOSTIC | | 158 | #ifdef DIAGNOSTIC |
159 | default: | | 159 | default: |
160 | printf("db_sparc_intop: opcode %d\n", opcode); | | 160 | printf("db_sparc_intop: opcode %d\n", opcode); |
161 | break; | | 161 | break; |
162 | #endif | | 162 | #endif |
163 | } | | 163 | } |
164 | | | 164 | |
165 | return 0; | | 165 | return 0; |
166 | } | | 166 | } |
167 | | | 167 | |
168 | static int | | 168 | static int |
169 | db_sparc_regop(const struct db_variable *vp, db_expr_t *val, int opcode) | | 169 | db_sparc_regop(const struct db_variable *vp, db_expr_t *val, int opcode) |
170 | { | | 170 | { |
171 | db_expr_t *regaddr = | | 171 | db_expr_t *regaddr = |
172 | (db_expr_t *)(((uint8_t *)DDB_REGS) + (size_t)vp->valuep); | | 172 | (db_expr_t *)(((uint8_t *)DDB_REGS) + (size_t)vp->valuep); |
173 | | | 173 | |
174 | switch (opcode) { | | 174 | switch (opcode) { |
175 | case DB_VAR_GET: | | 175 | case DB_VAR_GET: |
176 | *val = *regaddr; | | 176 | *val = *regaddr; |
177 | break; | | 177 | break; |
178 | case DB_VAR_SET: | | 178 | case DB_VAR_SET: |
179 | *regaddr = *val; | | 179 | *regaddr = *val; |
180 | break; | | 180 | break; |
181 | #ifdef DIAGNOSTIC | | 181 | #ifdef DIAGNOSTIC |
182 | default: | | 182 | default: |
183 | printf("db_sparc_regop: unknown op %d\n", opcode); | | 183 | printf("db_sparc_regop: unknown op %d\n", opcode); |
184 | break; | | 184 | break; |
185 | #endif | | 185 | #endif |
186 | } | | 186 | } |
187 | return 0; | | 187 | return 0; |
188 | } | | 188 | } |
189 | | | 189 | |
190 | /* | | 190 | /* |
191 | * Machine register set. | | 191 | * Machine register set. |
192 | */ | | 192 | */ |
193 | #define dbreg(xx) (long *)offsetof(db_regs_t, db_tf.tf_ ## xx) | | 193 | #define dbreg(xx) (long *)offsetof(db_regs_t, db_tf.tf_ ## xx) |
194 | #define dbregfr(xx) (long *)offsetof(db_regs_t, db_fr.fr_ ## xx) | | 194 | #define dbregfr(xx) (long *)offsetof(db_regs_t, db_fr.fr_ ## xx) |
195 | #define dbregfp(xx) (long *)offsetof(db_regs_t, db_fpstate.fs_ ## xx) | | 195 | #define dbregfp(xx) (long *)offsetof(db_regs_t, db_fpstate.fs_ ## xx) |
196 | | | 196 | |
197 | static int db_sparc_regop(const struct db_variable *, db_expr_t *, int); | | 197 | static int db_sparc_regop(const struct db_variable *, db_expr_t *, int); |
198 | | | 198 | |
199 | const struct db_variable db_regs[] = { | | 199 | const struct db_variable db_regs[] = { |
200 | { "tstate", dbreg(tstate), db_sparc_regop, 0 }, | | 200 | { "tstate", dbreg(tstate), db_sparc_regop, 0 }, |
201 | { "pc", dbreg(pc), db_sparc_regop, 0 }, | | 201 | { "pc", dbreg(pc), db_sparc_regop, 0 }, |
202 | { "npc", dbreg(npc), db_sparc_regop, 0 }, | | 202 | { "npc", dbreg(npc), db_sparc_regop, 0 }, |
203 | { "ipl", dbreg(oldpil), db_sparc_charop, 0 }, | | 203 | { "ipl", dbreg(oldpil), db_sparc_charop, 0 }, |
204 | { "y", dbreg(y), db_sparc_intop, 0 }, | | 204 | { "y", dbreg(y), db_sparc_intop, 0 }, |
205 | { "g0", (void *)&nil, FCN_NULL, 0 }, | | 205 | { "g0", (void *)&nil, FCN_NULL, 0 }, |
206 | { "g1", dbreg(global[1]), db_sparc_regop, 0 }, | | 206 | { "g1", dbreg(global[1]), db_sparc_regop, 0 }, |
207 | { "g2", dbreg(global[2]), db_sparc_regop, 0 }, | | 207 | { "g2", dbreg(global[2]), db_sparc_regop, 0 }, |
208 | { "g3", dbreg(global[3]), db_sparc_regop, 0 }, | | 208 | { "g3", dbreg(global[3]), db_sparc_regop, 0 }, |
209 | { "g4", dbreg(global[4]), db_sparc_regop, 0 }, | | 209 | { "g4", dbreg(global[4]), db_sparc_regop, 0 }, |
210 | { "g5", dbreg(global[5]), db_sparc_regop, 0 }, | | 210 | { "g5", dbreg(global[5]), db_sparc_regop, 0 }, |
211 | { "g6", dbreg(global[6]), db_sparc_regop, 0 }, | | 211 | { "g6", dbreg(global[6]), db_sparc_regop, 0 }, |
212 | { "g7", dbreg(global[7]), db_sparc_regop, 0 }, | | 212 | { "g7", dbreg(global[7]), db_sparc_regop, 0 }, |
213 | { "o0", dbreg(out[0]), db_sparc_regop, 0 }, | | 213 | { "o0", dbreg(out[0]), db_sparc_regop, 0 }, |
214 | { "o1", dbreg(out[1]), db_sparc_regop, 0 }, | | 214 | { "o1", dbreg(out[1]), db_sparc_regop, 0 }, |
215 | { "o2", dbreg(out[2]), db_sparc_regop, 0 }, | | 215 | { "o2", dbreg(out[2]), db_sparc_regop, 0 }, |
216 | { "o3", dbreg(out[3]), db_sparc_regop, 0 }, | | 216 | { "o3", dbreg(out[3]), db_sparc_regop, 0 }, |
217 | { "o4", dbreg(out[4]), db_sparc_regop, 0 }, | | 217 | { "o4", dbreg(out[4]), db_sparc_regop, 0 }, |
218 | { "o5", dbreg(out[5]), db_sparc_regop, 0 }, | | 218 | { "o5", dbreg(out[5]), db_sparc_regop, 0 }, |
219 | { "o6", dbreg(out[6]), db_sparc_regop, 0 }, | | 219 | { "o6", dbreg(out[6]), db_sparc_regop, 0 }, |
220 | { "o7", dbreg(out[7]), db_sparc_regop, 0 }, | | 220 | { "o7", dbreg(out[7]), db_sparc_regop, 0 }, |
221 | { "l0", dbregfr(local[0]), db_sparc_regop, 0 }, | | 221 | { "l0", dbregfr(local[0]), db_sparc_regop, 0 }, |
222 | { "l1", dbregfr(local[1]), db_sparc_regop, 0 }, | | 222 | { "l1", dbregfr(local[1]), db_sparc_regop, 0 }, |
223 | { "l2", dbregfr(local[2]), db_sparc_regop, 0 }, | | 223 | { "l2", dbregfr(local[2]), db_sparc_regop, 0 }, |
224 | { "l3", dbregfr(local[3]), db_sparc_regop, 0 }, | | 224 | { "l3", dbregfr(local[3]), db_sparc_regop, 0 }, |
225 | { "l4", dbregfr(local[4]), db_sparc_regop, 0 }, | | 225 | { "l4", dbregfr(local[4]), db_sparc_regop, 0 }, |
226 | { "l5", dbregfr(local[5]), db_sparc_regop, 0 }, | | 226 | { "l5", dbregfr(local[5]), db_sparc_regop, 0 }, |
227 | { "l6", dbregfr(local[6]), db_sparc_regop, 0 }, | | 227 | { "l6", dbregfr(local[6]), db_sparc_regop, 0 }, |
228 | { "l7", dbregfr(local[7]), db_sparc_regop, 0 }, | | 228 | { "l7", dbregfr(local[7]), db_sparc_regop, 0 }, |
229 | { "i0", dbregfr(arg[0]), db_sparc_regop, 0 }, | | 229 | { "i0", dbregfr(arg[0]), db_sparc_regop, 0 }, |
230 | { "i1", dbregfr(arg[1]), db_sparc_regop, 0 }, | | 230 | { "i1", dbregfr(arg[1]), db_sparc_regop, 0 }, |
231 | { "i2", dbregfr(arg[2]), db_sparc_regop, 0 }, | | 231 | { "i2", dbregfr(arg[2]), db_sparc_regop, 0 }, |
232 | { "i3", dbregfr(arg[3]), db_sparc_regop, 0 }, | | 232 | { "i3", dbregfr(arg[3]), db_sparc_regop, 0 }, |
233 | { "i4", dbregfr(arg[4]), db_sparc_regop, 0 }, | | 233 | { "i4", dbregfr(arg[4]), db_sparc_regop, 0 }, |
234 | { "i5", dbregfr(arg[5]), db_sparc_regop, 0 }, | | 234 | { "i5", dbregfr(arg[5]), db_sparc_regop, 0 }, |
235 | { "i6", dbregfr(arg[6]), db_sparc_regop, 0 }, | | 235 | { "i6", dbregfr(arg[6]), db_sparc_regop, 0 }, |
236 | { "i7", dbregfr(arg[7]), db_sparc_regop, 0 }, | | 236 | { "i7", dbregfr(arg[7]), db_sparc_regop, 0 }, |
237 | { "f0", dbregfp(regs[0]), db_sparc_regop, 0 }, | | 237 | { "f0", dbregfp(regs[0]), db_sparc_regop, 0 }, |
238 | { "f2", dbregfp(regs[2]), db_sparc_regop, 0 }, | | 238 | { "f2", dbregfp(regs[2]), db_sparc_regop, 0 }, |
239 | { "f4", dbregfp(regs[4]), db_sparc_regop, 0 }, | | 239 | { "f4", dbregfp(regs[4]), db_sparc_regop, 0 }, |
240 | { "f6", dbregfp(regs[6]), db_sparc_regop, 0 }, | | 240 | { "f6", dbregfp(regs[6]), db_sparc_regop, 0 }, |
241 | { "f8", dbregfp(regs[8]), db_sparc_regop, 0 }, | | 241 | { "f8", dbregfp(regs[8]), db_sparc_regop, 0 }, |
242 | { "f10", dbregfp(regs[10]), db_sparc_regop, 0 }, | | 242 | { "f10", dbregfp(regs[10]), db_sparc_regop, 0 }, |
243 | { "f12", dbregfp(regs[12]), db_sparc_regop, 0 }, | | 243 | { "f12", dbregfp(regs[12]), db_sparc_regop, 0 }, |
244 | { "f14", dbregfp(regs[14]), db_sparc_regop, 0 }, | | 244 | { "f14", dbregfp(regs[14]), db_sparc_regop, 0 }, |
245 | { "f16", dbregfp(regs[16]), db_sparc_regop, 0 }, | | 245 | { "f16", dbregfp(regs[16]), db_sparc_regop, 0 }, |
246 | { "f18", dbregfp(regs[18]), db_sparc_regop, 0 }, | | 246 | { "f18", dbregfp(regs[18]), db_sparc_regop, 0 }, |
247 | { "f20", dbregfp(regs[20]), db_sparc_regop, 0 }, | | 247 | { "f20", dbregfp(regs[20]), db_sparc_regop, 0 }, |
248 | { "f22", dbregfp(regs[22]), db_sparc_regop, 0 }, | | 248 | { "f22", dbregfp(regs[22]), db_sparc_regop, 0 }, |
249 | { "f24", dbregfp(regs[24]), db_sparc_regop, 0 }, | | 249 | { "f24", dbregfp(regs[24]), db_sparc_regop, 0 }, |
250 | { "f26", dbregfp(regs[26]), db_sparc_regop, 0 }, | | 250 | { "f26", dbregfp(regs[26]), db_sparc_regop, 0 }, |
251 | { "f28", dbregfp(regs[28]), db_sparc_regop, 0 }, | | 251 | { "f28", dbregfp(regs[28]), db_sparc_regop, 0 }, |
252 | { "f30", dbregfp(regs[30]), db_sparc_regop, 0 }, | | 252 | { "f30", dbregfp(regs[30]), db_sparc_regop, 0 }, |
253 | { "f32", dbregfp(regs[32]), db_sparc_regop, 0 }, | | 253 | { "f32", dbregfp(regs[32]), db_sparc_regop, 0 }, |
254 | { "f34", dbregfp(regs[34]), db_sparc_regop, 0 }, | | 254 | { "f34", dbregfp(regs[34]), db_sparc_regop, 0 }, |
255 | { "f36", dbregfp(regs[36]), db_sparc_regop, 0 }, | | 255 | { "f36", dbregfp(regs[36]), db_sparc_regop, 0 }, |
256 | { "f38", dbregfp(regs[38]), db_sparc_regop, 0 }, | | 256 | { "f38", dbregfp(regs[38]), db_sparc_regop, 0 }, |
257 | { "f40", dbregfp(regs[40]), db_sparc_regop, 0 }, | | 257 | { "f40", dbregfp(regs[40]), db_sparc_regop, 0 }, |
258 | { "f42", dbregfp(regs[42]), db_sparc_regop, 0 }, | | 258 | { "f42", dbregfp(regs[42]), db_sparc_regop, 0 }, |
259 | { "f44", dbregfp(regs[44]), db_sparc_regop, 0 }, | | 259 | { "f44", dbregfp(regs[44]), db_sparc_regop, 0 }, |
260 | { "f46", dbregfp(regs[46]), db_sparc_regop, 0 }, | | 260 | { "f46", dbregfp(regs[46]), db_sparc_regop, 0 }, |
261 | { "f48", dbregfp(regs[48]), db_sparc_regop, 0 }, | | 261 | { "f48", dbregfp(regs[48]), db_sparc_regop, 0 }, |
262 | { "f50", dbregfp(regs[50]), db_sparc_regop, 0 }, | | 262 | { "f50", dbregfp(regs[50]), db_sparc_regop, 0 }, |
263 | { "f52", dbregfp(regs[52]), db_sparc_regop, 0 }, | | 263 | { "f52", dbregfp(regs[52]), db_sparc_regop, 0 }, |
264 | { "f54", dbregfp(regs[54]), db_sparc_regop, 0 }, | | 264 | { "f54", dbregfp(regs[54]), db_sparc_regop, 0 }, |
265 | { "f56", dbregfp(regs[56]), db_sparc_regop, 0 }, | | 265 | { "f56", dbregfp(regs[56]), db_sparc_regop, 0 }, |
266 | { "f58", dbregfp(regs[58]), db_sparc_regop, 0 }, | | 266 | { "f58", dbregfp(regs[58]), db_sparc_regop, 0 }, |
267 | { "f60", dbregfp(regs[60]), db_sparc_regop, 0 }, | | 267 | { "f60", dbregfp(regs[60]), db_sparc_regop, 0 }, |
268 | { "f62", dbregfp(regs[62]), db_sparc_regop, 0 }, | | 268 | { "f62", dbregfp(regs[62]), db_sparc_regop, 0 }, |
269 | { "fsr", dbregfp(fsr), db_sparc_regop, 0 }, | | 269 | { "fsr", dbregfp(fsr), db_sparc_regop, 0 }, |
270 | { "gsr", dbregfp(gsr), db_sparc_intop, 0 }, | | 270 | { "gsr", dbregfp(gsr), db_sparc_intop, 0 }, |
271 | }; | | 271 | }; |
272 | const struct db_variable * const db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); | | 272 | const struct db_variable * const db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); |
273 | | | 273 | |
274 | int db_active = 0; | | 274 | int db_active = 0; |
275 | | | 275 | |
276 | extern char *trap_type[]; | | 276 | extern char *trap_type[]; |
277 | | | 277 | |
278 | void kdb_kbd_trap(struct trapframe64 *); | | 278 | void kdb_kbd_trap(struct trapframe64 *); |
279 | void db_prom_cmd(db_expr_t, bool, db_expr_t, const char *); | | 279 | void db_prom_cmd(db_expr_t, bool, db_expr_t, const char *); |
280 | void db_lwp_cmd(db_expr_t, bool, db_expr_t, const char *); | | 280 | void db_lwp_cmd(db_expr_t, bool, db_expr_t, const char *); |
281 | void db_proc_cmd(db_expr_t, bool, db_expr_t, const char *); | | 281 | void db_proc_cmd(db_expr_t, bool, db_expr_t, const char *); |
282 | void db_ctx_cmd(db_expr_t, bool, db_expr_t, const char *); | | 282 | void db_ctx_cmd(db_expr_t, bool, db_expr_t, const char *); |
283 | void db_dump_pcb(db_expr_t, bool, db_expr_t, const char *); | | 283 | void db_dump_pcb(db_expr_t, bool, db_expr_t, const char *); |
284 | void db_dump_pv(db_expr_t, bool, db_expr_t, const char *); | | 284 | void db_dump_pv(db_expr_t, bool, db_expr_t, const char *); |
285 | void db_setpcb(db_expr_t, bool, db_expr_t, const char *); | | 285 | void db_setpcb(db_expr_t, bool, db_expr_t, const char *); |
286 | void db_dump_dtlb(db_expr_t, bool, db_expr_t, const char *); | | 286 | void db_dump_dtlb(db_expr_t, bool, db_expr_t, const char *); |
287 | void db_dump_itlb(db_expr_t, bool, db_expr_t, const char *); | | 287 | void db_dump_itlb(db_expr_t, bool, db_expr_t, const char *); |
288 | void db_dump_dtsb(db_expr_t, bool, db_expr_t, const char *); | | 288 | void db_dump_dtsb(db_expr_t, bool, db_expr_t, const char *); |
289 | void db_dump_itsb(db_expr_t, bool, db_expr_t, const char *); | | 289 | void db_dump_itsb(db_expr_t, bool, db_expr_t, const char *); |
290 | void db_pmap_kernel(db_expr_t, bool, db_expr_t, const char *); | | 290 | void db_pmap_kernel(db_expr_t, bool, db_expr_t, const char *); |
291 | void db_pload_cmd(db_expr_t, bool, db_expr_t, const char *); | | 291 | void db_pload_cmd(db_expr_t, bool, db_expr_t, const char *); |
292 | void db_pmap_cmd(db_expr_t, bool, db_expr_t, const char *); | | 292 | void db_pmap_cmd(db_expr_t, bool, db_expr_t, const char *); |
293 | void db_traptrace(db_expr_t, bool, db_expr_t, const char *); | | 293 | void db_traptrace(db_expr_t, bool, db_expr_t, const char *); |
294 | void db_watch(db_expr_t, bool, db_expr_t, const char *); | | 294 | void db_watch(db_expr_t, bool, db_expr_t, const char *); |
295 | void db_pm_extract(db_expr_t, bool, db_expr_t, const char *); | | 295 | void db_pm_extract(db_expr_t, bool, db_expr_t, const char *); |
296 | void db_cpu_cmd(db_expr_t, bool, db_expr_t, const char *); | | 296 | void db_cpu_cmd(db_expr_t, bool, db_expr_t, const char *); |
297 | void db_sir_cmd(db_expr_t, bool, db_expr_t, const char *); | | 297 | void db_sir_cmd(db_expr_t, bool, db_expr_t, const char *); |
298 | | | 298 | |
299 | #ifdef DDB | | 299 | #ifdef DDB |
300 | static void db_dump_pmap(struct pmap *); | | 300 | static void db_dump_pmap(struct pmap *); |
301 | static void db_print_trace_entry(struct traptrace *, int); | | 301 | static void db_print_trace_entry(struct traptrace *, int); |
302 | | | 302 | |
303 | #ifdef MULTIPROCESSOR | | 303 | #ifdef MULTIPROCESSOR |
304 | | | 304 | |
305 | #define NOCPU -1 | | 305 | #define NOCPU -1 |
306 | | | 306 | |
307 | static int db_suspend_others(void); | | 307 | static int db_suspend_others(void); |
308 | static void ddb_suspend(struct trapframe64 *); | | 308 | static void ddb_suspend(struct trapframe64 *); |
309 | void db_resume_others(void); | | 309 | void db_resume_others(void); |
310 | | | 310 | |
311 | int ddb_cpu = NOCPU; | | 311 | int ddb_cpu = NOCPU; |
312 | | | 312 | |
313 | bool | | 313 | bool |
314 | ddb_running_on_this_cpu(void) | | 314 | ddb_running_on_this_cpu(void) |
315 | { | | 315 | { |
316 | return ddb_cpu == cpu_number(); | | 316 | return ddb_cpu == cpu_number(); |
317 | } | | 317 | } |
318 | | | 318 | |
319 | static int | | 319 | static int |
320 | db_suspend_others(void) | | 320 | db_suspend_others(void) |
321 | { | | 321 | { |
322 | int cpu_me = cpu_number(); | | 322 | int cpu_me = cpu_number(); |
323 | bool win; | | 323 | bool win; |
324 | | | 324 | |
325 | if (cpus == NULL) | | 325 | if (cpus == NULL) |
326 | return 1; | | 326 | return 1; |
327 | | | 327 | |
328 | win = atomic_cas_32(&ddb_cpu, NOCPU, cpu_me) == (uint32_t)NOCPU; | | 328 | win = atomic_cas_32(&ddb_cpu, NOCPU, cpu_me) == (uint32_t)NOCPU; |
329 | if (win) | | 329 | if (win) |
330 | mp_pause_cpus(); | | 330 | mp_pause_cpus(); |
331 | | | 331 | |
332 | return win; | | 332 | return win; |
333 | } | | 333 | } |
334 | | | 334 | |
335 | void | | 335 | void |
336 | db_resume_others(void) | | 336 | db_resume_others(void) |
337 | { | | 337 | { |
338 | int cpu_me = cpu_number(); | | 338 | int cpu_me = cpu_number(); |
339 | | | 339 | |
340 | if (atomic_cas_32(&ddb_cpu, cpu_me, NOCPU) == cpu_me) | | 340 | if (atomic_cas_32(&ddb_cpu, cpu_me, NOCPU) == cpu_me) |
341 | mp_resume_cpus(); | | 341 | mp_resume_cpus(); |
342 | } | | 342 | } |
343 | | | 343 | |
344 | static void | | 344 | static void |
345 | ddb_suspend(struct trapframe64 *tf) | | 345 | ddb_suspend(struct trapframe64 *tf) |
346 | { | | 346 | { |
347 | | | 347 | |
348 | sparc64_ipi_pause_thiscpu(tf); | | 348 | sparc64_ipi_pause_thiscpu(tf); |
349 | } | | 349 | } |
350 | #endif /* MULTIPROCESSOR */ | | 350 | #endif /* MULTIPROCESSOR */ |
351 | | | 351 | |
352 | /* | | 352 | /* |
353 | * Received keyboard interrupt sequence. | | 353 | * Received keyboard interrupt sequence. |
354 | */ | | 354 | */ |
355 | void | | 355 | void |
356 | kdb_kbd_trap(struct trapframe64 *tf) | | 356 | kdb_kbd_trap(struct trapframe64 *tf) |
357 | { | | 357 | { |
358 | if (db_active == 0 /* && (boothowto & RB_KDB) */) { | | 358 | if (db_active == 0 /* && (boothowto & RB_KDB) */) { |
359 | printf("\n\nkernel: keyboard interrupt tf=%p\n", tf); | | 359 | printf("\n\nkernel: keyboard interrupt tf=%p\n", tf); |
360 | kdb_trap(-1, tf); | | 360 | kdb_trap(-1, tf); |
361 | } | | 361 | } |
362 | } | | 362 | } |
363 | | | 363 | |
364 | void | | 364 | void |
365 | fill_ddb_regs_from_tf(struct trapframe64 *tf) | | 365 | fill_ddb_regs_from_tf(struct trapframe64 *tf) |
366 | { | | 366 | { |
367 | extern int savetstate(struct trapstate *); | | 367 | extern int savetstate(struct trapstate *); |
368 | | | 368 | |
369 | #ifdef MULTIPROCESSOR | | 369 | #ifdef MULTIPROCESSOR |
370 | static db_regs_t ddbregs[CPUSET_MAXNUMCPU]; | | 370 | static db_regs_t ddbregs[CPUSET_MAXNUMCPU]; |
371 | | | 371 | |
372 | curcpu()->ci_ddb_regs = &ddbregs[cpu_number()]; | | 372 | curcpu()->ci_ddb_regs = &ddbregs[cpu_number()]; |
373 | #else | | 373 | #else |
374 | static db_regs_t ddbregs; | | 374 | static db_regs_t ddbregs; |
375 | | | 375 | |
376 | curcpu()->ci_ddb_regs = &ddbregs; | | 376 | curcpu()->ci_ddb_regs = &ddbregs; |
377 | #endif | | 377 | #endif |
378 | | | 378 | |
379 | DDB_REGS->db_tf = *tf; | | 379 | DDB_REGS->db_tf = *tf; |
380 | #ifdef __arch64__ | | 380 | #ifdef __arch64__ |
381 | DDB_REGS->db_fr = *(struct frame64 *)(uintptr_t)tf->tf_out[6]; | | 381 | DDB_REGS->db_fr = *(struct frame64 *)(uintptr_t)tf->tf_out[6]; |
382 | #else | | 382 | #else |
383 | { | | 383 | { |
384 | struct frame32 *tf32 = (struct frame32 *)(uintptr_t)tf->tf_out[6]; | | 384 | struct frame32 *tf32 = (struct frame32 *)(uintptr_t)tf->tf_out[6]; |
385 | int i; | | 385 | int i; |
386 | | | 386 | |
387 | for (i = 0; i < 8; i++) | | 387 | for (i = 0; i < 8; i++) |
388 | DDB_REGS->db_fr.fr_local[i] = (uint32_t)tf32->fr_local[i]; | | 388 | DDB_REGS->db_fr.fr_local[i] = (uint32_t)tf32->fr_local[i]; |
389 | for (i = 0; i < 6; i++) | | 389 | for (i = 0; i < 6; i++) |
390 | DDB_REGS->db_fr.fr_arg[i] = (uint32_t)tf32->fr_arg[i]; | | 390 | DDB_REGS->db_fr.fr_arg[i] = (uint32_t)tf32->fr_arg[i]; |
391 | DDB_REGS->db_fr.fr_fp = tf32->fr_fp; | | 391 | DDB_REGS->db_fr.fr_fp = tf32->fr_fp; |
392 | DDB_REGS->db_fr.fr_pc = tf32->fr_pc; | | 392 | DDB_REGS->db_fr.fr_pc = tf32->fr_pc; |
393 | } | | 393 | } |
394 | #endif | | 394 | #endif |
395 | | | 395 | |
396 | if (fplwp) { | | 396 | if (fplwp) { |
397 | savefpstate(fplwp->l_md.md_fpstate); | | 397 | savefpstate(fplwp->l_md.md_fpstate); |
398 | DDB_REGS->db_fpstate = *fplwp->l_md.md_fpstate; | | 398 | DDB_REGS->db_fpstate = *fplwp->l_md.md_fpstate; |
399 | loadfpstate(fplwp->l_md.md_fpstate); | | 399 | loadfpstate(fplwp->l_md.md_fpstate); |
400 | } | | 400 | } |
401 | /* We should do a proper copyin and xlate 64-bit stack frames, but... */ | | 401 | /* We should do a proper copyin and xlate 64-bit stack frames, but... */ |
402 | /* if (tf->tf_tstate & TSTATE_PRIV) { .. } */ | | 402 | /* if (tf->tf_tstate & TSTATE_PRIV) { .. } */ |
403 | | | 403 | |
404 | #if 0 | | 404 | #if 0 |
405 | /* make sure this is not causing ddb problems. */ | | 405 | /* make sure this is not causing ddb problems. */ |
406 | if (tf->tf_out[6] & 1) { | | 406 | if (tf->tf_out[6] & 1) { |
407 | if ((unsigned)(tf->tf_out[6] + BIAS) > (unsigned)KERNBASE) | | 407 | if ((unsigned)(tf->tf_out[6] + BIAS) > (unsigned)KERNBASE) |
408 | DDB_REGS->db_fr = *(struct frame64 *)(tf->tf_out[6] + BIAS); | | 408 | DDB_REGS->db_fr = *(struct frame64 *)(tf->tf_out[6] + BIAS); |
409 | else | | 409 | else |
410 | copyin((void *)(tf->tf_out[6] + BIAS), &DDB_REGS->db_fr, sizeof(struct frame64)); | | 410 | copyin((void *)(tf->tf_out[6] + BIAS), &DDB_REGS->db_fr, sizeof(struct frame64)); |
411 | } else { | | 411 | } else { |
412 | struct frame32 tfr; | | 412 | struct frame32 tfr; |
413 | int i; | | 413 | int i; |
414 | | | 414 | |
415 | /* First get a local copy of the frame32 */ | | 415 | /* First get a local copy of the frame32 */ |
416 | if ((unsigned)(tf->tf_out[6]) > (unsigned)KERNBASE) | | 416 | if ((unsigned)(tf->tf_out[6]) > (unsigned)KERNBASE) |
417 | tfr = *(struct frame32 *)tf->tf_out[6]; | | 417 | tfr = *(struct frame32 *)tf->tf_out[6]; |
418 | else | | 418 | else |
419 | copyin((void *)(tf->tf_out[6]), &tfr, sizeof(struct frame32)); | | 419 | copyin((void *)(tf->tf_out[6]), &tfr, sizeof(struct frame32)); |
420 | /* Now copy each field from the 32-bit value to the 64-bit value */ | | 420 | /* Now copy each field from the 32-bit value to the 64-bit value */ |
421 | for (i=0; i<8; i++) | | 421 | for (i=0; i<8; i++) |
422 | DDB_REGS->db_fr.fr_local[i] = tfr.fr_local[i]; | | 422 | DDB_REGS->db_fr.fr_local[i] = tfr.fr_local[i]; |
423 | for (i=0; i<6; i++) | | 423 | for (i=0; i<6; i++) |
424 | DDB_REGS->db_fr.fr_arg[i] = tfr.fr_arg[i]; | | 424 | DDB_REGS->db_fr.fr_arg[i] = tfr.fr_arg[i]; |
425 | DDB_REGS->db_fr.fr_fp = (long)tfr.fr_fp; | | 425 | DDB_REGS->db_fr.fr_fp = (long)tfr.fr_fp; |
426 | DDB_REGS->db_fr.fr_pc = tfr.fr_pc; | | 426 | DDB_REGS->db_fr.fr_pc = tfr.fr_pc; |
427 | } | | 427 | } |
428 | #endif | | 428 | #endif |
429 | DDB_REGS->db_tl = savetstate(&DDB_REGS->db_ts[0]); | | 429 | DDB_REGS->db_tl = savetstate(&DDB_REGS->db_ts[0]); |
430 | } | | 430 | } |
431 | | | 431 | |
432 | void | | 432 | void |
433 | ddb_restore_state(void) | | 433 | ddb_restore_state(void) |
434 | { | | 434 | { |
435 | extern void restoretstate(int, struct trapstate *); | | 435 | extern void restoretstate(int, struct trapstate *); |
436 | | | 436 | |
437 | restoretstate(DDB_REGS->db_tl, &DDB_REGS->db_ts[0]); | | 437 | restoretstate(DDB_REGS->db_tl, &DDB_REGS->db_ts[0]); |
438 | if (fplwp) { | | 438 | if (fplwp) { |
439 | *fplwp->l_md.md_fpstate = DDB_REGS->db_fpstate; | | 439 | *fplwp->l_md.md_fpstate = DDB_REGS->db_fpstate; |
440 | loadfpstate(fplwp->l_md.md_fpstate); | | 440 | loadfpstate(fplwp->l_md.md_fpstate); |
441 | } | | 441 | } |
442 | } | | 442 | } |
443 | | | 443 | |
444 | /* | | 444 | /* |
445 | * kdb_trap - field a TRACE or BPT trap | | 445 | * kdb_trap - field a TRACE or BPT trap |
446 | */ | | 446 | */ |
447 | int | | 447 | int |
448 | kdb_trap(int type, struct trapframe64 *tf) | | 448 | kdb_trap(int type, struct trapframe64 *tf) |
449 | { | | 449 | { |
450 | int s; | | 450 | int s; |
451 | extern int trap_trace_dis; | | 451 | extern int trap_trace_dis; |
452 | extern int doing_shutdown; | | 452 | extern int doing_shutdown; |
453 | | | 453 | |
454 | trap_trace_dis++; | | 454 | trap_trace_dis++; |
455 | doing_shutdown++; | | 455 | doing_shutdown++; |
456 | #if NFB > 0 | | 456 | #if NFB > 0 |
457 | fb_unblank(); | | 457 | fb_unblank(); |
458 | #endif | | 458 | #endif |
459 | switch (type) { | | 459 | switch (type) { |
460 | case T_BREAKPOINT: /* breakpoint */ | | 460 | case T_BREAKPOINT: /* breakpoint */ |
461 | break; | | 461 | break; |
462 | case -1: /* keyboard interrupt */ | | 462 | case -1: /* keyboard interrupt */ |
463 | printf("kdb tf=%p\n", tf); | | 463 | printf("kdb tf=%p\n", tf); |
464 | break; | | 464 | break; |
465 | default: | | 465 | default: |
466 | if (!db_onpanic && db_recover==0) | | 466 | if (!db_onpanic && db_recover==0) |
467 | return (0); | | 467 | return (0); |
468 | | | 468 | |
469 | printf("kernel trap %x: %s\n", type, trap_type[type & 0x1ff]); | | 469 | printf("kernel trap %x: %s\n", type, trap_type[type & 0x1ff]); |
470 | if (db_recover != 0) { | | 470 | if (db_recover != 0) { |
471 | prom_abort(); | | 471 | prom_abort(); |
472 | db_error("Faulted in DDB; continuing...\n"); | | 472 | db_error("Faulted in DDB; continuing...\n"); |
473 | prom_abort(); | | 473 | prom_abort(); |
474 | /*NOTREACHED*/ | | 474 | /*NOTREACHED*/ |
475 | } | | 475 | } |
476 | db_recover = (label_t *)1; | | 476 | db_recover = (label_t *)1; |
477 | } | | 477 | } |
478 | | | 478 | |
479 | /* Should switch to kdb`s own stack here. */ | | 479 | /* Should switch to kdb`s own stack here. */ |
480 | write_all_windows(); | | 480 | write_all_windows(); |
481 | | | 481 | |
482 | #if defined(MULTIPROCESSOR) | | 482 | #if defined(MULTIPROCESSOR) |
483 | if (!db_suspend_others()) { | | 483 | if (!db_suspend_others()) { |
484 | ddb_suspend(tf); | | 484 | ddb_suspend(tf); |
485 | return 1; | | 485 | return 1; |
486 | } | | 486 | } |
487 | #endif | | 487 | #endif |
488 | | | 488 | |
489 | /* Initialise local dbregs storage from trap frame */ | | 489 | /* Initialise local dbregs storage from trap frame */ |
490 | fill_ddb_regs_from_tf(tf); | | 490 | fill_ddb_regs_from_tf(tf); |
491 | | | 491 | |
492 | s = splhigh(); | | 492 | s = splhigh(); |
493 | db_active++; | | 493 | db_active++; |
494 | cnpollc(TRUE); | | 494 | cnpollc(TRUE); |
495 | /* Need to do spl stuff till cnpollc works */ | | 495 | /* Need to do spl stuff till cnpollc works */ |
496 | db_dump_ts(0, 0, 0, 0); | | 496 | db_dump_ts(0, 0, 0, 0); |
497 | db_trap(type, 0/*code*/); | | 497 | db_trap(type, 0/*code*/); |
498 | ddb_restore_state(); | | 498 | ddb_restore_state(); |
499 | cnpollc(FALSE); | | 499 | cnpollc(FALSE); |
500 | db_active--; | | 500 | db_active--; |
501 | | | 501 | |
502 | splx(s); | | 502 | splx(s); |
503 | | | 503 | |
504 | *tf = DDB_REGS->db_tf; | | 504 | *tf = DDB_REGS->db_tf; |
505 | curcpu()->ci_ddb_regs = NULL; | | 505 | curcpu()->ci_ddb_regs = NULL; |
506 | | | 506 | |
507 | trap_trace_dis--; | | 507 | trap_trace_dis--; |
508 | doing_shutdown--; | | 508 | doing_shutdown--; |
509 | | | 509 | |
510 | #if defined(MULTIPROCESSOR) | | 510 | #if defined(MULTIPROCESSOR) |
511 | db_resume_others(); | | 511 | db_resume_others(); |
512 | #endif | | 512 | #endif |
513 | | | 513 | |
514 | return (1); | | 514 | return (1); |
515 | } | | 515 | } |
516 | #endif /* DDB */ | | 516 | #endif /* DDB */ |
517 | | | 517 | |
518 | /* | | 518 | /* |
519 | * Read bytes from kernel address space for debugger. | | 519 | * Read bytes from kernel address space for debugger. |
520 | */ | | 520 | */ |
521 | void | | 521 | void |
522 | db_read_bytes(db_addr_t addr, size_t size, char *data) | | 522 | db_read_bytes(db_addr_t addr, size_t size, char *data) |
523 | { | | 523 | { |
524 | char *src; | | 524 | char *src; |
525 | | | 525 | |
526 | src = (char *)(uintptr_t)addr; | | 526 | src = (char *)(uintptr_t)addr; |
527 | while (size-- > 0) { | | 527 | while (size-- > 0) { |
528 | if (src >= (char *)VM_MIN_KERNEL_ADDRESS) | | 528 | if (src >= (char *)VM_MIN_KERNEL_ADDRESS) |
529 | *data++ = probeget((paddr_t)(u_long)src++, ASI_P, 1); | | 529 | *data++ = probeget((paddr_t)(u_long)src++, ASI_P, 1); |
530 | else | | 530 | else |
531 | *data++ = fubyte(src++); | | 531 | *data++ = fubyte(src++); |
532 | } | | 532 | } |
533 | } | | 533 | } |
534 | | | 534 | |
535 | | | 535 | |
536 | /* | | 536 | /* |
537 | * Write bytes to kernel address space for debugger. | | 537 | * Write bytes to kernel address space for debugger. |
538 | */ | | 538 | */ |
539 | void | | 539 | void |
540 | db_write_bytes(db_addr_t addr, size_t size, const char *data) | | 540 | db_write_bytes(db_addr_t addr, size_t size, const char *data) |
541 | { | | 541 | { |
542 | char *dst; | | 542 | char *dst; |
543 | extern paddr_t pmap_kextract(vaddr_t va); | | 543 | extern paddr_t pmap_kextract(vaddr_t va); |
544 | | | 544 | |
545 | dst = (char *)(uintptr_t)addr; | | 545 | dst = (char *)(uintptr_t)addr; |
546 | while (size-- > 0) { | | 546 | while (size-- > 0) { |
547 | if ((dst >= (char *)VM_MIN_KERNEL_ADDRESS+0x400000)) | | 547 | if ((dst >= (char *)VM_MIN_KERNEL_ADDRESS+0x400000)) |
548 | *dst = *data; | | 548 | *dst = *data; |
549 | else if ((dst >= (char *)VM_MIN_KERNEL_ADDRESS) && | | 549 | else if ((dst >= (char *)VM_MIN_KERNEL_ADDRESS) && |
550 | (dst < (char *)VM_MIN_KERNEL_ADDRESS+0x400000)) | | 550 | (dst < (char *)VM_MIN_KERNEL_ADDRESS+0x400000)) |
551 | /* Read Only mapping -- need to do a bypass access */ | | 551 | /* Read Only mapping -- need to do a bypass access */ |
552 | stba(pmap_kextract((vaddr_t)dst), ASI_PHYS_CACHED, *data); | | 552 | stba(pmap_kextract((vaddr_t)dst), ASI_PHYS_CACHED, *data); |
553 | else | | 553 | else |
554 | subyte(dst, *data); | | 554 | subyte(dst, *data); |
555 | dst++, data++; | | 555 | dst++, data++; |
556 | } | | 556 | } |
557 | | | 557 | |
558 | } | | 558 | } |
559 | | | 559 | |
560 | #ifdef DDB | | 560 | #ifdef DDB |
561 | void | | 561 | void |
562 | Debugger(void) | | 562 | Debugger(void) |
563 | { | | 563 | { |
564 | /* We use the breakpoint to trap into DDB */ | | 564 | /* We use the breakpoint to trap into DDB */ |
565 | __asm("ta 1; nop"); | | 565 | __asm("ta 1; nop"); |
566 | } | | 566 | } |
567 | | | 567 | |
568 | void | | 568 | void |
569 | db_prom_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 569 | db_prom_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
570 | { | | 570 | { |
571 | prom_abort(); | | 571 | prom_abort(); |
572 | } | | 572 | } |
573 | | | 573 | |
574 | void | | 574 | void |
575 | db_dump_dtlb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 575 | db_dump_dtlb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
576 | { | | 576 | { |
577 | extern void print_dtlb(void); | | 577 | extern void print_dtlb(void); |
578 | | | 578 | |
579 | print_dtlb(); | | 579 | print_dtlb(); |
580 | } | | 580 | } |
581 | | | 581 | |
582 | void | | 582 | void |
583 | db_dump_itlb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 583 | db_dump_itlb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
584 | { | | 584 | { |
585 | extern void print_itlb(void); | | 585 | extern void print_itlb(void); |
586 | | | 586 | |
587 | print_itlb(); | | 587 | print_itlb(); |
588 | } | | 588 | } |
589 | | | 589 | |
590 | void | | 590 | void |
591 | db_pload_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 591 | db_pload_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
592 | { | | 592 | { |
593 | static paddr_t oldaddr = -1; | | 593 | static paddr_t oldaddr = -1; |
594 | int asi = ASI_PHYS_CACHED; | | 594 | int asi = ASI_PHYS_CACHED; |
595 | | | 595 | |
596 | if (!have_addr) { | | 596 | if (!have_addr) { |
597 | addr = oldaddr; | | 597 | addr = oldaddr; |
598 | } | | 598 | } |
599 | if (addr == -1) { | | 599 | if (addr == -1) { |
600 | db_printf("no address\n"); | | 600 | db_printf("no address\n"); |
601 | return; | | 601 | return; |
602 | } | | 602 | } |
603 | addr &= ~0x7; /* align */ | | 603 | addr &= ~0x7; /* align */ |
604 | { | | 604 | { |
605 | register char c; | | 605 | register char c; |
606 | register const char *cp = modif; | | 606 | register const char *cp = modif; |
607 | while ((c = *cp++) != 0) | | 607 | while ((c = *cp++) != 0) |
608 | if (c == 'u') | | 608 | if (c == 'u') |
609 | asi = ASI_AIUS; | | 609 | asi = ASI_AIUS; |
610 | } | | 610 | } |
611 | while (count--) { | | 611 | while (count--) { |
612 | if (db_print_position() == 0) { | | 612 | if (db_print_position() == 0) { |
613 | /* Always print the address. */ | | 613 | /* Always print the address. */ |
614 | db_printf("%16.16lx:\t", (long)addr); | | 614 | db_printf("%16.16lx:\t", (long)addr); |
615 | } | | 615 | } |
616 | oldaddr=addr; | | 616 | oldaddr=addr; |
617 | db_printf("%8.8lx\n", (long)ldxa(addr, asi)); | | 617 | db_printf("%8.8lx\n", (long)ldxa(addr, asi)); |
618 | addr += 8; | | 618 | addr += 8; |
619 | if (db_print_position() != 0) | | 619 | if (db_print_position() != 0) |
620 | db_end_line(); | | 620 | db_end_line(); |
621 | } | | 621 | } |
622 | } | | 622 | } |
623 | | | 623 | |
624 | int64_t pseg_get(struct pmap *, vaddr_t); | | 624 | int64_t pseg_get(struct pmap *, vaddr_t); |
625 | | | 625 | |
626 | void | | 626 | void |
627 | db_dump_pmap(struct pmap *pm) | | 627 | db_dump_pmap(struct pmap *pm) |
628 | { | | 628 | { |
629 | /* print all valid pages in the kernel pmap */ | | 629 | /* print all valid pages in the kernel pmap */ |
630 | unsigned long long i, j, k, n, data0, data1; | | 630 | unsigned long long i, j, k, n, data0, data1; |
631 | paddr_t *pdir, *ptbl; | | 631 | paddr_t *pdir, *ptbl; |
632 | | | 632 | |
633 | n = 0; | | 633 | n = 0; |
634 | for (i = 0; i < STSZ; i++) { | | 634 | for (i = 0; i < STSZ; i++) { |
635 | pdir = (paddr_t *)(u_long)ldxa((vaddr_t)&pm->pm_segs[i], ASI_PHYS_CACHED); | | 635 | pdir = (paddr_t *)(u_long)ldxa((vaddr_t)&pm->pm_segs[i], ASI_PHYS_CACHED); |
636 | if (!pdir) { | | 636 | if (!pdir) { |
637 | continue; | | 637 | continue; |
638 | } | | 638 | } |
639 | db_printf("pdir %lld at %lx:\n", i, (long)pdir); | | 639 | db_printf("pdir %lld at %lx:\n", i, (long)pdir); |
640 | for (k = 0; k < PDSZ; k++) { | | 640 | for (k = 0; k < PDSZ; k++) { |
641 | ptbl = (paddr_t *)(u_long)ldxa((vaddr_t)&pdir[k], ASI_PHYS_CACHED); | | 641 | ptbl = (paddr_t *)(u_long)ldxa((vaddr_t)&pdir[k], ASI_PHYS_CACHED); |
642 | if (!ptbl) { | | 642 | if (!ptbl) { |
643 | continue; | | 643 | continue; |
644 | } | | 644 | } |
645 | db_printf("\tptable %lld:%lld at %lx:\n", i, k, (long)ptbl); | | 645 | db_printf("\tptable %lld:%lld at %lx:\n", i, k, (long)ptbl); |
646 | for (j = 0; j < PTSZ; j++) { | | 646 | for (j = 0; j < PTSZ; j++) { |
647 | data0 = ldxa((vaddr_t)&ptbl[j], ASI_PHYS_CACHED); | | 647 | data0 = ldxa((vaddr_t)&ptbl[j], ASI_PHYS_CACHED); |
648 | j++; | | 648 | j++; |
649 | data1 = ldxa((vaddr_t)&ptbl[j], ASI_PHYS_CACHED); | | 649 | data1 = ldxa((vaddr_t)&ptbl[j], ASI_PHYS_CACHED); |
650 | if (!data0 && !data1) { | | 650 | if (!data0 && !data1) { |
651 | continue; | | 651 | continue; |
652 | } | | 652 | } |
653 | db_printf("%016llx: %016llx\t", | | 653 | db_printf("%016llx: %016llx\t", |
654 | (i << STSHIFT) | (k << PDSHIFT) | ((j - 1) << PTSHIFT), | | 654 | (i << STSHIFT) | (k << PDSHIFT) | ((j - 1) << PTSHIFT), |
655 | data0); | | 655 | data0); |
656 | db_printf("%016llx: %016llx\n", | | 656 | db_printf("%016llx: %016llx\n", |
657 | (i << STSHIFT) | (k << PDSHIFT) | (j << PTSHIFT), | | 657 | (i << STSHIFT) | (k << PDSHIFT) | (j << PTSHIFT), |
658 | data1); | | 658 | data1); |
659 | } | | 659 | } |
660 | } | | 660 | } |
661 | } | | 661 | } |
662 | } | | 662 | } |
663 | | | 663 | |
664 | void | | 664 | void |
665 | db_pmap_kernel(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 665 | db_pmap_kernel(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
666 | { | | 666 | { |
667 | int i, j, full = 0; | | 667 | int i, j, full = 0; |
668 | uint64_t data; | | 668 | uint64_t data; |
669 | | | 669 | |
670 | { | | 670 | { |
671 | register char c; | | 671 | register char c; |
672 | register const char *cp = modif; | | 672 | register const char *cp = modif; |
673 | while ((c = *cp++) != 0) | | 673 | while ((c = *cp++) != 0) |
674 | if (c == 'f') | | 674 | if (c == 'f') |
675 | full = 1; | | 675 | full = 1; |
676 | } | | 676 | } |
677 | if (have_addr) { | | 677 | if (have_addr) { |
678 | /* lookup an entry for this VA */ | | 678 | /* lookup an entry for this VA */ |
679 | | | 679 | |
680 | if ((data = pseg_get(pmap_kernel(), (vaddr_t)addr))) { | | 680 | if ((data = pseg_get(pmap_kernel(), (vaddr_t)addr))) { |
681 | db_printf("pmap_kernel(%p)->pm_segs[%lx][%lx][%lx]=>%qx\n", | | 681 | db_printf("pmap_kernel(%p)->pm_segs[%lx][%lx][%lx]=>%qx\n", |
682 | (void *)(uintptr_t)addr, (u_long)va_to_seg(addr), | | 682 | (void *)(uintptr_t)addr, (u_long)va_to_seg(addr), |
683 | (u_long)va_to_dir(addr), (u_long)va_to_pte(addr), | | 683 | (u_long)va_to_dir(addr), (u_long)va_to_pte(addr), |
684 | (unsigned long long)data); | | 684 | (unsigned long long)data); |
685 | } else { | | 685 | } else { |
686 | db_printf("No mapping for %p\n", (void *)(uintptr_t)addr); | | 686 | db_printf("No mapping for %p\n", (void *)(uintptr_t)addr); |
687 | } | | 687 | } |
688 | return; | | 688 | return; |
689 | } | | 689 | } |
690 | | | 690 | |
691 | db_printf("pmap_kernel(%p) psegs %p phys %llx\n", | | 691 | db_printf("pmap_kernel(%p) psegs %p phys %llx\n", |
692 | pmap_kernel(), pmap_kernel()->pm_segs, | | 692 | pmap_kernel(), pmap_kernel()->pm_segs, |
693 | (unsigned long long)pmap_kernel()->pm_physaddr); | | 693 | (unsigned long long)pmap_kernel()->pm_physaddr); |
694 | if (full) { | | 694 | if (full) { |
695 | db_dump_pmap(pmap_kernel()); | | 695 | db_dump_pmap(pmap_kernel()); |
696 | } else { | | 696 | } else { |
697 | for (j=i=0; i<STSZ; i++) { | | 697 | for (j=i=0; i<STSZ; i++) { |
698 | long seg = (long)ldxa((vaddr_t)pmap_kernel()->pm_segs[i], ASI_PHYS_CACHED); | | 698 | long seg = (long)ldxa((vaddr_t)pmap_kernel()->pm_segs[i], ASI_PHYS_CACHED); |
699 | if (seg) | | 699 | if (seg) |
700 | db_printf("seg %d => %lx%c", i, seg, (j++%4)?'\t':'\n'); | | 700 | db_printf("seg %d => %lx%c", i, seg, (j++%4)?'\t':'\n'); |
701 | } | | 701 | } |
702 | } | | 702 | } |
703 | } | | 703 | } |
704 | | | 704 | |
705 | void | | 705 | void |
706 | db_pm_extract(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 706 | db_pm_extract(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
707 | { | | 707 | { |
708 | if (have_addr) { | | 708 | if (have_addr) { |
709 | paddr_t pa; | | 709 | paddr_t pa; |
710 | | | 710 | |
711 | if (pmap_extract(pmap_kernel(), addr, &pa)) | | 711 | if (pmap_extract(pmap_kernel(), addr, &pa)) |
712 | db_printf("pa = %llx\n", (long long)pa); | | 712 | db_printf("pa = %llx\n", (long long)pa); |
713 | else | | 713 | else |
714 | db_printf("%p not found\n", (void *)(uintptr_t)addr); | | 714 | db_printf("%p not found\n", (void *)(uintptr_t)addr); |
715 | } else | | 715 | } else |
716 | db_printf("pmap_extract: no address\n"); | | 716 | db_printf("pmap_extract: no address\n"); |
717 | } | | 717 | } |
718 | | | 718 | |
719 | void | | 719 | void |
720 | db_pmap_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 720 | db_pmap_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
721 | { | | 721 | { |
722 | struct pmap* pm=NULL; | | 722 | struct pmap* pm=NULL; |
723 | int i, j=0, full = 0; | | 723 | int i, j=0, full = 0; |
724 | | | 724 | |
725 | { | | 725 | { |
726 | register char c; | | 726 | register char c; |
727 | register const char *cp = modif; | | 727 | register const char *cp = modif; |
728 | if (modif) | | 728 | if (modif) |
729 | while ((c = *cp++) != 0) | | 729 | while ((c = *cp++) != 0) |
730 | if (c == 'f') | | 730 | if (c == 'f') |
731 | full = 1; | | 731 | full = 1; |
732 | } | | 732 | } |
733 | if (curlwp && curlwp->l_proc->p_vmspace) | | 733 | if (curlwp && curlwp->l_proc->p_vmspace) |
734 | pm = curlwp->l_proc->p_vmspace->vm_map.pmap; | | 734 | pm = curlwp->l_proc->p_vmspace->vm_map.pmap; |
735 | if (have_addr) | | 735 | if (have_addr) |
736 | pm = (struct pmap*)(uintptr_t)addr; | | 736 | pm = (struct pmap*)(uintptr_t)addr; |
737 | | | 737 | |
738 | db_printf("pmap %p: ctx %x refs %d physaddr %llx psegs %p\n", | | 738 | db_printf("pmap %p: ctx %x refs %d physaddr %llx psegs %p\n", |
739 | pm, pmap_ctx(pm), pm->pm_refs, | | 739 | pm, pmap_ctx(pm), pm->pm_refs, |
740 | (unsigned long long)pm->pm_physaddr, pm->pm_segs); | | 740 | (unsigned long long)pm->pm_physaddr, pm->pm_segs); |
741 | | | 741 | |
742 | if (full) { | | 742 | if (full) { |
743 | db_dump_pmap(pm); | | 743 | db_dump_pmap(pm); |
744 | } else { | | 744 | } else { |
745 | for (i=0; i<STSZ; i++) { | | 745 | for (i=0; i<STSZ; i++) { |
746 | long seg = (long)ldxa((vaddr_t)pmap_kernel()->pm_segs[i], ASI_PHYS_CACHED); | | 746 | long seg = (long)ldxa((vaddr_t)pmap_kernel()->pm_segs[i], ASI_PHYS_CACHED); |
747 | if (seg) | | 747 | if (seg) |
748 | db_printf("seg %d => %lx%c", i, seg, (j++%4)?'\t':'\n'); | | 748 | db_printf("seg %d => %lx%c", i, seg, (j++%4)?'\t':'\n'); |
749 | } | | 749 | } |
750 | } | | 750 | } |
751 | } | | 751 | } |
752 | | | 752 | |
753 | #define TSBENTS (512 << tsbsize) | | 753 | #define TSBENTS (512 << tsbsize) |
754 | extern pte_t *tsb_dmmu, *tsb_immu; | | 754 | extern pte_t *tsb_dmmu, *tsb_immu; |
755 | extern int tsbsize; | | 755 | extern int tsbsize; |
756 | | | 756 | |
757 | void db_dump_tsb_common(pte_t *); | | 757 | void db_dump_tsb_common(pte_t *); |
758 | | | 758 | |
759 | void | | 759 | void |
760 | db_dump_dtsb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 760 | db_dump_dtsb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
761 | { | | 761 | { |
762 | | | 762 | |
763 | db_printf("DTSB:\n"); | | 763 | db_printf("DTSB:\n"); |
764 | db_dump_tsb_common(curcpu()->ci_tsb_dmmu); | | 764 | db_dump_tsb_common(curcpu()->ci_tsb_dmmu); |
765 | } | | 765 | } |
766 | | | 766 | |
767 | void | | 767 | void |
768 | db_dump_itsb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 768 | db_dump_itsb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
769 | { | | 769 | { |
770 | | | 770 | |
771 | db_printf("ITSB:\n"); | | 771 | db_printf("ITSB:\n"); |
772 | db_dump_tsb_common(curcpu()->ci_tsb_immu); | | 772 | db_dump_tsb_common(curcpu()->ci_tsb_immu); |
773 | } | | 773 | } |
774 | | | 774 | |
775 | void | | 775 | void |
776 | db_dump_tsb_common(pte_t *tsb) | | 776 | db_dump_tsb_common(pte_t *tsb) |
777 | { | | 777 | { |
778 | uint64_t tag, data; | | 778 | uint64_t tag, data; |
779 | int i; | | 779 | int i; |
780 | | | 780 | |
781 | for (i = 0; i < TSBENTS; i++) { | | 781 | for (i = 0; i < TSBENTS; i++) { |
782 | tag = tsb[i].tag; | | 782 | tag = tsb[i].tag; |
783 | data = tsb[i].data; | | 783 | data = tsb[i].data; |
784 | db_printf("%4d:%4d:%08x %08x:%08x ", i, | | 784 | db_printf("%4d:%4d:%08x %08x:%08x ", i, |
785 | (int)((tag & TSB_TAG_G) ? -1 : TSB_TAG_CTX(tag)), | | 785 | (int)((tag & TSB_TAG_G) ? -1 : TSB_TAG_CTX(tag)), |
786 | (int)((i << 13) | TSB_TAG_VA(tag)), | | 786 | (int)((i << 13) | TSB_TAG_VA(tag)), |
787 | (int)(data >> 32), (int)data); | | 787 | (int)(data >> 32), (int)data); |
788 | i++; | | 788 | i++; |
789 | tag = tsb[i].tag; | | 789 | tag = tsb[i].tag; |
790 | data = tsb[i].data; | | 790 | data = tsb[i].data; |
791 | db_printf("%4d:%4d:%08x %08x:%08x\n", i, | | 791 | db_printf("%4d:%4d:%08x %08x:%08x\n", i, |
792 | (int)((tag & TSB_TAG_G) ? -1 : TSB_TAG_CTX(tag)), | | 792 | (int)((tag & TSB_TAG_G) ? -1 : TSB_TAG_CTX(tag)), |
793 | (int)((i << 13) | TSB_TAG_VA(tag)), | | 793 | (int)((i << 13) | TSB_TAG_VA(tag)), |
794 | (int)(data >> 32), (int)data); | | 794 | (int)(data >> 32), (int)data); |
795 | } | | 795 | } |
796 | } | | 796 | } |
797 | | | 797 | |
798 | void db_page_cmd(db_expr_t, bool, db_expr_t, const char *); | | 798 | void db_page_cmd(db_expr_t, bool, db_expr_t, const char *); |
799 | void | | 799 | void |
800 | db_page_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 800 | db_page_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
801 | { | | 801 | { |
802 | | | 802 | |
803 | if (!have_addr) { | | 803 | if (!have_addr) { |
804 | db_printf("Need paddr for page\n"); | | 804 | db_printf("Need paddr for page\n"); |
805 | return; | | 805 | return; |
806 | } | | 806 | } |
807 | | | 807 | |
808 | db_printf("pa %llx pg %p\n", (unsigned long long)addr, | | 808 | db_printf("pa %llx pg %p\n", (unsigned long long)addr, |
809 | PHYS_TO_VM_PAGE(addr)); | | 809 | PHYS_TO_VM_PAGE(addr)); |
810 | } | | 810 | } |
811 | | | 811 | |
812 | void | | 812 | void |
813 | db_lwp_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 813 | db_lwp_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
814 | { | | 814 | { |
815 | struct lwp *l; | | 815 | struct lwp *l; |
816 | | | 816 | |
817 | l = curlwp; | | 817 | l = curlwp; |
818 | if (have_addr) | | 818 | if (have_addr) |
819 | l = (struct lwp*)(uintptr_t)addr; | | 819 | l = (struct lwp*)(uintptr_t)addr; |
820 | if (l == NULL) { | | 820 | if (l == NULL) { |
821 | db_printf("no current lwp\n"); | | 821 | db_printf("no current lwp\n"); |
822 | return; | | 822 | return; |
823 | } | | 823 | } |
824 | db_printf("lwp %p: lid %d\n", l, l->l_lid); | | 824 | db_printf("lwp %p: lid %d\n", l, l->l_lid); |
825 | db_printf("wchan:%p pri:%d epri:%d tf:%p\n", | | 825 | db_printf("wchan:%p pri:%d epri:%d tf:%p\n", |
826 | l->l_wchan, l->l_priority, lwp_eprio(l), l->l_md.md_tf); | | 826 | l->l_wchan, l->l_priority, lwp_eprio(l), l->l_md.md_tf); |
827 | db_printf("pcb: %p fpstate: %p\n", lwp_getpcb(l), | | 827 | db_printf("pcb: %p fpstate: %p\n", lwp_getpcb(l), |
828 | l->l_md.md_fpstate); | | 828 | l->l_md.md_fpstate); |
829 | return; | | 829 | return; |
830 | } | | 830 | } |
831 | | | 831 | |
832 | void | | 832 | void |
833 | db_proc_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 833 | db_proc_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
834 | { | | 834 | { |
835 | struct proc *p = NULL; | | 835 | struct proc *p = NULL; |
836 | | | 836 | |
837 | if (curlwp) | | 837 | if (curlwp) |
838 | p = curlwp->l_proc; | | 838 | p = curlwp->l_proc; |
839 | if (have_addr) | | 839 | if (have_addr) |
840 | p = (struct proc*)(uintptr_t)addr; | | 840 | p = (struct proc*)(uintptr_t)addr; |
841 | if (p == NULL) { | | 841 | if (p == NULL) { |
842 | db_printf("no current process\n"); | | 842 | db_printf("no current process\n"); |
843 | return; | | 843 | return; |
844 | } | | 844 | } |
845 | db_printf("process %p:", p); | | 845 | db_printf("process %p:", p); |
846 | db_printf("pid:%d vmspace:%p pmap:%p ctx:%x\n", | | 846 | db_printf("pid:%d vmspace:%p pmap:%p ctx:%x\n", |
847 | p->p_pid, p->p_vmspace, p->p_vmspace->vm_map.pmap, | | 847 | p->p_pid, p->p_vmspace, p->p_vmspace->vm_map.pmap, |
848 | pmap_ctx(p->p_vmspace->vm_map.pmap)); | | 848 | pmap_ctx(p->p_vmspace->vm_map.pmap)); |
849 | db_printf("maxsaddr:%p ssiz:%dpg or %llxB\n", | | 849 | db_printf("maxsaddr:%p ssiz:%dpg or %llxB\n", |
850 | p->p_vmspace->vm_maxsaddr, p->p_vmspace->vm_ssize, | | 850 | p->p_vmspace->vm_maxsaddr, p->p_vmspace->vm_ssize, |
851 | (unsigned long long)ctob(p->p_vmspace->vm_ssize)); | | 851 | (unsigned long long)ctob(p->p_vmspace->vm_ssize)); |
852 | db_printf("profile timer: %" PRId64 " sec %ld nsec\n", | | 852 | db_printf("profile timer: %" PRId64 " sec %ld nsec\n", |
853 | p->p_stats->p_timer[ITIMER_PROF].it_value.tv_sec, | | 853 | p->p_stats->p_timer[ITIMER_PROF].it_value.tv_sec, |
854 | p->p_stats->p_timer[ITIMER_PROF].it_value.tv_nsec); | | 854 | p->p_stats->p_timer[ITIMER_PROF].it_value.tv_nsec); |
855 | return; | | 855 | return; |
856 | } | | 856 | } |
857 | | | 857 | |
858 | void | | 858 | void |
859 | db_ctx_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 859 | db_ctx_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
860 | { | | 860 | { |
861 | struct proc *p; | | 861 | struct proc *p; |
862 | struct lwp *l; | | 862 | struct lwp *l; |
863 | struct pcb *pcb; | | 863 | struct pcb *pcb; |
864 | | | 864 | |
865 | /* XXX LOCKING XXX */ | | 865 | /* XXX LOCKING XXX */ |
866 | LIST_FOREACH(p, &allproc, p_list) { | | 866 | LIST_FOREACH(p, &allproc, p_list) { |
867 | if (p->p_stat) { | | 867 | if (p->p_stat) { |
868 | db_printf("process %p:", p); | | 868 | db_printf("process %p:", p); |
869 | db_printf("pid:%d pmap:%p ctx:%x\n", | | 869 | db_printf("pid:%d pmap:%p ctx:%x\n", |
870 | p->p_pid, p->p_vmspace->vm_map.pmap, | | 870 | p->p_pid, p->p_vmspace->vm_map.pmap, |
871 | pmap_ctx(p->p_vmspace->vm_map.pmap)); | | 871 | pmap_ctx(p->p_vmspace->vm_map.pmap)); |
872 | LIST_FOREACH(l, &p->p_lwps, l_sibling) { | | 872 | LIST_FOREACH(l, &p->p_lwps, l_sibling) { |
873 | pcb = lwp_getpcb(l); | | 873 | pcb = lwp_getpcb(l); |
874 | db_printf("\tlwp %p: lid:%d tf:%p fpstate %p " | | 874 | db_printf("\tlwp %p: lid:%d tf:%p fpstate %p " |
875 | "lastcall:%s\n", | | 875 | "lastcall:%s\n", |
876 | l, l->l_lid, l->l_md.md_tf, l->l_md.md_fpstate, | | 876 | l, l->l_lid, l->l_md.md_tf, l->l_md.md_fpstate, |
877 | (pcb->lastcall) ? | | 877 | (pcb->lastcall) ? |
878 | pcb->lastcall : "Null"); | | 878 | pcb->lastcall : "Null"); |
879 | } | | 879 | } |
880 | } | | 880 | } |
881 | } | | 881 | } |
882 | return; | | 882 | return; |
883 | } | | 883 | } |
884 | | | 884 | |
885 | void | | 885 | void |
886 | db_dump_pcb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 886 | db_dump_pcb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
887 | { | | 887 | { |
888 | struct pcb *pcb; | | 888 | struct pcb *pcb; |
889 | int i; | | 889 | int i; |
890 | | | 890 | |
891 | pcb = curpcb; | | 891 | pcb = curpcb; |
892 | if (have_addr) | | 892 | if (have_addr) |
893 | pcb = (struct pcb*)(uintptr_t)addr; | | 893 | pcb = (struct pcb*)(uintptr_t)addr; |
894 | | | 894 | |
895 | db_printf("pcb@%p sp:%p pc:%p cwp:%d pil:%d nsaved:%x onfault:%p\nlastcall:%s\nfull windows:\n", | | 895 | db_printf("pcb@%p sp:%p pc:%p cwp:%d pil:%d nsaved:%x onfault:%p\nlastcall:%s\nfull windows:\n", |
896 | pcb, (void *)(long)pcb->pcb_sp, (void *)(long)pcb->pcb_pc, pcb->pcb_cwp, | | 896 | pcb, (void *)(long)pcb->pcb_sp, (void *)(long)pcb->pcb_pc, pcb->pcb_cwp, |
897 | pcb->pcb_pil, pcb->pcb_nsaved, (void *)pcb->pcb_onfault, | | 897 | pcb->pcb_pil, pcb->pcb_nsaved, (void *)pcb->pcb_onfault, |
898 | (pcb->lastcall)?pcb->lastcall:"Null"); | | 898 | (pcb->lastcall)?pcb->lastcall:"Null"); |
899 | | | 899 | |
900 | for (i=0; i<pcb->pcb_nsaved; i++) { | | 900 | for (i=0; i<pcb->pcb_nsaved; i++) { |
901 | db_printf("win %d: at %llx local, in\n", i, | | 901 | db_printf("win %d: at %llx local, in\n", i, |
902 | (unsigned long long)pcb->pcb_rw[i+1].rw_in[6]); | | 902 | (unsigned long long)pcb->pcb_rw[i+1].rw_in[6]); |
903 | db_printf("%16llx %16llx %16llx %16llx\n", | | 903 | db_printf("%16llx %16llx %16llx %16llx\n", |
904 | (unsigned long long)pcb->pcb_rw[i].rw_local[0], | | 904 | (unsigned long long)pcb->pcb_rw[i].rw_local[0], |
905 | (unsigned long long)pcb->pcb_rw[i].rw_local[1], | | 905 | (unsigned long long)pcb->pcb_rw[i].rw_local[1], |
906 | (unsigned long long)pcb->pcb_rw[i].rw_local[2], | | 906 | (unsigned long long)pcb->pcb_rw[i].rw_local[2], |
907 | (unsigned long long)pcb->pcb_rw[i].rw_local[3]); | | 907 | (unsigned long long)pcb->pcb_rw[i].rw_local[3]); |
908 | db_printf("%16llx %16llx %16llx %16llx\n", | | 908 | db_printf("%16llx %16llx %16llx %16llx\n", |
909 | (unsigned long long)pcb->pcb_rw[i].rw_local[4], | | 909 | (unsigned long long)pcb->pcb_rw[i].rw_local[4], |
910 | (unsigned long long)pcb->pcb_rw[i].rw_local[5], | | 910 | (unsigned long long)pcb->pcb_rw[i].rw_local[5], |
911 | (unsigned long long)pcb->pcb_rw[i].rw_local[6], | | 911 | (unsigned long long)pcb->pcb_rw[i].rw_local[6], |
912 | (unsigned long long)pcb->pcb_rw[i].rw_local[7]); | | 912 | (unsigned long long)pcb->pcb_rw[i].rw_local[7]); |
913 | db_printf("%16llx %16llx %16llx %16llx\n", | | 913 | db_printf("%16llx %16llx %16llx %16llx\n", |
914 | (unsigned long long)pcb->pcb_rw[i].rw_in[0], | | 914 | (unsigned long long)pcb->pcb_rw[i].rw_in[0], |
915 | (unsigned long long)pcb->pcb_rw[i].rw_in[1], | | 915 | (unsigned long long)pcb->pcb_rw[i].rw_in[1], |
916 | (unsigned long long)pcb->pcb_rw[i].rw_in[2], | | 916 | (unsigned long long)pcb->pcb_rw[i].rw_in[2], |
917 | (unsigned long long)pcb->pcb_rw[i].rw_in[3]); | | 917 | (unsigned long long)pcb->pcb_rw[i].rw_in[3]); |
918 | db_printf("%16llx %16llx %16llx %16llx\n", | | 918 | db_printf("%16llx %16llx %16llx %16llx\n", |
919 | (unsigned long long)pcb->pcb_rw[i].rw_in[4], | | 919 | (unsigned long long)pcb->pcb_rw[i].rw_in[4], |
920 | (unsigned long long)pcb->pcb_rw[i].rw_in[5], | | 920 | (unsigned long long)pcb->pcb_rw[i].rw_in[5], |
921 | (unsigned long long)pcb->pcb_rw[i].rw_in[6], | | 921 | (unsigned long long)pcb->pcb_rw[i].rw_in[6], |
922 | (unsigned long long)pcb->pcb_rw[i].rw_in[7]); | | 922 | (unsigned long long)pcb->pcb_rw[i].rw_in[7]); |
923 | } | | 923 | } |
924 | } | | 924 | } |
925 | | | 925 | |
926 | | | 926 | |
927 | void | | 927 | void |
928 | db_setpcb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 928 | db_setpcb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
929 | { | | 929 | { |
930 | struct proc *p, *pp; | | 930 | struct proc *p, *pp; |
931 | int ctx; | | 931 | int ctx; |
932 | | | 932 | |
933 | if (!have_addr) { | | 933 | if (!have_addr) { |
934 | db_printf("What PID do you want to map in?\n"); | | 934 | db_printf("What PID do you want to map in?\n"); |
935 | return; | | 935 | return; |
936 | } | | 936 | } |
937 | | | 937 | |
938 | LIST_FOREACH(p, &allproc, p_list) { | | 938 | LIST_FOREACH(p, &allproc, p_list) { |
939 | pp = p->p_pptr; | | 939 | pp = p->p_pptr; |
940 | if (p->p_stat && p->p_pid == addr) { | | 940 | if (p->p_stat && p->p_pid == addr) { |
941 | #if 0 | | 941 | #if 0 |
942 | /* XXX Do we need to do the following too?: */ | | 942 | /* XXX Do we need to do the following too?: */ |
943 | extern struct pcb *cpcb; | | 943 | extern struct pcb *cpcb; |
944 | | | 944 | |
945 | curlwp = p; | | 945 | curlwp = p; |
946 | cpcb = (struct pcb*)p->p_addr; | | 946 | cpcb = (struct pcb*)p->p_addr; |
947 | #endif | | 947 | #endif |
948 | if (p->p_vmspace->vm_map.pmap == pmap_kernel()) { | | 948 | if (p->p_vmspace->vm_map.pmap == pmap_kernel()) { |
949 | db_printf("PID %ld has a kernel context.\n", | | 949 | db_printf("PID %ld has a kernel context.\n", |
950 | (long)addr); | | 950 | (long)addr); |
951 | return; | | 951 | return; |
952 | } | | 952 | } |
953 | ctx = pmap_ctx(p->p_vmspace->vm_map.pmap); | | 953 | ctx = pmap_ctx(p->p_vmspace->vm_map.pmap); |
954 | if (ctx < 0) { | | 954 | if (ctx < 0) { |
955 | ctx = -ctx; | | 955 | ctx = -ctx; |
956 | pmap_ctx(p->p_vmspace->vm_map.pmap) = ctx; | | 956 | pmap_ctx(p->p_vmspace->vm_map.pmap) = ctx; |
957 | } else if (ctx == 0) { | | 957 | } else if (ctx == 0) { |
958 | pmap_activate_pmap(p->p_vmspace->vm_map.pmap); | | 958 | pmap_activate_pmap(p->p_vmspace->vm_map.pmap); |
959 | ctx = pmap_ctx(p->p_vmspace->vm_map.pmap); | | 959 | ctx = pmap_ctx(p->p_vmspace->vm_map.pmap); |
960 | } | | 960 | } |
961 | if (ctx > 0) { | | 961 | if (ctx > 0) { |
962 | switchtoctx(ctx); | | 962 | switchtoctx(ctx); |
963 | return; | | 963 | return; |
964 | } | | 964 | } |
965 | db_printf("could not activate pmap for PID %ld.\n", | | 965 | db_printf("could not activate pmap for PID %ld.\n", |
966 | (long)addr); | | 966 | (long)addr); |
967 | return; | | 967 | return; |
968 | } | | 968 | } |
969 | } | | 969 | } |
970 | db_printf("PID %ld not found.\n", (long)addr); | | 970 | db_printf("PID %ld not found.\n", (long)addr); |
971 | } | | 971 | } |
972 | | | 972 | |
973 | static void | | 973 | static void |
974 | db_print_trace_entry(struct traptrace *te, int i) | | 974 | db_print_trace_entry(struct traptrace *te, int i) |
975 | { | | 975 | { |
976 | db_printf("%d:%d p:%d tt:%x:%llx:%llx %llx:%llx ", i, | | 976 | db_printf("%d:%d p:%d tt:%x:%llx:%llx %llx:%llx ", i, |
977 | (int)te->tl, (int)te->pid, | | 977 | (int)te->tl, (int)te->pid, |
978 | (int)te->tt, (unsigned long long)te->tstate, | | 978 | (int)te->tt, (unsigned long long)te->tstate, |
979 | (unsigned long long)te->tfault, (unsigned long long)te->tsp, | | 979 | (unsigned long long)te->tfault, (unsigned long long)te->tsp, |
980 | (unsigned long long)te->tpc); | | 980 | (unsigned long long)te->tpc); |
981 | db_printsym((u_long)te->tpc, DB_STGY_PROC, db_printf); | | 981 | db_printsym((u_long)te->tpc, DB_STGY_PROC, db_printf); |
982 | db_printf(": "); | | 982 | db_printf(": "); |
983 | if ((te->tpc && !(te->tpc&0x3)) && | | 983 | if ((te->tpc && !(te->tpc&0x3)) && |
984 | curlwp && | | 984 | curlwp && |
985 | (curproc->p_pid == te->pid)) { | | 985 | (curproc->p_pid == te->pid)) { |
986 | db_disasm((u_long)te->tpc, 0); | | 986 | db_disasm((u_long)te->tpc, 0); |
987 | } else db_printf("\n"); | | 987 | } else db_printf("\n"); |
988 | } | | 988 | } |
989 | | | 989 | |
990 | void | | 990 | void |
991 | db_traptrace(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 991 | db_traptrace(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
992 | { | | 992 | { |
993 | int i, start = 0, full = 0, reverse = 0; | | 993 | int i, start = 0, full = 0, reverse = 0; |
994 | struct traptrace *end; | | 994 | struct traptrace *end; |
995 | | | 995 | |
996 | start = 0; | | 996 | start = 0; |
997 | end = &trap_trace_end[0]; | | 997 | end = &trap_trace_end[0]; |
998 | | | 998 | |
999 | { | | 999 | { |
1000 | register char c; | | 1000 | register char c; |
1001 | register const char *cp = modif; | | 1001 | register const char *cp = modif; |
1002 | if (modif) | | 1002 | if (modif) |
1003 | while ((c = *cp++) != 0) { | | 1003 | while ((c = *cp++) != 0) { |
1004 | if (c == 'f') | | 1004 | if (c == 'f') |
1005 | full = 1; | | 1005 | full = 1; |
1006 | if (c == 'r') | | 1006 | if (c == 'r') |
1007 | reverse = 1; | | 1007 | reverse = 1; |
1008 | } | | 1008 | } |
1009 | } | | 1009 | } |
1010 | | | 1010 | |
1011 | if (have_addr) { | | 1011 | if (have_addr) { |
1012 | start = addr / (sizeof (struct traptrace)); | | 1012 | start = addr / (sizeof (struct traptrace)); |
1013 | if (&trap_trace[start] > &trap_trace_end[0]) { | | 1013 | if (&trap_trace[start] > &trap_trace_end[0]) { |
1014 | db_printf("Address out of range.\n"); | | 1014 | db_printf("Address out of range.\n"); |
1015 | return; | | 1015 | return; |
1016 | } | | 1016 | } |
1017 | if (!full) end = &trap_trace[start+1]; | | 1017 | if (!full) end = &trap_trace[start+1]; |
1018 | } | | 1018 | } |
1019 | | | 1019 | |
1020 | db_printf("#:tl p:pid tt:tt:tstate:tfault sp:pc\n"); | | 1020 | db_printf("#:tl p:pid tt:tt:tstate:tfault sp:pc\n"); |
1021 | if (reverse) { | | 1021 | if (reverse) { |
1022 | if (full && start) | | 1022 | if (full && start) |
1023 | for (i=start; --i;) { | | 1023 | for (i=start; --i;) { |
1024 | db_print_trace_entry(&trap_trace[i], i); | | 1024 | db_print_trace_entry(&trap_trace[i], i); |
1025 | } | | 1025 | } |
1026 | i = (end - &trap_trace[0]); | | 1026 | i = (end - &trap_trace[0]); |
1027 | while(--i > start) { | | 1027 | while(--i > start) { |
1028 | db_print_trace_entry(&trap_trace[i], i); | | 1028 | db_print_trace_entry(&trap_trace[i], i); |
1029 | } | | 1029 | } |
1030 | } else { | | 1030 | } else { |
1031 | for (i=start; &trap_trace[i] < end ; i++) { | | 1031 | for (i=start; &trap_trace[i] < end ; i++) { |
1032 | db_print_trace_entry(&trap_trace[i], i); | | 1032 | db_print_trace_entry(&trap_trace[i], i); |
1033 | } | | 1033 | } |
1034 | if (full && start) | | 1034 | if (full && start) |
1035 | for (i=0; i < start ; i++) { | | 1035 | for (i=0; i < start ; i++) { |
1036 | db_print_trace_entry(&trap_trace[i], i); | | 1036 | db_print_trace_entry(&trap_trace[i], i); |
1037 | } | | 1037 | } |
1038 | } | | 1038 | } |
1039 | } | | 1039 | } |
1040 | | | 1040 | |
1041 | /* | | 1041 | /* |
1042 | * Use physical or virtul watchpoint registers -- ugh | | 1042 | * Use physical or virtul watchpoint registers -- ugh |
1043 | * | | 1043 | * |
1044 | * UltraSPARC I and II have both a virtual and physical | | 1044 | * UltraSPARC I and II have both a virtual and physical |
1045 | * watchpoint register. They are controlled by the LSU | | 1045 | * watchpoint register. They are controlled by the LSU |
1046 | * control register. | | 1046 | * control register. |
1047 | */ | | 1047 | */ |
1048 | void | | 1048 | void |
1049 | db_watch(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 1049 | db_watch(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
1050 | { | | 1050 | { |
1051 | int phys = 0; | | 1051 | int phys = 0; |
1052 | int read = 0; | | 1052 | int read = 0; |
1053 | int width = 8; /* Default to 8 bytes */ | | 1053 | int width = 8; /* Default to 8 bytes */ |
1054 | int64_t mask = 0xff; | | 1054 | int64_t mask = 0xff; |
1055 | | | 1055 | |
1056 | #define WATCH_VR (1L<<22) | | 1056 | #define WATCH_VR (1L<<22) |
1057 | #define WATCH_VW (1L<<21) | | 1057 | #define WATCH_VW (1L<<21) |
1058 | #define WATCH_PR (1L<<24) | | 1058 | #define WATCH_PR (1L<<24) |
1059 | #define WATCH_PW (1L<<23) | | 1059 | #define WATCH_PW (1L<<23) |
1060 | #define WATCH_PM_SHIFT 33 | | 1060 | #define WATCH_PM_SHIFT 33 |
1061 | #define WATCH_PM (((uint64_t)0xffffL)<<WATCH_PM_SHIFT) | | 1061 | #define WATCH_PM (((uint64_t)0xffffL)<<WATCH_PM_SHIFT) |
1062 | #define WATCH_VM_SHIFT 25 | | 1062 | #define WATCH_VM_SHIFT 25 |
1063 | #define WATCH_VM (((uint64_t)0xffffL)<<WATCH_VM_SHIFT) | | 1063 | #define WATCH_VM (((uint64_t)0xffffL)<<WATCH_VM_SHIFT) |
1064 | | | 1064 | |
1065 | { | | 1065 | { |
1066 | register char c; | | 1066 | register char c; |
1067 | register const char *cp = modif; | | 1067 | register const char *cp = modif; |
1068 | if (modif) | | 1068 | if (modif) |
1069 | while ((c = *cp++) != 0) | | 1069 | while ((c = *cp++) != 0) |
1070 | switch (c) { | | 1070 | switch (c) { |
1071 | case 'p': | | 1071 | case 'p': |
1072 | /* Physical watchpoint */ | | 1072 | /* Physical watchpoint */ |
1073 | phys = 1; | | 1073 | phys = 1; |
1074 | break; | | 1074 | break; |
1075 | case 'r': | | 1075 | case 'r': |
1076 | /* Trap reads too */ | | 1076 | /* Trap reads too */ |
1077 | read = 1; | | 1077 | read = 1; |
1078 | break; | | 1078 | break; |
1079 | case 'b': | | 1079 | case 'b': |
1080 | width = 1; | | 1080 | width = 1; |
1081 | mask = 0x1 << (addr & 0x7); | | 1081 | mask = 0x1 << (addr & 0x7); |
1082 | break; | | 1082 | break; |
1083 | case 'h': | | 1083 | case 'h': |
1084 | width = 2; | | 1084 | width = 2; |
1085 | mask = 0x3 << (addr & 0x6); | | 1085 | mask = 0x3 << (addr & 0x6); |
1086 | break; | | 1086 | break; |
1087 | case 'l': | | 1087 | case 'l': |
1088 | width = 4; | | 1088 | width = 4; |
1089 | mask = 0x7 << (addr & 0x4); | | 1089 | mask = 0x7 << (addr & 0x4); |
1090 | break; | | 1090 | break; |
1091 | case 'L': | | 1091 | case 'L': |
1092 | width = 8; | | 1092 | width = 8; |
1093 | mask = 0xf; | | 1093 | mask = 0xf; |
1094 | break; | | 1094 | break; |
1095 | default: | | 1095 | default: |
1096 | break; | | 1096 | break; |
1097 | } | | 1097 | } |
1098 | } | | 1098 | } |
1099 | | | 1099 | |
1100 | if (have_addr) { | | 1100 | if (have_addr) { |
1101 | /* turn on the watchpoint */ | | 1101 | /* turn on the watchpoint */ |
1102 | int64_t tmp = ldxa(0, ASI_MCCR); | | 1102 | int64_t tmp = ldxa(0, ASI_MCCR); |
1103 | | | 1103 | |
1104 | if (phys) { | | 1104 | if (phys) { |
1105 | tmp &= ~WATCH_PM; | | 1105 | tmp &= ~WATCH_PM; |
1106 | tmp |= WATCH_PW | (mask << WATCH_PM_SHIFT); | | 1106 | tmp |= WATCH_PW | (mask << WATCH_PM_SHIFT); |
1107 | if (read) tmp |= WATCH_PR; | | 1107 | if (read) tmp |= WATCH_PR; |
1108 | | | 1108 | |
1109 | stxa(PHYSICAL_WATCHPOINT, ASI_DMMU, addr); | | 1109 | stxa(PHYSICAL_WATCHPOINT, ASI_DMMU, addr); |
1110 | db_printf("Setting physical watchpoint to %llx-%llx\n", | | 1110 | db_printf("Setting physical watchpoint to %llx-%llx\n", |
1111 | (long long)addr, (long long)addr + width); | | 1111 | (long long)addr, (long long)addr + width); |
1112 | } else { | | 1112 | } else { |
1113 | tmp &= ~WATCH_VM; | | 1113 | tmp &= ~WATCH_VM; |
1114 | tmp |= WATCH_VW | (mask << WATCH_VM_SHIFT); | | 1114 | tmp |= WATCH_VW | (mask << WATCH_VM_SHIFT); |
1115 | if (read) tmp |= WATCH_VR; | | 1115 | if (read) tmp |= WATCH_VR; |
1116 | | | 1116 | |
1117 | stxa(VIRTUAL_WATCHPOINT, ASI_DMMU, addr); | | 1117 | stxa(VIRTUAL_WATCHPOINT, ASI_DMMU, addr); |
1118 | db_printf("Setting virtual watchpoint to %llx-%llx\n", | | 1118 | db_printf("Setting virtual watchpoint to %llx-%llx\n", |
1119 | (long long)addr, (long long)addr + width); | | 1119 | (long long)addr, (long long)addr + width); |
1120 | } | | 1120 | } |
1121 | stxa(0, ASI_MCCR, tmp); | | 1121 | stxa(0, ASI_MCCR, tmp); |
1122 | } else { | | 1122 | } else { |
1123 | /* turn off the watchpoint */ | | 1123 | /* turn off the watchpoint */ |
1124 | int64_t tmp = ldxa(0, ASI_MCCR); | | 1124 | int64_t tmp = ldxa(0, ASI_MCCR); |
1125 | if (phys) { | | 1125 | if (phys) { |
1126 | tmp &= ~(WATCH_PM|WATCH_PR|WATCH_PW); | | 1126 | tmp &= ~(WATCH_PM|WATCH_PR|WATCH_PW); |
1127 | db_printf("Disabling physical watchpoint\n"); | | 1127 | db_printf("Disabling physical watchpoint\n"); |
1128 | } else { | | 1128 | } else { |
1129 | tmp &= ~(WATCH_VM|WATCH_VR|WATCH_VW); | | 1129 | tmp &= ~(WATCH_VM|WATCH_VR|WATCH_VW); |
1130 | db_printf("Disabling virtual watchpoint\n"); | | 1130 | db_printf("Disabling virtual watchpoint\n"); |
1131 | } | | 1131 | } |
1132 | stxa(0, ASI_MCCR, tmp); | | 1132 | stxa(0, ASI_MCCR, tmp); |
1133 | } | | 1133 | } |
1134 | } | | 1134 | } |
1135 | | | 1135 | |
1136 | /* XXX this belongs in cpu.c */ | | 1136 | /* XXX this belongs in cpu.c */ |
1137 | static void cpu_debug_dump(void); | | 1137 | static void cpu_debug_dump(void); |
1138 | static void | | 1138 | static void |
1139 | cpu_debug_dump(void) | | 1139 | cpu_debug_dump(void) |
1140 | { | | 1140 | { |
1141 | struct cpu_info *ci; | | 1141 | struct cpu_info *ci; |
1142 | | | 1142 | |
1143 | for (ci = cpus; ci; ci = ci->ci_next) { | | 1143 | for (ci = cpus; ci; ci = ci->ci_next) { |
1144 | db_printf("cpu%d: self 0x%08lx lwp 0x%08lx pcb 0x%08lx\n", | | 1144 | db_printf("cpu%d: self 0x%08lx lwp 0x%08lx pcb 0x%08lx " |
1145 | ci->ci_index, (u_long)ci->ci_self, | | 1145 | "fplwp 0x%08lx\n", ci->ci_index, (u_long)ci->ci_self, |
1146 | (u_long)ci->ci_curlwp, (u_long)ci->ci_cpcb); | | 1146 | (u_long)ci->ci_curlwp, (u_long)ci->ci_cpcb, |
| | | 1147 | (u_long)ci->ci_fplwp); |
1147 | } | | 1148 | } |
1148 | } | | 1149 | } |
1149 | | | 1150 | |
1150 | void | | 1151 | void |
1151 | db_cpu_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 1152 | db_cpu_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
1152 | { | | 1153 | { |
1153 | #ifdef MULTIPROCESSOR | | 1154 | #ifdef MULTIPROCESSOR |
1154 | struct cpu_info *ci; | | 1155 | struct cpu_info *ci; |
1155 | #endif | | 1156 | #endif |
1156 | | | 1157 | |
1157 | if (!have_addr) { | | 1158 | if (!have_addr) { |
1158 | cpu_debug_dump(); | | 1159 | cpu_debug_dump(); |
1159 | return; | | 1160 | return; |
1160 | } | | 1161 | } |
1161 | #ifdef MULTIPROCESSOR | | 1162 | #ifdef MULTIPROCESSOR |
1162 | for (ci = cpus; ci != NULL; ci = ci->ci_next) | | 1163 | for (ci = cpus; ci != NULL; ci = ci->ci_next) |
1163 | if (ci->ci_index == addr) | | 1164 | if (ci->ci_index == addr) |
1164 | break; | | 1165 | break; |
1165 | if (ci == NULL) { | | 1166 | if (ci == NULL) { |
1166 | db_printf("CPU %ld not configured\n", (long)addr); | | 1167 | db_printf("CPU %ld not configured\n", (long)addr); |
1167 | return; | | 1168 | return; |
1168 | } | | 1169 | } |
1169 | if (ci != curcpu()) { | | 1170 | if (ci != curcpu()) { |
1170 | if (!mp_cpu_is_paused(ci->ci_index)) { | | 1171 | if (!mp_cpu_is_paused(ci->ci_index)) { |
1171 | db_printf("CPU %ld not paused\n", (long)addr); | | 1172 | db_printf("CPU %ld not paused\n", (long)addr); |
1172 | return; | | 1173 | return; |
1173 | } | | 1174 | } |
1174 | /* no locking needed - all other cpus are paused */ | | 1175 | /* no locking needed - all other cpus are paused */ |
1175 | ddb_cpu = ci->ci_index; | | 1176 | ddb_cpu = ci->ci_index; |
1176 | mp_resume_cpu(ddb_cpu); | | 1177 | mp_resume_cpu(ddb_cpu); |
1177 | sparc64_do_pause(); | | 1178 | sparc64_do_pause(); |
1178 | } | | 1179 | } |
1179 | #endif | | 1180 | #endif |
1180 | } | | 1181 | } |
1181 | | | 1182 | |
1182 | void | | 1183 | void |
1183 | db_sir_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | | 1184 | db_sir_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) |
1184 | { | | 1185 | { |
1185 | | | 1186 | |
1186 | __asm("sir; nop"); | | 1187 | __asm("sir; nop"); |
1187 | } | | 1188 | } |
1188 | | | 1189 | |
1189 | const struct db_command db_machine_command_table[] = { | | 1190 | const struct db_command db_machine_command_table[] = { |
1190 | { DDB_ADD_CMD("ctx", db_ctx_cmd, 0, | | 1191 | { DDB_ADD_CMD("ctx", db_ctx_cmd, 0, |
1191 | "Print process MMU context information", NULL,NULL) }, | | 1192 | "Print process MMU context information", NULL,NULL) }, |
1192 | #ifdef MULTIPROCESSOR | | 1193 | #ifdef MULTIPROCESSOR |
1193 | { DDB_ADD_CMD("cpu", db_cpu_cmd, 0, | | 1194 | { DDB_ADD_CMD("cpu", db_cpu_cmd, 0, |
1194 | "switch to another cpu", "cpu-no", NULL) }, | | 1195 | "switch to another cpu", "cpu-no", NULL) }, |
1195 | #endif | | 1196 | #endif |
1196 | { DDB_ADD_CMD("dtlb", db_dump_dtlb, 0, | | 1197 | { DDB_ADD_CMD("dtlb", db_dump_dtlb, 0, |
1197 | "Print data translation look-aside buffer context information.", | | 1198 | "Print data translation look-aside buffer context information.", |
1198 | NULL,NULL) }, | | 1199 | NULL,NULL) }, |
1199 | { DDB_ADD_CMD("itlb", db_dump_itlb, 0, | | 1200 | { DDB_ADD_CMD("itlb", db_dump_itlb, 0, |
1200 | "Display instruction translation storage buffer information.", | | 1201 | "Display instruction translation storage buffer information.", |
1201 | NULL,NULL) }, | | 1202 | NULL,NULL) }, |
1202 | { DDB_ADD_CMD("dtsb", db_dump_dtsb, 0, | | 1203 | { DDB_ADD_CMD("dtsb", db_dump_dtsb, 0, |
1203 | "Display data translation storage buffer information.", NULL,NULL) }, | | 1204 | "Display data translation storage buffer information.", NULL,NULL) }, |
1204 | { DDB_ADD_CMD("itsb", db_dump_itsb, 0, | | 1205 | { DDB_ADD_CMD("itsb", db_dump_itsb, 0, |
1205 | "Display instruction translation storage buffer information.", | | 1206 | "Display instruction translation storage buffer information.", |
1206 | NULL,NULL) }, | | 1207 | NULL,NULL) }, |
1207 | { DDB_ADD_CMD("extract", db_pm_extract, 0, | | 1208 | { DDB_ADD_CMD("extract", db_pm_extract, 0, |
1208 | "Extract the physical address from the kernel pmap.", | | 1209 | "Extract the physical address from the kernel pmap.", |
1209 | "address", " address:\tvirtual address to look up") }, | | 1210 | "address", " address:\tvirtual address to look up") }, |
1210 | { DDB_ADD_CMD("fpstate", db_dump_fpstate,0, | | 1211 | { DDB_ADD_CMD("fpstate", db_dump_fpstate,0, |
1211 | "Dump the FPU state." ,NULL,NULL) }, | | 1212 | "Dump the FPU state." ,NULL,NULL) }, |
1212 | { DDB_ADD_CMD("kmap", db_pmap_kernel, 0, | | 1213 | { DDB_ADD_CMD("kmap", db_pmap_kernel, 0, |
1213 | "Display information about mappings in the kernel pmap.", | | 1214 | "Display information about mappings in the kernel pmap.", |
1214 | "[/f] [address]", | | 1215 | "[/f] [address]", |
1215 | " address:\tdisplay the mapping for this virtual address\n" | | 1216 | " address:\tdisplay the mapping for this virtual address\n" |
1216 | " /f:\tif no address is given, display a full dump of the pmap") }, | | 1217 | " /f:\tif no address is given, display a full dump of the pmap") }, |
1217 | { DDB_ADD_CMD("lwp", db_lwp_cmd, 0, | | 1218 | { DDB_ADD_CMD("lwp", db_lwp_cmd, 0, |
1218 | "Display a struct lwp", | | 1219 | "Display a struct lwp", |
1219 | "[address]", | | 1220 | "[address]", |
1220 | " address:\tthe struct lwp to print (curlwp otherwise)") }, | | 1221 | " address:\tthe struct lwp to print (curlwp otherwise)") }, |
1221 | { DDB_ADD_CMD("pcb", db_dump_pcb, 0, | | 1222 | { DDB_ADD_CMD("pcb", db_dump_pcb, 0, |
1222 | "Display information about a struct pcb", | | 1223 | "Display information about a struct pcb", |
1223 | "[address]", | | 1224 | "[address]", |
1224 | " address:\tthe struct pcb to print (curpcb otherwise)") }, | | 1225 | " address:\tthe struct pcb to print (curpcb otherwise)") }, |
1225 | { DDB_ADD_CMD("pctx", db_setpcb, 0, | | 1226 | { DDB_ADD_CMD("pctx", db_setpcb, 0, |
1226 | "Attempt to change MMU process context","pid", | | 1227 | "Attempt to change MMU process context","pid", |
1227 | " pid:\tthe process id to switch the MMU context to") }, | | 1228 | " pid:\tthe process id to switch the MMU context to") }, |
1228 | { DDB_ADD_CMD("page", db_page_cmd, 0, | | 1229 | { DDB_ADD_CMD("page", db_page_cmd, 0, |
1229 | "Display the address of a struct vm_page given a physical address", | | 1230 | "Display the address of a struct vm_page given a physical address", |
1230 | "pa", " pa:\tphysical address to look up") }, | | 1231 | "pa", " pa:\tphysical address to look up") }, |
1231 | { DDB_ADD_CMD("phys", db_pload_cmd, 0, | | 1232 | { DDB_ADD_CMD("phys", db_pload_cmd, 0, |
1232 | "Display physical memory.", "[address][,count]", | | 1233 | "Display physical memory.", "[address][,count]", |
1233 | " adddress:\tphysical address to start (8 byte aligned)\n" | | 1234 | " adddress:\tphysical address to start (8 byte aligned)\n" |
1234 | " count:\tnumber of bytes to display") }, | | 1235 | " count:\tnumber of bytes to display") }, |
1235 | { DDB_ADD_CMD("pmap", db_pmap_cmd, 0, | | 1236 | { DDB_ADD_CMD("pmap", db_pmap_cmd, 0, |
1236 | "Display the pmap", "[/f] [pm_addr]", | | 1237 | "Display the pmap", "[/f] [pm_addr]", |
1237 | " pm_addr:\tAddress of struct pmap to display\n" | | 1238 | " pm_addr:\tAddress of struct pmap to display\n" |
1238 | " /f:\tdo a full dump of the pmap") }, | | 1239 | " /f:\tdo a full dump of the pmap") }, |
1239 | { DDB_ADD_CMD("proc", db_proc_cmd, 0, | | 1240 | { DDB_ADD_CMD("proc", db_proc_cmd, 0, |
1240 | "Display some information about a process", | | 1241 | "Display some information about a process", |
1241 | "[addr]"," addr:\tstruct proc address (curproc otherwise)") }, | | 1242 | "[addr]"," addr:\tstruct proc address (curproc otherwise)") }, |
1242 | { DDB_ADD_CMD("prom", db_prom_cmd, 0, | | 1243 | { DDB_ADD_CMD("prom", db_prom_cmd, 0, |
1243 | "Enter the OFW PROM.", NULL,NULL) }, | | 1244 | "Enter the OFW PROM.", NULL,NULL) }, |
1244 | { DDB_ADD_CMD("pv", db_dump_pv, 0, | | 1245 | { DDB_ADD_CMD("pv", db_dump_pv, 0, |
1245 | "Display a struct pv for a physical address", | | 1246 | "Display a struct pv for a physical address", |
1246 | "pa", " pa:\tphysical address of a managed page") }, | | 1247 | "pa", " pa:\tphysical address of a managed page") }, |
1247 | { DDB_ADD_CMD("sir", db_sir_cmd, 0, | | 1248 | { DDB_ADD_CMD("sir", db_sir_cmd, 0, |
1248 | "do a Software Initiated Reset (entering PROM)", NULL,NULL) }, | | 1249 | "do a Software Initiated Reset (entering PROM)", NULL,NULL) }, |
1249 | { DDB_ADD_CMD("stack", db_dump_stack, 0, | | 1250 | { DDB_ADD_CMD("stack", db_dump_stack, 0, |
1250 | "Dump the window stack.", "[/u] [addr]", | | 1251 | "Dump the window stack.", "[/u] [addr]", |
1251 | " addr:\tstart address of dump (current stack otherwise)\n" | | 1252 | " addr:\tstart address of dump (current stack otherwise)\n" |
1252 | " /u:\tcontinue trace into userland") }, | | 1253 | " /u:\tcontinue trace into userland") }, |
1253 | { DDB_ADD_CMD("tf", db_dump_trap, 0, | | 1254 | { DDB_ADD_CMD("tf", db_dump_trap, 0, |
1254 | "Display full trap frame state.", | | 1255 | "Display full trap frame state.", |
1255 | "[/u] [addr]", | | 1256 | "[/u] [addr]", |
1256 | " addr:\tdisplay this trap frame (current kernel frame otherwise)\n" | | 1257 | " addr:\tdisplay this trap frame (current kernel frame otherwise)\n" |
1257 | " /u:\tdisplay the current userland trap frame") }, | | 1258 | " /u:\tdisplay the current userland trap frame") }, |
1258 | { DDB_ADD_CMD("ts", db_dump_ts, 0, | | 1259 | { DDB_ADD_CMD("ts", db_dump_ts, 0, |
1259 | "Display trap state.", NULL,NULL) }, | | 1260 | "Display trap state.", NULL,NULL) }, |
1260 | { DDB_ADD_CMD("traptrace", db_traptrace, 0, | | 1261 | { DDB_ADD_CMD("traptrace", db_traptrace, 0, |
1261 | "Display or set trap trace information.", | | 1262 | "Display or set trap trace information.", |
1262 | "[/fr] [addr]", | | 1263 | "[/fr] [addr]", |
1263 | " addr:\tstart address of trace\n" | | 1264 | " addr:\tstart address of trace\n" |
1264 | " /f:\tdisplay full information\n" | | 1265 | " /f:\tdisplay full information\n" |
1265 | " /r:\treverse the trace order") }, | | 1266 | " /r:\treverse the trace order") }, |
1266 | { DDB_ADD_CMD("watch", db_watch, 0, | | 1267 | { DDB_ADD_CMD("watch", db_watch, 0, |
1267 | "Set or clear a physical or virtual hardware watchpoint.", | | 1268 | "Set or clear a physical or virtual hardware watchpoint.", |
1268 | "[/prbhlL] [addr]", | | 1269 | "[/prbhlL] [addr]", |
1269 | " addr:\tset the breakpoint (clear watchpoint if not present)\n" | | 1270 | " addr:\tset the breakpoint (clear watchpoint if not present)\n" |
1270 | " /p:\taddress is physical\n" | | 1271 | " /p:\taddress is physical\n" |
1271 | " /r:\ttrap on reads too (otherwise only write access)\n" | | 1272 | " /r:\ttrap on reads too (otherwise only write access)\n" |
1272 | " /b:\t8 bit\n" | | 1273 | " /b:\t8 bit\n" |
1273 | " /h:\t16 bit\n" | | 1274 | " /h:\t16 bit\n" |
1274 | " /l:\t32 bit\n" | | 1275 | " /l:\t32 bit\n" |
1275 | " /L:\t64 bit") }, | | 1276 | " /L:\t64 bit") }, |
1276 | { DDB_ADD_CMD("window", db_dump_window, 0, | | 1277 | { DDB_ADD_CMD("window", db_dump_window, 0, |
1277 | "Print register window information", | | 1278 | "Print register window information", |
1278 | "[no]", " no:\tstack frame number (0, i.e. top, if missing)") }, | | 1279 | "[no]", " no:\tstack frame number (0, i.e. top, if missing)") }, |
1279 | { DDB_ADD_CMD(NULL, NULL, 0, NULL,NULL,NULL) } | | 1280 | { DDB_ADD_CMD(NULL, NULL, 0, NULL,NULL,NULL) } |
1280 | }; | | 1281 | }; |
1281 | | | 1282 | |
1282 | #endif /* DDB */ | | 1283 | #endif /* DDB */ |
1283 | | | 1284 | |
1284 | /* | | 1285 | /* |
1285 | * support for SOFTWARE_SSTEP: | | 1286 | * support for SOFTWARE_SSTEP: |
1286 | * return the next pc if the given branch is taken. | | 1287 | * return the next pc if the given branch is taken. |
1287 | * | | 1288 | * |
1288 | * note: in the case of conditional branches with annul, | | 1289 | * note: in the case of conditional branches with annul, |
1289 | * this actually returns the next pc in the "not taken" path, | | 1290 | * this actually returns the next pc in the "not taken" path, |
1290 | * but in that case next_instr_address() will return the | | 1291 | * but in that case next_instr_address() will return the |
1291 | * next pc in the "taken" path. so even tho the breakpoints | | 1292 | * next pc in the "taken" path. so even tho the breakpoints |
1292 | * are backwards, everything will still work, and the logic is | | 1293 | * are backwards, everything will still work, and the logic is |
1293 | * much simpler this way. | | 1294 | * much simpler this way. |
1294 | */ | | 1295 | */ |
1295 | db_addr_t | | 1296 | db_addr_t |
1296 | db_branch_taken(int inst, db_addr_t pc, db_regs_t *regs) | | 1297 | db_branch_taken(int inst, db_addr_t pc, db_regs_t *regs) |
1297 | { | | 1298 | { |
1298 | union instr insn; | | 1299 | union instr insn; |
1299 | db_addr_t npc; | | 1300 | db_addr_t npc; |
1300 | | | 1301 | |
1301 | npc = DDB_REGS->db_tf.tf_npc; | | 1302 | npc = DDB_REGS->db_tf.tf_npc; |
1302 | | | 1303 | |
1303 | insn.i_int = inst; | | 1304 | insn.i_int = inst; |
1304 | | | 1305 | |
1305 | /* | | 1306 | /* |
1306 | * if this is not an annulled conditional branch, the next pc is "npc". | | 1307 | * if this is not an annulled conditional branch, the next pc is "npc". |
1307 | */ | | 1308 | */ |
1308 | | | 1309 | |
1309 | if (insn.i_any.i_op != IOP_OP2 || insn.i_branch.i_annul != 1) | | 1310 | if (insn.i_any.i_op != IOP_OP2 || insn.i_branch.i_annul != 1) |
1310 | return npc; | | 1311 | return npc; |
1311 | | | 1312 | |
1312 | switch (insn.i_op2.i_op2) { | | 1313 | switch (insn.i_op2.i_op2) { |
1313 | case IOP2_Bicc: | | 1314 | case IOP2_Bicc: |
1314 | case IOP2_FBfcc: | | 1315 | case IOP2_FBfcc: |
1315 | case IOP2_BPcc: | | 1316 | case IOP2_BPcc: |
1316 | case IOP2_FBPfcc: | | 1317 | case IOP2_FBPfcc: |
1317 | case IOP2_CBccc: | | 1318 | case IOP2_CBccc: |
1318 | /* branch on some condition-code */ | | 1319 | /* branch on some condition-code */ |
1319 | switch (insn.i_branch.i_cond) | | 1320 | switch (insn.i_branch.i_cond) |
1320 | { | | 1321 | { |
1321 | case Icc_A: /* always */ | | 1322 | case Icc_A: /* always */ |
1322 | return pc + ((inst << 10) >> 8); | | 1323 | return pc + ((inst << 10) >> 8); |
1323 | | | 1324 | |
1324 | default: /* all other conditions */ | | 1325 | default: /* all other conditions */ |
1325 | return npc + 4; | | 1326 | return npc + 4; |
1326 | } | | 1327 | } |
1327 | | | 1328 | |
1328 | case IOP2_BPr: | | 1329 | case IOP2_BPr: |
1329 | /* branch on register, always conditional */ | | 1330 | /* branch on register, always conditional */ |
1330 | return npc + 4; | | 1331 | return npc + 4; |
1331 | | | 1332 | |
1332 | default: | | 1333 | default: |
1333 | /* not a branch */ | | 1334 | /* not a branch */ |
1334 | panic("branch_taken() on non-branch"); | | 1335 | panic("branch_taken() on non-branch"); |
1335 | } | | 1336 | } |
1336 | } | | 1337 | } |
1337 | | | 1338 | |
1338 | bool | | 1339 | bool |
1339 | db_inst_branch(int inst) | | 1340 | db_inst_branch(int inst) |
1340 | { | | 1341 | { |
1341 | union instr insn; | | 1342 | union instr insn; |
1342 | | | 1343 | |
1343 | insn.i_int = inst; | | 1344 | insn.i_int = inst; |
1344 | | | 1345 | |
1345 | if (insn.i_any.i_op != IOP_OP2) | | 1346 | if (insn.i_any.i_op != IOP_OP2) |
1346 | return FALSE; | | 1347 | return FALSE; |
1347 | | | 1348 | |
1348 | switch (insn.i_op2.i_op2) { | | 1349 | switch (insn.i_op2.i_op2) { |
1349 | case IOP2_BPcc: | | 1350 | case IOP2_BPcc: |
1350 | case IOP2_Bicc: | | 1351 | case IOP2_Bicc: |
1351 | case IOP2_BPr: | | 1352 | case IOP2_BPr: |
1352 | case IOP2_FBPfcc: | | 1353 | case IOP2_FBPfcc: |
1353 | case IOP2_FBfcc: | | 1354 | case IOP2_FBfcc: |
1354 | case IOP2_CBccc: | | 1355 | case IOP2_CBccc: |
1355 | return TRUE; | | 1356 | return TRUE; |
1356 | | | 1357 | |
1357 | default: | | 1358 | default: |
1358 | return FALSE; | | 1359 | return FALSE; |
1359 | } | | 1360 | } |
1360 | } | | 1361 | } |
1361 | | | 1362 | |
1362 | | | 1363 | |
1363 | bool | | 1364 | bool |
1364 | db_inst_call(int inst) | | 1365 | db_inst_call(int inst) |
1365 | { | | 1366 | { |
1366 | union instr insn; | | 1367 | union instr insn; |
1367 | | | 1368 | |
1368 | insn.i_int = inst; | | 1369 | insn.i_int = inst; |
1369 | | | 1370 | |
1370 | switch (insn.i_any.i_op) { | | 1371 | switch (insn.i_any.i_op) { |
1371 | case IOP_CALL: | | 1372 | case IOP_CALL: |
1372 | return TRUE; | | 1373 | return TRUE; |
1373 | | | 1374 | |
1374 | case IOP_reg: | | 1375 | case IOP_reg: |
1375 | return (insn.i_op3.i_op3 == IOP3_JMPL) && !db_inst_return(inst); | | 1376 | return (insn.i_op3.i_op3 == IOP3_JMPL) && !db_inst_return(inst); |
1376 | | | 1377 | |
1377 | default: | | 1378 | default: |
1378 | return FALSE; | | 1379 | return FALSE; |
1379 | } | | 1380 | } |
1380 | } | | 1381 | } |
1381 | | | 1382 | |
1382 | | | 1383 | |
1383 | bool | | 1384 | bool |
1384 | db_inst_unconditional_flow_transfer(int inst) | | 1385 | db_inst_unconditional_flow_transfer(int inst) |
1385 | { | | 1386 | { |
1386 | union instr insn; | | 1387 | union instr insn; |
1387 | | | 1388 | |
1388 | insn.i_int = inst; | | 1389 | insn.i_int = inst; |
1389 | | | 1390 | |
1390 | if (db_inst_call(inst)) | | 1391 | if (db_inst_call(inst)) |
1391 | return TRUE; | | 1392 | return TRUE; |
1392 | | | 1393 | |
1393 | if (insn.i_any.i_op != IOP_OP2) | | 1394 | if (insn.i_any.i_op != IOP_OP2) |
1394 | return FALSE; | | 1395 | return FALSE; |
1395 | | | 1396 | |
1396 | switch (insn.i_op2.i_op2) | | 1397 | switch (insn.i_op2.i_op2) |
1397 | { | | 1398 | { |
1398 | case IOP2_BPcc: | | 1399 | case IOP2_BPcc: |
1399 | case IOP2_Bicc: | | 1400 | case IOP2_Bicc: |
1400 | case IOP2_FBPfcc: | | 1401 | case IOP2_FBPfcc: |
1401 | case IOP2_FBfcc: | | 1402 | case IOP2_FBfcc: |
1402 | case IOP2_CBccc: | | 1403 | case IOP2_CBccc: |
1403 | return insn.i_branch.i_cond == Icc_A; | | 1404 | return insn.i_branch.i_cond == Icc_A; |
1404 | | | 1405 | |
1405 | default: | | 1406 | default: |
1406 | return FALSE; | | 1407 | return FALSE; |
1407 | } | | 1408 | } |
1408 | } | | 1409 | } |
1409 | | | 1410 | |
1410 | | | 1411 | |
1411 | bool | | 1412 | bool |
1412 | db_inst_return(int inst) | | 1413 | db_inst_return(int inst) |
1413 | { | | 1414 | { |
1414 | return (inst == I_JMPLri(I_G0, I_O7, 8) || /* ret */ | | 1415 | return (inst == I_JMPLri(I_G0, I_O7, 8) || /* ret */ |
1415 | inst == I_JMPLri(I_G0, I_I7, 8)); /* retl */ | | 1416 | inst == I_JMPLri(I_G0, I_I7, 8)); /* retl */ |
1416 | } | | 1417 | } |
1417 | | | 1418 | |
1418 | bool | | 1419 | bool |
1419 | db_inst_trap_return(int inst) | | 1420 | db_inst_trap_return(int inst) |
1420 | { | | 1421 | { |
1421 | union instr insn; | | 1422 | union instr insn; |
1422 | | | 1423 | |
1423 | insn.i_int = inst; | | 1424 | insn.i_int = inst; |
1424 | | | 1425 | |
1425 | return (insn.i_any.i_op == IOP_reg && | | 1426 | return (insn.i_any.i_op == IOP_reg && |
1426 | insn.i_op3.i_op3 == IOP3_RETT); | | 1427 | insn.i_op3.i_op3 == IOP3_RETT); |
1427 | } | | 1428 | } |
1428 | | | 1429 | |
1429 | | | 1430 | |
1430 | int | | 1431 | int |
1431 | db_inst_load(int inst) | | 1432 | db_inst_load(int inst) |
1432 | { | | 1433 | { |
1433 | union instr insn; | | 1434 | union instr insn; |
1434 | | | 1435 | |
1435 | insn.i_int = inst; | | 1436 | insn.i_int = inst; |
1436 | | | 1437 | |
1437 | if (insn.i_any.i_op != IOP_mem) | | 1438 | if (insn.i_any.i_op != IOP_mem) |
1438 | return 0; | | 1439 | return 0; |
1439 | | | 1440 | |
1440 | switch (insn.i_op3.i_op3) { | | 1441 | switch (insn.i_op3.i_op3) { |
1441 | case IOP3_LD: | | 1442 | case IOP3_LD: |
1442 | case IOP3_LDUB: | | 1443 | case IOP3_LDUB: |
1443 | case IOP3_LDUH: | | 1444 | case IOP3_LDUH: |
1444 | case IOP3_LDD: | | 1445 | case IOP3_LDD: |
1445 | case IOP3_LDSB: | | 1446 | case IOP3_LDSB: |
1446 | case IOP3_LDSH: | | 1447 | case IOP3_LDSH: |
1447 | case IOP3_LDSTUB: | | 1448 | case IOP3_LDSTUB: |
1448 | case IOP3_SWAP: | | 1449 | case IOP3_SWAP: |
1449 | case IOP3_LDA: | | 1450 | case IOP3_LDA: |
1450 | case IOP3_LDUBA: | | 1451 | case IOP3_LDUBA: |
1451 | case IOP3_LDUHA: | | 1452 | case IOP3_LDUHA: |
1452 | case IOP3_LDDA: | | 1453 | case IOP3_LDDA: |
1453 | case IOP3_LDSBA: | | 1454 | case IOP3_LDSBA: |
1454 | case IOP3_LDSHA: | | 1455 | case IOP3_LDSHA: |
1455 | case IOP3_LDSTUBA: | | 1456 | case IOP3_LDSTUBA: |
1456 | case IOP3_SWAPA: | | 1457 | case IOP3_SWAPA: |
1457 | case IOP3_LDF: | | 1458 | case IOP3_LDF: |
1458 | case IOP3_LDFSR: | | 1459 | case IOP3_LDFSR: |
1459 | case IOP3_LDDF: | | 1460 | case IOP3_LDDF: |
1460 | case IOP3_LFC: | | 1461 | case IOP3_LFC: |
1461 | case IOP3_LDCSR: | | 1462 | case IOP3_LDCSR: |
1462 | case IOP3_LDDC: | | 1463 | case IOP3_LDDC: |
1463 | return 1; | | 1464 | return 1; |
1464 | | | 1465 | |
1465 | default: | | 1466 | default: |
1466 | return 0; | | 1467 | return 0; |
1467 | } | | 1468 | } |
1468 | } | | 1469 | } |
1469 | | | 1470 | |
1470 | int | | 1471 | int |
1471 | db_inst_store(int inst) | | 1472 | db_inst_store(int inst) |
1472 | { | | 1473 | { |
1473 | union instr insn; | | 1474 | union instr insn; |
1474 | | | 1475 | |
1475 | insn.i_int = inst; | | 1476 | insn.i_int = inst; |
1476 | | | 1477 | |
1477 | if (insn.i_any.i_op != IOP_mem) | | 1478 | if (insn.i_any.i_op != IOP_mem) |
1478 | return 0; | | 1479 | return 0; |
1479 | | | 1480 | |
1480 | switch (insn.i_op3.i_op3) { | | 1481 | switch (insn.i_op3.i_op3) { |
1481 | case IOP3_ST: | | 1482 | case IOP3_ST: |
1482 | case IOP3_STB: | | 1483 | case IOP3_STB: |
1483 | case IOP3_STH: | | 1484 | case IOP3_STH: |
1484 | case IOP3_STD: | | 1485 | case IOP3_STD: |
1485 | case IOP3_LDSTUB: | | 1486 | case IOP3_LDSTUB: |
1486 | case IOP3_SWAP: | | 1487 | case IOP3_SWAP: |
1487 | case IOP3_STA: | | 1488 | case IOP3_STA: |
1488 | case IOP3_STBA: | | 1489 | case IOP3_STBA: |
1489 | case IOP3_STHA: | | 1490 | case IOP3_STHA: |
1490 | case IOP3_STDA: | | 1491 | case IOP3_STDA: |
1491 | case IOP3_LDSTUBA: | | 1492 | case IOP3_LDSTUBA: |
1492 | case IOP3_SWAPA: | | 1493 | case IOP3_SWAPA: |
1493 | case IOP3_STF: | | 1494 | case IOP3_STF: |
1494 | case IOP3_STFSR: | | 1495 | case IOP3_STFSR: |
1495 | case IOP3_STDFQ: | | 1496 | case IOP3_STDFQ: |
1496 | case IOP3_STDF: | | 1497 | case IOP3_STDF: |
1497 | case IOP3_STC: | | 1498 | case IOP3_STC: |
1498 | case IOP3_STCSR: | | 1499 | case IOP3_STCSR: |
1499 | case IOP3_STDCQ: | | 1500 | case IOP3_STDCQ: |
1500 | case IOP3_STDC: | | 1501 | case IOP3_STDC: |
1501 | return 1; | | 1502 | return 1; |
1502 | | | 1503 | |
1503 | default: | | 1504 | default: |
1504 | return 0; | | 1505 | return 0; |
1505 | } | | 1506 | } |
1506 | } | | 1507 | } |