File: | ddb/db_run.c |
Warning: | line 189, column 3 Value stored to 'ins' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: db_run.c,v 1.30 2020/10/15 03:14:00 deraadt Exp $ */ |
2 | /* $NetBSD: db_run.c,v 1.8 1996/02/05 01:57:12 christos Exp $ */ |
3 | |
4 | /* |
5 | * Mach Operating System |
6 | * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University |
7 | * All Rights Reserved. |
8 | * |
9 | * Permission to use, copy, modify and distribute this software and its |
10 | * documentation is hereby granted, provided that both the copyright |
11 | * notice and this permission notice appear in all copies of the |
12 | * software, derivative works or modified versions, and any portions |
13 | * thereof, and that both notices appear in supporting documentation. |
14 | * |
15 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" |
16 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR |
17 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. |
18 | * |
19 | * Carnegie Mellon requests users of this software to return to |
20 | * |
21 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU |
22 | * School of Computer Science |
23 | * Carnegie Mellon University |
24 | * Pittsburgh PA 15213-3890 |
25 | * |
26 | * any improvements or extensions that they make and grant Carnegie Mellon |
27 | * the rights to redistribute these changes. |
28 | * |
29 | * Author: David B. Golub, Carnegie Mellon University |
30 | * Date: 7/90 |
31 | */ |
32 | |
33 | /* |
34 | * Commands to run process. |
35 | */ |
36 | #include <sys/param.h> |
37 | #include <sys/systm.h> |
38 | |
39 | #include <machine/db_machdep.h> |
40 | |
41 | #include <ddb/db_run.h> |
42 | #include <ddb/db_break.h> |
43 | #include <ddb/db_access.h> |
44 | |
45 | #ifdef SOFTWARE_SSTEP |
46 | db_breakpoint_t db_not_taken_bkpt = 0; |
47 | db_breakpoint_t db_taken_bkpt = 0; |
48 | #endif |
49 | |
50 | int db_inst_count; |
51 | |
52 | #include <ddb/db_watch.h> |
53 | #include <ddb/db_output.h> |
54 | #include <ddb/db_sym.h> |
55 | #include <ddb/db_extern.h> |
56 | |
57 | int db_run_mode; |
58 | #define STEP_NONE0 0 |
59 | #define STEP_ONCE1 1 |
60 | #define STEP_RETURN2 2 |
61 | #define STEP_CALLT3 3 |
62 | #define STEP_CONTINUE4 4 |
63 | #define STEP_INVISIBLE5 5 |
64 | #define STEP_COUNT6 6 |
65 | |
66 | int db_sstep_print; |
67 | int db_loop_count; |
68 | int db_call_depth; |
69 | |
70 | int |
71 | db_stop_at_pc(db_regs_t *regs, int *is_breakpoint) |
72 | { |
73 | vaddr_t pc, old_pc; |
74 | db_breakpoint_t bkpt; |
75 | |
76 | db_clear_breakpoints(); |
77 | db_clear_watchpoints(); |
78 | old_pc = pc = PC_REGS(regs)((vaddr_t)(regs)->tf_rip); |
79 | |
80 | #ifdef FIXUP_PC_AFTER_BREAK |
81 | if (*is_breakpoint) { |
82 | /* |
83 | * Breakpoint trap. Fix up the PC if the |
84 | * machine requires it. |
85 | */ |
86 | FIXUP_PC_AFTER_BREAK(regs)((regs)->tf_rip -= (1)); |
87 | pc = PC_REGS(regs)((vaddr_t)(regs)->tf_rip); |
88 | } |
89 | #endif |
90 | |
91 | /* |
92 | * Now check for a breakpoint at this address. |
93 | */ |
94 | bkpt = db_find_breakpoint(pc); |
95 | if (bkpt) { |
96 | if (--bkpt->count == 0) { |
97 | db_clear_single_step(regs)((regs)->tf_rflags &= ~0x00000100); |
98 | bkpt->count = bkpt->init_count; |
99 | *is_breakpoint = 1; |
100 | return 1; /* stop here */ |
101 | } |
102 | } else if (*is_breakpoint |
103 | #ifdef SOFTWARE_SSTEP |
104 | && !((db_taken_bkpt && db_taken_bkpt->address == pc) || |
105 | (db_not_taken_bkpt && db_not_taken_bkpt->address == pc)) |
106 | #endif |
107 | ) { |
108 | #ifdef PC_ADVANCE |
109 | PC_ADVANCE(regs); |
110 | #else |
111 | # ifdef SET_PC_REGS |
112 | SET_PC_REGS(regs, old_pc)(regs)->tf_rip = (int64_t)(old_pc); |
113 | # else |
114 | PC_REGS(regs)((vaddr_t)(regs)->tf_rip) = old_pc; |
115 | # endif |
116 | #endif |
117 | } |
118 | db_clear_single_step(regs)((regs)->tf_rflags &= ~0x00000100); |
119 | |
120 | *is_breakpoint = 0; |
121 | |
122 | if (db_run_mode == STEP_INVISIBLE5) { |
123 | db_run_mode = STEP_CONTINUE4; |
124 | return 0; /* continue */ |
125 | } |
126 | if (db_run_mode == STEP_COUNT6) { |
127 | return 0; /* continue */ |
128 | } |
129 | if (db_run_mode == STEP_ONCE1) { |
130 | if (--db_loop_count > 0) { |
131 | if (db_sstep_print) { |
132 | db_printf("\t\t"); |
133 | db_print_loc_and_inst(pc); |
134 | db_printf("\n"); |
135 | } |
136 | return 0; /* continue */ |
137 | } |
138 | } |
139 | if (db_run_mode == STEP_RETURN2) { |
140 | db_expr_t ins = db_get_value(pc, sizeof(int), 0); |
141 | |
142 | /* continue until matching return */ |
143 | |
144 | if (!inst_trap_return(ins)(((ins)&0xff) == 0xcf) && |
145 | (!inst_return(ins)(((ins)&0xff) == 0xc3) || --db_call_depth != 0)) { |
146 | if (db_sstep_print) { |
147 | if (inst_call(ins)(((ins)&0xff) == 0xe8 || (((ins)&0xff) == 0xff && ((ins)&0x3800) == 0x1000)) || inst_return(ins)(((ins)&0xff) == 0xc3)) { |
148 | int i; |
149 | |
150 | db_printf("[after %6d] ", db_inst_count); |
151 | for (i = db_call_depth; --i > 0; ) |
152 | db_printf(" "); |
153 | db_print_loc_and_inst(pc); |
154 | db_printf("\n"); |
155 | } |
156 | } |
157 | if (inst_call(ins)(((ins)&0xff) == 0xe8 || (((ins)&0xff) == 0xff && ((ins)&0x3800) == 0x1000))) |
158 | db_call_depth++; |
159 | return 0; /* continue */ |
160 | } |
161 | } |
162 | if (db_run_mode == STEP_CALLT3) { |
163 | db_expr_t ins = db_get_value(pc, sizeof(int), 0); |
164 | |
165 | /* continue until call or return */ |
166 | |
167 | if (!inst_call(ins)(((ins)&0xff) == 0xe8 || (((ins)&0xff) == 0xff && ((ins)&0x3800) == 0x1000)) && !inst_return(ins)(((ins)&0xff) == 0xc3) && |
168 | !inst_trap_return(ins)(((ins)&0xff) == 0xcf)) { |
169 | return 0; /* continue */ |
170 | } |
171 | } |
172 | db_run_mode = STEP_NONE0; |
173 | return 1; |
174 | } |
175 | |
176 | void |
177 | db_restart_at_pc(db_regs_t *regs, int watchpt) |
178 | { |
179 | vaddr_t pc = PC_REGS(regs)((vaddr_t)(regs)->tf_rip); |
180 | |
181 | if ((db_run_mode == STEP_COUNT6) || (db_run_mode == STEP_RETURN2) || |
182 | (db_run_mode == STEP_CALLT3)) { |
183 | db_expr_t ins; |
184 | |
185 | /* |
186 | * We are about to execute this instruction, |
187 | * so count it now. |
188 | */ |
189 | ins = db_get_value(pc, sizeof(int), 0); |
Value stored to 'ins' is never read | |
190 | db_inst_count++; |
191 | #ifdef SOFTWARE_SSTEP |
192 | /* XXX works on mips, but... */ |
193 | if (inst_branch(ins) || inst_call(ins)(((ins)&0xff) == 0xe8 || (((ins)&0xff) == 0xff && ((ins)&0x3800) == 0x1000))) { |
194 | ins = db_get_value(next_instr_address(pc, 1), |
195 | sizeof(int), 0); |
196 | db_inst_count++; |
197 | } |
198 | #endif /* SOFTWARE_SSTEP */ |
199 | } |
200 | |
201 | if (db_run_mode == STEP_CONTINUE4) { |
202 | if (watchpt || db_find_breakpoint(pc)) { |
203 | /* |
204 | * Step over breakpoint/watchpoint. |
205 | */ |
206 | db_run_mode = STEP_INVISIBLE5; |
207 | db_set_single_step(regs)((regs)->tf_rflags |= 0x00000100); |
208 | } else { |
209 | db_set_breakpoints(); |
210 | db_set_watchpoints(); |
211 | } |
212 | } else { |
213 | db_set_single_step(regs)((regs)->tf_rflags |= 0x00000100); |
214 | } |
215 | } |
216 | |
217 | void |
218 | db_single_step(db_regs_t *regs) |
219 | { |
220 | if (db_run_mode == STEP_CONTINUE4) { |
221 | db_run_mode = STEP_INVISIBLE5; |
222 | db_set_single_step(regs)((regs)->tf_rflags |= 0x00000100); |
223 | } |
224 | } |
225 | |
226 | /* single-step */ |
227 | /*ARGSUSED*/ |
228 | void |
229 | db_single_step_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) |
230 | { |
231 | int print = 0; |
232 | |
233 | if (count == -1) |
234 | count = 1; |
235 | |
236 | if (modif[0] == 'p') |
237 | print = 1; |
238 | |
239 | db_run_mode = STEP_ONCE1; |
240 | db_loop_count = count; |
241 | db_sstep_print = print; |
242 | db_inst_count = 0; |
243 | |
244 | db_cmd_loop_done = 1; |
245 | } |
246 | |
247 | /* trace and print until call/return */ |
248 | /*ARGSUSED*/ |
249 | void |
250 | db_trace_until_call_cmd(db_expr_t addr, int have_addr, db_expr_t count, |
251 | char *modif) |
252 | { |
253 | int print = 0; |
254 | |
255 | if (modif[0] == 'p') |
256 | print = 1; |
257 | |
258 | db_run_mode = STEP_CALLT3; |
259 | db_sstep_print = print; |
260 | db_inst_count = 0; |
261 | |
262 | db_cmd_loop_done = 1; |
263 | } |
264 | |
265 | /*ARGSUSED*/ |
266 | void |
267 | db_trace_until_matching_cmd(db_expr_t addr, int have_addr, db_expr_t count, |
268 | char *modif) |
269 | { |
270 | int print = 0; |
271 | |
272 | if (modif[0] == 'p') |
273 | print = 1; |
274 | |
275 | db_run_mode = STEP_RETURN2; |
276 | db_call_depth = 1; |
277 | db_sstep_print = print; |
278 | db_inst_count = 0; |
279 | |
280 | db_cmd_loop_done = 1; |
281 | } |
282 | |
283 | /* continue */ |
284 | /*ARGSUSED*/ |
285 | void |
286 | db_continue_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) |
287 | { |
288 | if (modif[0] == 'c') |
289 | db_run_mode = STEP_COUNT6; |
290 | else |
291 | db_run_mode = STEP_CONTINUE4; |
292 | db_inst_count = 0; |
293 | |
294 | db_cmd_loop_done = 1; |
295 | } |
296 | |
297 | #ifdef SOFTWARE_SSTEP |
298 | /* |
299 | * Software implementation of single-stepping. |
300 | * If your machine does not have a trace mode |
301 | * similar to the vax or sun ones you can use |
302 | * this implementation, done for the mips. |
303 | * Just define the above conditional and provide |
304 | * the functions/macros defined below. |
305 | * |
306 | * extern int |
307 | * inst_branch(ins), returns true if the instruction might branch |
308 | * extern unsigned |
309 | * branch_taken(ins, pc, getreg_val, regs), |
310 | * return the address the instruction might |
311 | * branch to |
312 | * getreg_val(regs, reg), return the value of a user register, |
313 | * as indicated in the hardware instruction |
314 | * encoding, e.g. 8 for r8 |
315 | * |
316 | * next_instr_address(pc, bd) returns the address of the first |
317 | * instruction following the one at "pc", |
318 | * which is either in the taken path of |
319 | * the branch (bd==1) or not. This is |
320 | * for machines (mips) with branch delays. |
321 | * |
322 | * A single-step may involve at most 2 breakpoints - |
323 | * one for branch-not-taken and one for branch taken. |
324 | * If one of these addresses does not already have a breakpoint, |
325 | * we allocate a breakpoint and save it here. |
326 | * These breakpoints are deleted on return. |
327 | */ |
328 | |
329 | void |
330 | db_set_single_step(db_regs_t *regs)((db_regs_t *regs)->tf_rflags |= 0x00000100) |
331 | { |
332 | vaddr_t pc = PC_REGS(regs)((vaddr_t)(regs)->tf_rip); |
333 | #ifndef SOFTWARE_SSTEP_EMUL |
334 | vaddr_t brpc; |
335 | u_int inst; |
336 | |
337 | /* |
338 | * User was stopped at pc, e.g. the instruction |
339 | * at pc was not executed. |
340 | */ |
341 | inst = db_get_value(pc, sizeof(int), 0); |
342 | if (inst_branch(inst) || inst_call(inst)(((inst)&0xff) == 0xe8 || (((inst)&0xff) == 0xff && ((inst)&0x3800) == 0x1000)) || inst_return(inst)(((inst)&0xff) == 0xc3)) { |
343 | brpc = branch_taken(inst, pc, getreg_val, regs); |
344 | if (brpc != pc) { /* self-branches are hopeless */ |
345 | db_taken_bkpt = db_set_temp_breakpoint(brpc); |
346 | } |
347 | #if 0 |
348 | /* XXX this seems like a true bug, no? */ |
349 | pc = next_instr_address(pc, 1); |
350 | #endif |
351 | } |
352 | #endif /*SOFTWARE_SSTEP_EMUL*/ |
353 | pc = next_instr_address(pc, 0); |
354 | db_not_taken_bkpt = db_set_temp_breakpoint(pc); |
355 | } |
356 | |
357 | void |
358 | db_clear_single_step(db_regs_t *regs)((db_regs_t *regs)->tf_rflags &= ~0x00000100) |
359 | { |
360 | if (db_taken_bkpt != 0) { |
361 | db_delete_temp_breakpoint(db_taken_bkpt); |
362 | db_taken_bkpt = 0; |
363 | } |
364 | if (db_not_taken_bkpt != 0) { |
365 | db_delete_temp_breakpoint(db_not_taken_bkpt); |
366 | db_not_taken_bkpt = 0; |
367 | } |
368 | } |
369 | |
370 | #endif /* SOFTWARE_SSTEP */ |