1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <gccore.h>
5 
6 #include "lwp_threads.h"
7 #include "debug_supp.h"
8 
9 extern lwp_objinfo _lwp_cond_objects;
10 extern lwp_objinfo _lwp_thr_objects;
11 extern lwp_objinfo _lwp_tqueue_objects;
12 extern lwp_objinfo _lwp_mqbox_objects;
13 extern lwp_objinfo _lwp_mutex_objects;
14 extern lwp_objinfo _lwp_sema_objects;
15 
16 extern const u8 hexchars[];
17 
18 extern u8 __text_start[],__data_start[],__bss_start[];
19 extern u8 __text_fstart[],__data_fstart[],__bss_fstart[];
20 
hstr2nibble(const char * buf,s32 * nibble)21 s32 hstr2nibble(const char *buf,s32 *nibble)
22 {
23 	s32 ch;
24 
25 	ch = *buf;
26 	if(ch>='0' && ch<='9') {
27 		*nibble = ch - '0';
28 		return 1;
29 	}
30 	if(ch>='a' && ch<='f') {
31 		*nibble = ch - 'a' + 10;
32 		return 1;
33 	}
34 	if(ch>='A' && ch<='F') {
35 		*nibble = ch - 'A' + 10;
36 		return 1;
37 	}
38 	return 0;
39 }
40 
hstr2byte(const char * buf,s32 * bval)41 s32 hstr2byte(const char *buf,s32 *bval)
42 {
43 	s32 hnib,lnib;
44 
45 	if(!hstr2nibble(buf,&hnib) || !hstr2nibble(buf+1,&lnib)) return 0;
46 
47 	*bval = (hnib<<4)|lnib;
48 	return 1;
49 }
50 
vhstr2int(const char * buf,s32 * ival)51 const char* vhstr2int(const char *buf,s32 *ival)
52 {
53 	s32 i,val,nibble;
54 	s32 found0,lim;
55 
56 	found0 = 0;
57 	for(i=0;i<8;i++,buf++) {
58 		if(*buf!='0') break;
59 
60 		found0 = 1;
61 	}
62 
63 	val = 0;
64 	lim = 8 - i;
65 	for(i=0;i<lim;i++,buf++) {
66 		if(!hstr2nibble(buf,&nibble)) {
67 			if(i==0 && !found0) return NULL;
68 
69 			*ival = val;
70 			return buf;
71 		}
72 		val = (val<<4)|nibble;
73 	}
74 	if(hstr2nibble(buf,&nibble)) return NULL;
75 
76 	*ival = val;
77 	return buf;
78 }
79 
fhstr2int(const char * buf,s32 * ival)80 const char* fhstr2int(const char *buf,s32 *ival)
81 {
82 	s32 i,val,nibble;
83 
84 	val = 0;
85 	for(i=0;i<8;i++,buf++) {
86 		if(!hstr2nibble(buf,&nibble)) return NULL;
87 
88 		val = (val<<4)|nibble;
89 	}
90 
91 	*ival = val;
92 	return buf;
93 }
94 
int2fhstr(char * buf,s32 val)95 char* int2fhstr(char *buf,s32 val)
96 {
97 	s32 i,nibble,shift;
98 
99 	for(i=0,shift=28;i<8;i++,shift-=4,buf++) {
100 		nibble = (val>>shift)&0x0f;
101 		*buf = hexchars[nibble];
102 	}
103 	return buf;
104 }
105 
int2vhstr(char * buf,s32 val)106 char* int2vhstr(char *buf,s32 val)
107 {
108 	s32 i,nibble,shift;
109 
110 	for(i=0,shift=28;i<8;i++,shift-=4) {
111 		nibble = (val>>shift)&0x0f;
112 		if(nibble) break;
113 	}
114 	if(i==8) {
115 		*buf++ = '0';
116 		return buf;
117 	}
118 
119 	*buf++ = hexchars[nibble];
120 	for(i++,shift-=4;i<8;i++,shift-=4,buf++) {
121 		nibble = (val>>shift)&0x0f;
122 		*buf = hexchars[nibble];
123 	}
124 	return buf;
125 }
126 
mem2hstr(char * buf,const char * mem,s32 count)127 char* mem2hstr(char *buf,const char *mem,s32 count)
128 {
129 	s32 i;
130 	char ch;
131 
132 	for(i=0;i<count;i++,mem++) {
133 		ch = *mem;
134 		*buf++ = hexchars[ch>>4];
135 		*buf++ = hexchars[ch&0x0f];
136 	}
137 	*buf = 0;
138 	return buf;
139 }
thread2fhstr(char * buf,s32 thread)140 char* thread2fhstr(char *buf,s32 thread)
141 {
142 	s32 i,nibble,shift;
143 
144 	for(i=0;i<8;i++,buf++) *buf = '0';
145 	for(i=0,shift=28;i<8;i++,shift-=4,buf++) {
146 		nibble = (thread>>shift)&0x0f;
147 		*buf = hexchars[nibble];
148 	}
149 	return buf;
150 }
151 
thread2vhstr(char * buf,s32 thread)152 char* thread2vhstr(char *buf,s32 thread)
153 {
154 	s32 i,nibble,shift;
155 
156 	for(i=0,shift=28;i<8;i++,shift-=4) {
157 		nibble = (thread>>shift)&0x0f;
158 		if(nibble) break;
159 	}
160 	if(i==8) {
161 		*buf++ = '0';
162 		return buf;
163 	}
164 
165 	*buf++ = hexchars[nibble];
166 	for(i++,shift-=4;i<8;i++,shift-=4,buf++) {
167 		nibble = (thread>>shift)&0x0f;
168 		*buf = hexchars[nibble];
169 	}
170 	return buf;
171 }
172 
fhstr2thread(const char * buf,s32 * thread)173 const char* fhstr2thread(const char *buf,s32 *thread)
174 {
175 	s32 i,nibble,val;
176 
177 	for(i=0;i<8;i++,buf++)
178 		if(*buf!='0') return NULL;
179 
180 	val = 0;
181 	for(i=0;i<8;i++,buf++) {
182 		if(!hstr2nibble(buf,&nibble)) return NULL;
183 
184 		val = (val<<4)|nibble;
185 	}
186 
187 	*thread = val;
188 	return buf;
189 }
190 
vhstr2thread(const char * buf,s32 * thread)191 const char* vhstr2thread(const char *buf,s32 *thread)
192 {
193 	s32 i,val,nibble;
194 	s32 found0,lim;
195 
196 	found0 = 0;
197 	for(i=0;i<16;i++,buf++) {
198 		if(*buf!='0') break;
199 
200 		found0 = 1;
201 	}
202 
203 	val = 0;
204 	lim = 16 - i;
205 	for(i=0;i<lim;i++,buf++) {
206 		if(!hstr2nibble(buf,&nibble)) {
207 			if(i==0 && found0) return NULL;
208 
209 			*thread = val;
210 			return buf;
211 		}
212 
213 		val = (val<<4)|nibble;
214 	}
215 	if(hstr2nibble(buf,&nibble)) return NULL;
216 
217 	*thread = val;
218 	return buf;
219 }
220 
gdbstub_idtoindex(s32 objid)221 s32 gdbstub_idtoindex(s32 objid)
222 {
223 	s32 min_id,max_id;
224 	s32 first_id;
225 
226 	if(_thr_executing==_thr_idle) return 1;
227 
228 	first_id = 1;
229 	min_id = _lwp_thr_objects.min_id;
230 	max_id = _lwp_thr_objects.max_id;
231 	if(objid>=min_id && objid<max_id) return first_id + (objid - min_id);
232 
233 	return 1;
234 }
235 
gdbstub_indextoid(s32 thread)236 lwp_cntrl* gdbstub_indextoid(s32 thread)
237 {
238 	s32 min_id,max_id,first_id;
239 	lwp_cntrl *th;
240 
241 	if(thread<=0) return NULL;
242 
243 	if(thread==1) return _thr_idle;
244 
245 	first_id = 1;
246 	min_id = _lwp_thr_objects.min_id;
247 	max_id = _lwp_thr_objects.max_id;
248 	if(thread<(first_id + (max_id - min_id))) {
249 		th = (lwp_cntrl*)_lwp_thr_objects.local_table[thread - first_id];
250 		return th;
251 	}
252 	return NULL;
253 }
254 
gdbstub_getcurrentthread()255 s32 gdbstub_getcurrentthread()
256 {
257 	return gdbstub_idtoindex(_thr_executing->object.id);
258 }
259 
gdbstub_getnextthread(s32 athread)260 s32 gdbstub_getnextthread(s32 athread)
261 {
262 	s32 id,start;
263 	s32 first_id,min_id,max_id,lim;
264 
265 	if(athread<1) return 1;
266 
267 	first_id = 1;
268 	min_id = _lwp_thr_objects.min_id;
269 	max_id = _lwp_thr_objects.max_id;
270 	lim = first_id + max_id - min_id;
271 	if(athread<lim) {
272 		if(athread<first_id)
273 			start = first_id;
274 		else
275 			start = athread+1;
276 
277 		for(id=start;id<lim;id++)
278 			if(_lwp_thr_objects.local_table[id - first_id]!=NULL) return id;
279 	}
280 
281 	return 0;
282 }
283 
gdbstub_getoffsets(char ** textaddr,char ** dataaddr,char ** bssaddr)284 s32 gdbstub_getoffsets(char **textaddr,char **dataaddr,char **bssaddr)
285 {
286 	*textaddr = (char*)((u32)__text_fstart - (u32)__text_fstart);
287 	*dataaddr = (char*)((u32)__data_fstart - (u32)__text_fstart);
288 	*bssaddr = (char*)((u32)__bss_fstart - (u32)__text_fstart);
289 
290 	return 1;
291 }
292 
gdbstub_getthreadinfo(s32 thread,struct gdbstub_threadinfo * info)293 s32 gdbstub_getthreadinfo(s32 thread,struct gdbstub_threadinfo *info)
294 {
295 	s32 first_id,min_id,max_id;
296 	lwp_cntrl *th;
297 	char tmp_buf[20];
298 
299 	if(thread<=0) return 0;
300 
301 	if(thread==1) {
302 		strcpy(info->display,"idle thread");
303 		strcpy(info->name,"IDLE");
304 		info->more_display[0] = 0;
305 		return 1;
306 	}
307 
308 	first_id = 1;
309 	min_id = _lwp_thr_objects.min_id;
310 	max_id = _lwp_thr_objects.max_id;
311 	if(thread<=(first_id + (max_id - min_id))){
312 		th = (lwp_cntrl*)_lwp_thr_objects.local_table[thread - first_id];
313 		if(th==NULL) return 0;
314 
315 		strcpy(info->display,"libogc task:   control at: 0x");
316 		tmp_buf[0] = hexchars[(((int)th)>>28)&0x0f];
317 		tmp_buf[1] = hexchars[(((int)th)>>24)&0x0f];
318 		tmp_buf[2] = hexchars[(((int)th)>>20)&0x0f];
319 		tmp_buf[3] = hexchars[(((int)th)>>16)&0x0f];
320 		tmp_buf[4] = hexchars[(((int)th)>>12)&0x0f];
321 		tmp_buf[5] = hexchars[(((int)th)>>8)&0x0f];
322 		tmp_buf[6] = hexchars[(((int)th)>>4)&0x0f];
323 		tmp_buf[7] = hexchars[((int)th)&0x0f];
324 		tmp_buf[8] = 0;
325 		strcat(info->display,tmp_buf);
326 
327 		info->name[0] = 0;
328 		info->name[1] = 0;
329 		info->name[2] = 0;
330 		info->name[3] = 0;
331 		info->name[4] = 0;
332 
333 		info->more_display[0] = 0;
334 		return 1;
335 	}
336 	return 0;
337 }
338 
parsezbreak(const char * in,s32 * type,char ** addr,u32 * len)339 s32 parsezbreak(const char *in,s32 *type,char **addr,u32 *len)
340 {
341 	s32 ttmp,atmp,ltmp;
342 
343 	in++;
344 	if(!hstr2nibble(in,&ttmp) || *(in+1)!=',') return 0;
345 
346 	in += 2;
347 	in = vhstr2int(in,&atmp);
348 	if(in==NULL || *in!=',') return 0;
349 
350 	in++;
351 	in = vhstr2int(in,&ltmp);
352 	if(in==NULL || ltmp<1) return 0;
353 
354 	*type = ttmp;
355 	*addr = (char*)atmp;
356 	*len = ltmp;
357 
358 	return 1;
359 }
360 
parseqp(const char * in,s32 * mask,s32 * thread)361 s32 parseqp(const char *in,s32 *mask,s32 *thread)
362 {
363 	const char *ptr;
364 
365 	ptr = fhstr2int(in+2,mask);
366 	if(ptr==NULL) return 0;
367 
368 	ptr = fhstr2thread(ptr,thread);
369 	if(ptr==NULL) return 0;
370 
371 	return 1;
372 }
373 
packqq(char * out,s32 mask,s32 thread,struct gdbstub_threadinfo * info)374 void packqq(char *out,s32 mask,s32 thread,struct gdbstub_threadinfo *info)
375 {
376 	s32 len;
377 
378 	*out++ = 'q';
379 	*out++ = 'Q';
380 	out = int2fhstr(out,mask);
381 	out = thread2fhstr(out,thread);
382 
383 	if(mask&0x01) {
384 		memcpy(out,"00000001",8);
385 		out += 8;
386 		*out++ = '1';
387 		*out++ = '0';
388 		out = thread2fhstr(out,thread);
389 	}
390 	if(mask&0x02) {
391 		memcpy(out,"00000002",8);
392 		out += 8;
393 		*out++ = '0';
394 		*out++ = '1';
395 		*out++ = '1';
396 	}
397 	if(mask&0x04) {
398 		memcpy(out,"00000004",8);
399 		out += 8;
400 
401 		info->display[sizeof(info->display)-1] = 0;			//for god sake
402 		len = strlen(info->display);
403 
404 		*out++ = hexchars[(len>>4)&0x0f];
405 		*out++ = hexchars[len&0x0f];
406 
407 		memcpy(out,info->display,len);
408 		out += len;
409 	}
410 	if(mask&0x08) {
411 		memcpy(out,"00000008",8);
412 		out += 8;
413 
414 		info->display[sizeof(info->name)-1] = 0;			//for god sake
415 		len = strlen(info->name);
416 
417 		*out++ = hexchars[(len>>4)&0x0f];
418 		*out++ = hexchars[len&0x0f];
419 
420 		memcpy(out,info->name,len);
421 		out += len;
422 	}
423 	if(mask&0x10) {
424 		memcpy(out,"00000010",8);
425 		out += 8;
426 
427 		info->display[sizeof(info->more_display)-1] = 0;			//for god sake
428 		len = strlen(info->more_display);
429 
430 		*out++ = hexchars[(len>>4)&0x0f];
431 		*out++ = hexchars[len&0x0f];
432 
433 		memcpy(out,info->more_display,len);
434 		out += len;
435 	}
436 	*out = 0;
437 }
438 
parseql(const char * in,s32 * first,s32 * max_cnt,s32 * athread)439 s32 parseql(const char *in,s32 *first,s32 *max_cnt,s32 *athread)
440 {
441 	const char *ptr;
442 
443 	ptr = in+2;
444 	if(!hstr2nibble(ptr,first)) return 0;
445 
446 	ptr++;
447 	if(!hstr2byte(ptr,max_cnt)) return 0;
448 
449 	ptr += 2;
450 	ptr = fhstr2thread(ptr,athread);
451 	if(ptr==NULL) return 0;
452 
453 	return 1;
454 }
455 
reserve_qmheader(char * out)456 char* reserve_qmheader(char *out)
457 {
458 	return (out+21);
459 }
460 
packqmthread(char * out,s32 thread)461 char* packqmthread(char *out,s32 thread)
462 {
463 	return thread2fhstr(out,thread);
464 }
465 
packqmheader(char * out,s32 count,s32 done,s32 athread)466 void packqmheader(char *out,s32 count,s32 done,s32 athread)
467 {
468 	*out++ = 'q';
469 	*out++ = 'M';
470 	*out++ = hexchars[(count>>4)&0x0f];
471 	*out++ = hexchars[count&0x0f];
472 
473 	if(done) *out++ = '1';
474 	else *out++ = '0';
475 
476 	thread2fhstr(out,athread);
477 }
478