gdbregs.c
8.31 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
/*---------------------------------------------------------------------*
* Copyright (C) 2004 BroadOn Communications Corp.
*
* $RCSfile: gdbregs.c,v $ (corresponds to rmonregs.c)
* $Revision: 1.1 $
* $Date: 2004/02/06 02:12:22 $
*---------------------------------------------------------------------*/
/*
* This file contains functions for setting/accessing registers for the
* GDB stub.
*/
#include "ultragdb.h"
/**************** GDB Register Access Functions **************/
static Registers reg;
/************************************************************************
Function: __gdbGetRegisterContents
Args: OSThread* tptr - which thread to use for reg info
int regNumber - which register to return
Type: u32 - returns the contents of the register
Purpose: This function obtains the contents of the register specifed from
either the static application register storage area or the Thread
Control Block. This function is called by the routine that sets
breakpoints for stepping through a jump to register contents inst.
************************************************************************/
u32 __gdbGetRegisterContents( OSThread* tptr, int regNumber )
{
u32 * regPointer;
if (tptr == NULL) return 0;
if ( regNumber >= 1 && regNumber <= 25 )
regNumber -= 1; /* no stored 0 */
else if ( regNumber >= 28 && regNumber <= 31 )
regNumber -= 3; /* no stored 0, 26, 27 */
else
return 0; /* not available */
regPointer = (u32 *) &tptr->context;
regPointer += regNumber;
return *regPointer;
}
/************************************************************************
Function: __gdbSetRegister
Args: OSThread* thread - Thread for which the register should be set
int reg - Register number. The register order follows
that expected by GDB for mips-linux.
(see ultragdb.h and GDB's tm-mips.h)
` int value - Value to set the register to
Purpose: This function sets the specified register to value for the
given thread.
Returns: int - Error code (<0 indicates error, >= 0 is OK)
GDB_ERROR_NO_ERROR (0) - Register successfully set
GDB_ERROR_INVALID_ID - Invalid register or thread
************************************************************************/
int __gdbSetRegister(OSThread* thread, int reg, int value)
{
volatile float f;
__OSThreadContext *c;
/*
* Touch a floating point register to become the owner of the floating
* point unit (and force the previous owner to save its registers.
*/
f = 0.0F;
if (thread == NULL)
{
/* Argh, we can't find any threads */
return GDB_ERROR_INVALID_ID;
}
c = &thread->context;
if (reg == 0)
{
/* Cannot set this register - R0 tied to 0 */
return GDB_ERROR_INVALID_ID;
}
else if ((reg >= 1) && (reg <= 25))
{
/* General purpose registers - u64 in thread context */
u64 *regptr = &c->at;
regptr[reg-1] = value;
}
else if ((reg == 26) || (reg == 27))
{
/* Cannot set these registers - K0 and K1 are not in the thread context */
return GDB_ERROR_INVALID_ID;
}
else if ((reg >= 28) && (reg <= 31))
{
/* General purpose registers - u64 in thread context */
u64 *regptr = &c->gp;
regptr[reg-28] = value;
}
else if (reg == 32)
{
c->sr = value;
}
else if (reg == 33)
{
c->hi = value;
}
else if (reg == 34)
{
c->lo = value;
}
else if (reg == 35)
{
c->badvaddr = value;
}
else if (reg == 36)
{
c->cause = value;
}
else if (reg == 37)
{
c->pc = value;
}
else if ((reg >= 38) && (reg <= 69))
{
/* Floating point registers */
u32 *regptr = (u32*) &c->fp0;
regptr[reg-38] = value;
}
else if (reg == 70)
{
c->fpcsr = value;
}
else
{
return GDB_ERROR_INVALID_ID;
}
return GDB_ERROR_NO_ERROR;
}
/************************************************************************
Function: gdbProcSetRegister
Args: char* ptr - Set Register command (format: n=value)
char* resp - Response buffer
Purpose: This function parses the GDB set register command and sets
the specified register for the current thread. This function
will also write to the response buffer (null-terminated)
the status to be sent to GDB:
OK - If the operation was successful
ENN - If there was an error
TODO: If current thread is -1, set register for all threads????
************************************************************************/
void gdbProcSetRegisterPkt(char* ptr, char *resp)
{
int reg, value;
if ((ptr == NULL) || (resp == NULL)) return;
if (hexToInt(&ptr, ®) /* get register number */
&& (*ptr++ == '=')
&& hexToInt(&ptr, &value))
{
OSThread* t = getOneCurrentThread();
if (t != NULL) {
if (__gdbSetRegister(t, reg, value) >= 0)
strcpy(resp, GDB_RESP_STATUS_OK);
else strcpy(resp, GDB_RESP_ERR_INVALID_ADDR);
}
else strcpy(resp, GDB_RESP_ERR_NO_THREAD);
}
else strcpy(resp, GDB_RESP_ERR_PKT_FORMAT);
}
/************************************************************************
Function: gdbAssembleRegisters
Args: char* resp - Response buffer
Purpose: This function responds to the GDB get register request by
assembling the registers for the current thread and placing
it in the response buffer (null-terminated). The registers
are given in the order specified by GDB for mips-linux
(see ultragdb.h and GDB's tm-mips.h) Each register is given
in the target-byte order and is 4 bytes wide.
The response to GDB will be:
<registers in hex> - If the operation was successful
ENN - If there was an error
TODO: What to do if current thread is -1 (i.e. all threads)?
************************************************************************/
void gdbAssembleRegisters(char *resp)
{
u32 *src;
u32 *dest;
int i;
OSThread *t;
__OSThreadContext *c;
volatile float f;
if (resp == NULL) return;
/*
* Touch a floating point register to become the owner of the floating
* point unit (and force the previous owner to save its registers.
*/
f = 0.0F;
t = getOneCurrentThread();
if (t == NULL)
{
/* Argh, we can't find any threads */
strcpy(resp, GDB_RESP_ERR_NO_THREAD);
return;
}
c = &t->context;
/* Copies general registers */
reg.zero = 0;
reg.at = c->at;
reg.v0 = c->v0;
reg.v1 = c->v1;
reg.a0 = c->a0;
reg.a1 = c->a1;
reg.a2 = c->a2;
reg.a3 = c->a3;
reg.t0 = c->t0;
reg.t1 = c->t1;
reg.t2 = c->t2;
reg.t3 = c->t3;
reg.t4 = c->t4;
reg.t5 = c->t5;
reg.t6 = c->t6;
reg.t7 = c->t7;
reg.s0 = c->s0;
reg.s1 = c->s1;
reg.s2 = c->s2;
reg.s3 = c->s3;
reg.s4 = c->s4;
reg.s5 = c->s5;
reg.s6 = c->s6;
reg.s7 = c->s7;
reg.t8 = c->t8;
reg.t9 = c->t9;
reg.k0 = 0; /* Not in thread context */
reg.k1 = 0; /* Not in thread context */
reg.gp = c->gp;
reg.sp = c->sp;
reg.s8 = c->s8;
reg.ra = c->ra;
/* Copies special registers for main CPU */
reg.sr = c->sr;
reg.lo = c->lo;
reg.hi = c->hi;
reg.bad = c->badvaddr;
reg.cause = c->cause;
reg.pc = c->pc;
/* Copies floating point registers */
dest = (u32 *)®.f0;
src = (u32 *)&c->fp0;
for (i = 0; i < 32; i++)
*dest++ = *src++;
/* Copies flating point control registers */
/* The R4300 is suppose to have 32 control registers - most of which we ignore
since it's unclear what they do and GDB does not seem to need them */
reg.fsr = c->fpcsr; /* Floating point control/status register? */
/* Registers are given in target endianess */
mem2hex((char *)®, resp, sizeof(Registers));
}