breakpoint.c
6.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
/*************************************************************************
*
* File: breakpoint.c
*
* This file contains signal handler for SIGILL.
*
* $Header: /root/leakn64/depot/rf/sw/n64os20l/iosim/src/breakpoint.c,v 1.1.1.1 2002/05/30 05:41:20 whs Exp $
*
*/
#include <sys/cachectl.h>
#include <siginfo.h>
#include <signal.h>
#include <ucontext.h>
#include <stdio.h>
#include "sim.h"
#include "simipc.h"
#define DIR_LOAD DIR_SINGLE_LOAD
#define DIR_STORE DIR_SINGLE_STORE
#define SIZE_BYTE 1
#define SIZE_HALF 2
#define SIZE_WORD 4
#define SIZE_DWORD 8
static void breakpoint_set(minst_t *, int);
static void breakpoint_handler(int, siginfo_t *, ucontext_t *);
static int is_branch(minst_t);
static minst_t *branch_target(minst_t, minst_t *, gregset_t);
static int is_loadstore(minst_t, dir_t *, sz_t *);
static ulong loadstore_addr(minst_t, gregset_t);
static struct save {
minst_t *addr;
minst_t value;
} save[2];
static int savecount;
static minst_t bp = { 0x40906000 }; /* mtc0: illegal */
static const struct sigaction act = {SA_SIGINFO, breakpoint_handler, 0};
static minst_t *lo, *hi;
void
breakpoint_init(descriptor_t *dp)
{
sigaction(SIGILL, &act, NULL);
lo = (minst_t *)dp->addr;
hi = (minst_t *)(dp->addr + dp->size);
breakpoint_set((minst_t *)dp->entry, 0);
}
static void
breakpoint_set(minst_t *addr, int index)
{
if (addr < lo || addr >= hi)
return;
save[index].addr = addr;
save[index].value = *addr;
*addr = bp;
cacheflush(addr, sizeof(*addr), ICACHE);
printf("breakpoint_set: save[%d]: addr=0x%08x, value=0x%08x\n",
index, save[index].addr, save[index].value);
printf("breakpoint_set: bp=0x%08x, *addr=0x%08x\n", bp, *addr);
savecount = index + 1;
}
static void
breakpoint_remove(int index)
{
*save[index].addr = save[index].value;
cacheflush(save[index].addr, sizeof (minst_t), ICACHE);
}
static void
breakpoint_handler(int sig, siginfo_t *sip, ucontext_t *up)
{
register int i;
minst_t inst, bdinst;
minst_t *pc;
minst_t *target_pc;
dir_t dir;
sz_t sz;
printf("**** BREAKPOINT HANDLER ****\n");
/*
* Verify we faulted on one of our own here XXX
*/
for (i = 0; i < savecount; i++)
breakpoint_remove(i);
pc = (minst_t *)sip->si_addr;
printf("PC=0x%08x, INST=0x%08x, PC+2=0x%08x\n", pc, *pc, pc+2);
printf("EPC=0x%08x, INST=0x%08x\n",
up->uc_mcontext.gregs[CTX_EPC],
*(minst_t *)(up->uc_mcontext.gregs[CTX_EPC]));
/* up->uc_mcontext.gregs[CTX_EPC] += 4; */
#if 0
memory_access((long)pc, REF_INST, DIR_LOAD, SIZE_WORD);
inst = *pc;
if (is_branch(inst)) {
printf(" **** is_branch ****\n");
target_pc = branch_target(inst, pc, up->uc_mcontext.gregs);
memory_access((long)(pc+1), REF_INST, DIR_LOAD, SIZE_WORD);
bdinst = *(pc+1);
if (is_loadstore(bdinst, &dir, &sz)) {
memory_access(
(ulong)loadstore_addr(bdinst, up->uc_mcontext.gregs),
REF_DATA, dir, sz);
}
breakpoint_set(target_pc, 0);
breakpoint_set(pc+2, 0);
} else {
if (is_loadstore(inst, &dir, &sz)) {
printf(" **** is_loadstore ****\n");
memory_access(
(ulong)loadstore_addr(inst, up->uc_mcontext.gregs),
REF_DATA, dir, sz);
}
breakpoint_set(pc+1, 0);
}
#endif
}
static int
is_branch(minst_t inst)
{
switch (inst.j_format.opcode) {
case spec_op:
switch (inst.r_format.func) {
case jr_op:
case jalr_op:
return(1);
}
return(0);
case bcond_op:
switch (inst.i_format.rt) {
case bltz_op:
case bgez_op:
case bltzal_op:
case bgezal_op:
case bltzl_op:
case bgezl_op:
case bltzall_op:
case bgezall_op:
return(1);
}
return(0);
case j_op:
case jal_op:
case beq_op:
case bne_op:
case blez_op:
case bgtz_op:
case beql_op:
case bnel_op:
case blezl_op:
case bgtzl_op:
return(1);
case cop0_op:
case cop1_op:
case cop2_op:
case cop3_op:
switch (inst.r_format.rs) {
case bc_op:
return(1);
}
return(0);
}
return(0);
}
/*
* branch_target - return address where branch will go
*/
static minst_t *
branch_target(minst_t inst, minst_t *pc, gregset_t gr)
{
register short simmediate;
switch (inst.j_format.opcode) {
case spec_op:
switch (inst.r_format.func) {
case jr_op:
case jalr_op:
return((minst_t *)gr[inst.r_format.rs]);
}
break;
case bcond_op:
switch (inst.i_format.rt) {
case bltz_op:
case bgez_op:
case bltzal_op:
case bgezal_op:
case bltzl_op:
case bgezl_op:
case bltzall_op:
case bgezall_op:
/*
* assign to temp since compiler currently
* doesn't handle signed bit fields
*/
simmediate = inst.i_format.simmediate;
return((minst_t *)((long)pc+4+(simmediate<<2)));
}
break;
case j_op:
case jal_op:
return((minst_t *)((((long)pc+4)&~((1<<28)-1)) | (inst.j_format.target<<2)));
case beq_op:
case bne_op:
case blez_op:
case bgtz_op:
case beql_op:
case bnel_op:
case blezl_op:
case bgtzl_op:
/*
* assign to temp since compiler currently
* doesn't handle signed bit fields
*/
simmediate = inst.i_format.simmediate;
return((minst_t *)((long)pc+4+(simmediate<<2)));
case cop0_op:
case cop1_op:
case cop2_op:
case cop3_op:
switch (inst.r_format.rs) {
case bc_op:
/*
* kludge around compiler deficiency
*/
simmediate = inst.i_format.simmediate;
return((minst_t *)((long)pc+4+(simmediate<<2)));
}
break;
}
return pc;
}
static int
is_loadstore(minst_t inst, dir_t *dirp, sz_t *szp)
{
switch(inst.i_format.opcode) {
case lb_op: case lbu_op:
*dirp=DIR_LOAD; *szp = SIZE_BYTE; return(1);
case lh_op: case lhu_op:
*dirp=DIR_LOAD; *szp = SIZE_HALF; return(1);
case lw_op: case lwu_op: case ll_op: case lwc1_op:
*dirp=DIR_LOAD; *szp = SIZE_WORD; return(1);
#ifdef JEFF
case lwl_op: case lwr_op:
abort();
#endif
case ld_op: case lld_op: case ldc1_op:
*dirp=DIR_LOAD; *szp = SIZE_DWORD; return(1);
#ifdef JEFF
case ldl_op:
case ldr_op:
#endif
case sb_op:
*dirp=DIR_STORE; *szp = SIZE_BYTE; return(1);
case sh_op:
*dirp=DIR_STORE; *szp = SIZE_HALF; return(1);
case sw_op: case sc_op: case swc1_op:
*dirp=DIR_STORE; *szp = SIZE_WORD; return(1);
#ifdef JEFF
case swl_op:
case swr_op:
#endif
case sd_op: case scd_op: case sdc1_op:
*dirp=DIR_STORE; *szp = SIZE_DWORD; return(1);
#ifdef JEFF
case sdl_op:
case sdr_op:
#endif
return(1);
}
return(0);
}
/*
* ldst_addr - compute data address instruction at EF_EPC would reference
* 2 versions - layered-up to allow caller to avoid
* assumptions that the outer layer makes.
*/
static ulong
loadstore_addr(minst_t inst, gregset_t gr)
{
ulong base;
base = (inst.i_format.rs == 0) ? 0 : gr[inst.i_format.rs];
return (base + inst.i_format.simmediate);
}