gdbStep.c
4.66 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
/*====================================================================
*
* File: gdbStep.c
* Author: Steve Shepard (sjs@sgi.com)
*
*====================================================================*/
#include <ultratypes.h>
#include <os_internal.h>
#include <sys/inst.h>
#include "ultragdb.h"
typedef u32 inst_t;
typedef u32 __psunsigned_t;
typedef struct {
inst_t *addr;
u32 data;
} TmpBreak;
TmpBreak breakList[2];
int breakCnt;
/*
* branch_target - return address where branch will go
*/
#define REGVAL(x) ( ((u32 *)®) [(x)] )
int
is_branch(inst_t inst)
{
union mips_instruction i;
i.word = inst;
switch (i.j_format.opcode) {
case spec_op:
switch (i.r_format.func) {
case jr_op:
case jalr_op:
return(1);
}
return(0);
case bcond_op:
switch (i.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 (i.r_format.rs) {
case bc_op:
return(1);
}
return(0);
}
return(0);
}
static inst_t *
branch_target(inst_t inst, inst_t *pc)
{
union mips_instruction i;
register short simmediate;
i.word = inst;
switch (i.j_format.opcode) {
case spec_op:
switch (i.r_format.func) {
case jr_op:
case jalr_op:
return ((inst_t *)(REGVAL(i.r_format.rs)));
}
break;
case bcond_op:
switch (i.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 = i.i_format.simmediate;
return ((inst_t *)((__psunsigned_t)pc+4+(simmediate<<2)));
}
break;
case j_op:
case jal_op:
return((inst_t *)((((__psunsigned_t)pc+4)&~((1<<28)-1)) | (i.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 = i.i_format.simmediate;
return ((inst_t *)((__psunsigned_t)pc+4+(simmediate<<2)));
case cop0_op:
case cop1_op:
case cop2_op:
case cop3_op:
switch (i.r_format.rs) {
case bc_op:
/*
* kludge around compiler deficiency
*/
simmediate = i.i_format.simmediate;
return((inst_t *)((__psunsigned_t)pc+4+(simmediate<<2)));
}
break;
}
if (gdbDebug)
osSyncPrintf("illegal instruction in branch_target\n");
return pc;
}
void set_bp(inst_t *loc, int i)
{
if (gdbDebug)
osSyncPrintf("setting tmp bp %d at 0x%x\n", i, loc);
breakList[i].addr = loc;
breakList[i].data = *loc;
*loc = TMP_BREAK; /* break instruction */
gdbWritebackDCache((void *)loc, 4);
gdbInvalICache((void *)loc, 4);
}
void installBP(void)
{
inst_t inst;
inst_t *target;
inst_t *pc;
/* ### what if this triggers a watch point??? */
breakCnt = 0;
pc = (inst_t *)reg.pc;
inst = *pc; /* ### should check to make sure this is valid!!!*/
if (is_branch(inst)) {
target = branch_target(inst, pc);
/*
* Can't single step self-branches, so just wait
* until they fall through
*/
if (target != pc)
set_bp(target, breakCnt++); /* set branch target */
set_bp((inst_t *)pc+2, breakCnt++); /* and branch not taken loc */
} else
set_bp((inst_t *)pc+1, breakCnt++); /* bp one instruction later */
}
s32 removeBP(void)
{
int i;
/* need to remove in reverse order */
for (i = --breakCnt; i >= 0; i--) {
if (gdbDebug)
osSyncPrintf("removing tmp bp %d at 0x%x\n", i, breakList[i].addr);
*breakList[i].addr = breakList[i].data;
gdbWritebackDCache((void *)breakList[i].addr, 4);
gdbInvalICache((void *)breakList[i].addr, 4);
}
breakCnt = 0;
return 1;
}