1 |
douglas |
2 |
/* Low level interface for debugging FreeBSD user threads for GDB, the GNU debugger. |
2 |
|
|
Copyright 1996, 1999 Free Software Foundation, Inc. |
3 |
|
|
|
4 |
|
|
This file is part of GDB. |
5 |
|
|
|
6 |
|
|
This program is free software; you can redistribute it and/or modify |
7 |
|
|
it under the terms of the GNU General Public License as published by |
8 |
|
|
the Free Software Foundation; either version 2 of the License, or |
9 |
|
|
(at your option) any later version. |
10 |
|
|
|
11 |
|
|
This program is distributed in the hope that it will be useful, |
12 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
|
|
GNU General Public License for more details. |
15 |
|
|
|
16 |
|
|
You should have received a copy of the GNU General Public License |
17 |
|
|
along with this program; if not, write to the Free Software |
18 |
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
19 |
|
|
|
20 |
|
|
/* $FreeBSD: ports/devel/gdb6/files/freebsd-uthread.c,v 1.3 2004/08/23 06:34:48 obrien Exp $ */ |
21 |
|
|
|
22 |
|
|
/* This module implements a sort of half target that sits between the |
23 |
|
|
machine-independent parts of GDB and the ptrace interface (infptrace.c) to |
24 |
|
|
provide access to the FreeBSD user-mode thread implementation. |
25 |
|
|
|
26 |
|
|
FreeBSD threads are true user-mode threads, which are invoked via |
27 |
|
|
the pthread_* interfaces. These are mostly implemented in |
28 |
|
|
user-space, with all thread context kept in various structures that |
29 |
|
|
live in the user's heap. For the most part, the kernel has no |
30 |
|
|
knowlege of these threads. |
31 |
|
|
|
32 |
|
|
Based largely on hpux-thread.c |
33 |
|
|
|
34 |
|
|
*/ |
35 |
|
|
|
36 |
|
|
|
37 |
|
|
#include "defs.h" |
38 |
|
|
#include <sys/queue.h> |
39 |
|
|
#include <signal.h> |
40 |
|
|
#include <setjmp.h> |
41 |
|
|
#include <string.h> |
42 |
|
|
#include "gdbthread.h" |
43 |
|
|
#include "target.h" |
44 |
|
|
#include "inferior.h" |
45 |
|
|
#include <fcntl.h> |
46 |
|
|
#include <ucontext.h> |
47 |
|
|
#include <unistd.h> |
48 |
|
|
#include <sys/stat.h> |
49 |
|
|
#include "gdbcore.h" |
50 |
|
|
#include "regcache.h" |
51 |
|
|
|
52 |
|
|
extern int child_suppress_run; |
53 |
|
|
extern struct target_ops child_ops; /* target vector for inftarg.c */ |
54 |
|
|
|
55 |
|
|
extern void _initialize_freebsd_uthread PARAMS ((void)); |
56 |
|
|
|
57 |
|
|
/* Set to true while we are part-way through attaching */ |
58 |
|
|
static int freebsd_uthread_attaching; |
59 |
|
|
|
60 |
|
|
static int freebsd_uthread_active = 0; |
61 |
|
|
static CORE_ADDR P_thread_list; |
62 |
|
|
static CORE_ADDR P_thread_run; |
63 |
|
|
|
64 |
|
|
/* Pointer to the next function on the objfile event chain. */ |
65 |
|
|
static void (*target_new_objfile_chain) (struct objfile *objfile); |
66 |
|
|
|
67 |
|
|
static void freebsd_uthread_resume PARAMS ((ptid_t pid, int step, |
68 |
|
|
enum target_signal signo)); |
69 |
|
|
|
70 |
|
|
static void init_freebsd_uthread_ops PARAMS ((void)); |
71 |
|
|
|
72 |
|
|
static struct target_ops freebsd_uthread_ops; |
73 |
|
|
|
74 |
|
|
static ptid_t find_active_ptid PARAMS ((void)); |
75 |
|
|
|
76 |
|
|
struct cached_pthread { |
77 |
|
|
u_int64_t uniqueid; |
78 |
|
|
int state; |
79 |
|
|
CORE_ADDR name; |
80 |
|
|
union { |
81 |
|
|
ucontext_t uc; |
82 |
|
|
jmp_buf jb; |
83 |
|
|
} ctx; |
84 |
|
|
}; |
85 |
|
|
|
86 |
|
|
static ptid_t cached_ptid; |
87 |
|
|
static struct cached_pthread cached_pthread; |
88 |
|
|
static CORE_ADDR cached_pthread_addr; |
89 |
|
|
|
90 |
|
|
LIST_HEAD(idmaplist, idmap); |
91 |
|
|
|
92 |
|
|
struct idmap { |
93 |
|
|
LIST_ENTRY(idmap) link; |
94 |
|
|
u_int64_t uniqueid; |
95 |
|
|
int tid; |
96 |
|
|
}; |
97 |
|
|
|
98 |
|
|
#define MAPHASH_SIZE 257 |
99 |
|
|
#define TID_MIN 1 |
100 |
|
|
#define TID_MAX 16383 |
101 |
|
|
|
102 |
|
|
static int tid_to_hash[TID_MAX + 1]; /* set to map_hash index */ |
103 |
|
|
static struct idmaplist map_hash[MAPHASH_SIZE]; |
104 |
|
|
static int next_free_tid = TID_MIN; /* first available tid */ |
105 |
|
|
static int last_free_tid = TID_MIN; /* first unavailable */ |
106 |
|
|
|
107 |
|
|
static CORE_ADDR P_thread_next_offset; |
108 |
|
|
static CORE_ADDR P_thread_uniqueid_offset; |
109 |
|
|
static CORE_ADDR P_thread_state_offset; |
110 |
|
|
static CORE_ADDR P_thread_name_offset; |
111 |
|
|
static CORE_ADDR P_thread_ctx_offset; |
112 |
|
|
static CORE_ADDR P_thread_PS_RUNNING_value; |
113 |
|
|
static CORE_ADDR P_thread_PS_DEAD_value; |
114 |
|
|
|
115 |
|
|
static int next_offset; |
116 |
|
|
static int uniqueid_offset; |
117 |
|
|
static int state_offset; |
118 |
|
|
static int name_offset; |
119 |
|
|
static int ctx_offset; |
120 |
|
|
static int PS_RUNNING_value; |
121 |
|
|
static int PS_DEAD_value; |
122 |
|
|
|
123 |
|
|
#define UNIQUEID_HASH(id) (id % MAPHASH_SIZE) |
124 |
|
|
#define TID_ADD1(tid) (((tid) + 1) == TID_MAX + 1 \ |
125 |
|
|
? TID_MIN : (tid) + 1) |
126 |
|
|
#define IS_TID_FREE(tid) (tid_to_hash[tid] == -1) |
127 |
|
|
|
128 |
|
|
static int |
129 |
|
|
get_new_tid(int h) |
130 |
|
|
{ |
131 |
|
|
int tid = next_free_tid; |
132 |
|
|
|
133 |
|
|
tid_to_hash[tid] = h; |
134 |
|
|
next_free_tid = TID_ADD1(next_free_tid); |
135 |
|
|
if (next_free_tid == last_free_tid) |
136 |
|
|
{ |
137 |
|
|
int i; |
138 |
|
|
|
139 |
|
|
for (i = last_free_tid; TID_ADD1(i) != last_free_tid; i = TID_ADD1(i)) |
140 |
|
|
if (IS_TID_FREE(i)) |
141 |
|
|
break; |
142 |
|
|
if (TID_ADD1(i) == last_free_tid) |
143 |
|
|
{ |
144 |
|
|
error("too many threads"); |
145 |
|
|
return 0; |
146 |
|
|
} |
147 |
|
|
next_free_tid = i; |
148 |
|
|
for (i = TID_ADD1(i); IS_TID_FREE(i); i = TID_ADD1(i)) |
149 |
|
|
; |
150 |
|
|
last_free_tid = i; |
151 |
|
|
} |
152 |
|
|
|
153 |
|
|
return tid; |
154 |
|
|
} |
155 |
|
|
|
156 |
|
|
static ptid_t |
157 |
|
|
find_ptid(u_int64_t uniqueid) |
158 |
|
|
{ |
159 |
|
|
int h = UNIQUEID_HASH(uniqueid); |
160 |
|
|
struct idmap *im; |
161 |
|
|
|
162 |
|
|
LIST_FOREACH(im, &map_hash[h], link) |
163 |
|
|
if (im->uniqueid == uniqueid) |
164 |
|
|
return MERGEPID(PIDGET(inferior_ptid), im->tid); |
165 |
|
|
|
166 |
|
|
im = xmalloc(sizeof(struct idmap)); |
167 |
|
|
im->uniqueid = uniqueid; |
168 |
|
|
im->tid = get_new_tid(h); |
169 |
|
|
LIST_INSERT_HEAD(&map_hash[h], im, link); |
170 |
|
|
|
171 |
|
|
return MERGEPID(PIDGET(inferior_ptid), im->tid); |
172 |
|
|
} |
173 |
|
|
|
174 |
|
|
static void |
175 |
|
|
free_ptid(ptid_t ptid) |
176 |
|
|
{ |
177 |
|
|
int tid = TIDGET(ptid); |
178 |
|
|
int h = tid_to_hash[tid]; |
179 |
|
|
struct idmap *im; |
180 |
|
|
|
181 |
|
|
if (!tid) return; |
182 |
|
|
|
183 |
|
|
LIST_FOREACH(im, &map_hash[h], link) |
184 |
|
|
if (im->tid == tid) |
185 |
|
|
break; |
186 |
|
|
|
187 |
|
|
if (!im) return; |
188 |
|
|
|
189 |
|
|
LIST_REMOVE(im, link); |
190 |
|
|
tid_to_hash[tid] = -1; |
191 |
|
|
free(im); |
192 |
|
|
} |
193 |
|
|
|
194 |
|
|
#define READ_OFFSET(field) read_memory(P_thread_##field##_offset, \ |
195 |
|
|
(char *) &field##_offset, \ |
196 |
|
|
sizeof(field##_offset)) |
197 |
|
|
|
198 |
|
|
#define READ_VALUE(name) read_memory(P_thread_##name##_value, \ |
199 |
|
|
(char *) &name##_value, \ |
200 |
|
|
sizeof(name##_value)) |
201 |
|
|
|
202 |
|
|
static void |
203 |
|
|
read_thread_offsets (void) |
204 |
|
|
{ |
205 |
|
|
READ_OFFSET(next); |
206 |
|
|
READ_OFFSET(uniqueid); |
207 |
|
|
READ_OFFSET(state); |
208 |
|
|
READ_OFFSET(name); |
209 |
|
|
READ_OFFSET(ctx); |
210 |
|
|
|
211 |
|
|
READ_VALUE(PS_RUNNING); |
212 |
|
|
READ_VALUE(PS_DEAD); |
213 |
|
|
} |
214 |
|
|
|
215 |
|
|
#define READ_FIELD(ptr, T, field, result) \ |
216 |
|
|
read_memory ((ptr) + field##_offset, (char *) &(result), sizeof result) |
217 |
|
|
|
218 |
|
|
static u_int64_t |
219 |
|
|
read_pthread_uniqueid (CORE_ADDR ptr) |
220 |
|
|
{ |
221 |
|
|
u_int64_t uniqueid; |
222 |
|
|
READ_FIELD(ptr, u_int64_t, uniqueid, uniqueid); |
223 |
|
|
return uniqueid; |
224 |
|
|
} |
225 |
|
|
|
226 |
|
|
static CORE_ADDR |
227 |
|
|
read_pthread_next (CORE_ADDR ptr) |
228 |
|
|
{ |
229 |
|
|
CORE_ADDR next; |
230 |
|
|
READ_FIELD(ptr, CORE_ADDR, next, next); |
231 |
|
|
return next; |
232 |
|
|
} |
233 |
|
|
|
234 |
|
|
static void |
235 |
|
|
read_cached_pthread (CORE_ADDR ptr, struct cached_pthread *cache) |
236 |
|
|
{ |
237 |
|
|
READ_FIELD(ptr, u_int64_t, uniqueid, cache->uniqueid); |
238 |
|
|
READ_FIELD(ptr, int, state, cache->state); |
239 |
|
|
READ_FIELD(ptr, CORE_ADDR, name, cache->name); |
240 |
|
|
READ_FIELD(ptr, ucontext_t, ctx, cache->ctx); |
241 |
|
|
} |
242 |
|
|
|
243 |
|
|
static ptid_t |
244 |
|
|
find_active_ptid (void) |
245 |
|
|
{ |
246 |
|
|
CORE_ADDR ptr; |
247 |
|
|
|
248 |
|
|
read_memory ((CORE_ADDR)P_thread_run, |
249 |
|
|
(char *)&ptr, |
250 |
|
|
sizeof ptr); |
251 |
|
|
|
252 |
|
|
return find_ptid(read_pthread_uniqueid(ptr)); |
253 |
|
|
} |
254 |
|
|
|
255 |
|
|
static CORE_ADDR find_pthread_addr PARAMS ((ptid_t ptid)); |
256 |
|
|
static struct cached_pthread * find_pthread PARAMS ((ptid_t ptid)); |
257 |
|
|
|
258 |
|
|
static CORE_ADDR |
259 |
|
|
find_pthread_addr (ptid_t ptid) |
260 |
|
|
{ |
261 |
|
|
CORE_ADDR ptr; |
262 |
|
|
|
263 |
|
|
if (ptid_equal(ptid, cached_ptid)) |
264 |
|
|
return cached_pthread_addr; |
265 |
|
|
|
266 |
|
|
read_memory ((CORE_ADDR)P_thread_list, |
267 |
|
|
(char *)&ptr, |
268 |
|
|
sizeof ptr); |
269 |
|
|
|
270 |
|
|
while (ptr != 0) |
271 |
|
|
{ |
272 |
|
|
if (ptid_equal(find_ptid(read_pthread_uniqueid(ptr)), ptid)) |
273 |
|
|
{ |
274 |
|
|
cached_ptid = ptid; |
275 |
|
|
cached_pthread_addr = ptr; |
276 |
|
|
read_cached_pthread(ptr, &cached_pthread); |
277 |
|
|
return ptr; |
278 |
|
|
} |
279 |
|
|
ptr = read_pthread_next(ptr); |
280 |
|
|
} |
281 |
|
|
|
282 |
|
|
return NULL; |
283 |
|
|
} |
284 |
|
|
|
285 |
|
|
static struct cached_pthread * |
286 |
|
|
find_pthread (ptid_t ptid) |
287 |
|
|
{ |
288 |
|
|
CORE_ADDR ptr; |
289 |
|
|
|
290 |
|
|
if (ptid_equal(ptid, cached_ptid)) |
291 |
|
|
return &cached_pthread; |
292 |
|
|
|
293 |
|
|
read_memory ((CORE_ADDR)P_thread_list, |
294 |
|
|
(char *)&ptr, |
295 |
|
|
sizeof ptr); |
296 |
|
|
|
297 |
|
|
while (ptr != 0) |
298 |
|
|
{ |
299 |
|
|
if (ptid_equal(find_ptid(read_pthread_uniqueid(ptr)), ptid)) |
300 |
|
|
{ |
301 |
|
|
cached_ptid = ptid; |
302 |
|
|
cached_pthread_addr = ptr; |
303 |
|
|
read_cached_pthread(ptr, &cached_pthread); |
304 |
|
|
return &cached_pthread; |
305 |
|
|
} |
306 |
|
|
ptr = read_pthread_next(ptr); |
307 |
|
|
} |
308 |
|
|
|
309 |
|
|
#if 0 |
310 |
|
|
error ("Can't find pthread %d,%d", PIDGET(ptid), TIDGET(ptid)); |
311 |
|
|
#endif |
312 |
|
|
return NULL; |
313 |
|
|
} |
314 |
|
|
|
315 |
|
|
|
316 |
|
|
/* Most target vector functions from here on actually just pass through to |
317 |
|
|
inftarg.c, as they don't need to do anything specific for threads. */ |
318 |
|
|
|
319 |
|
|
/* ARGSUSED */ |
320 |
|
|
static void |
321 |
|
|
freebsd_uthread_open (char *arg, int from_tty) |
322 |
|
|
{ |
323 |
|
|
child_ops.to_open (arg, from_tty); |
324 |
|
|
} |
325 |
|
|
|
326 |
|
|
/* Attach to process PID, then initialize for debugging it |
327 |
|
|
and wait for the trace-trap that results from attaching. */ |
328 |
|
|
|
329 |
|
|
static void |
330 |
|
|
freebsd_uthread_attach (char *args, int from_tty) |
331 |
|
|
{ |
332 |
|
|
child_ops.to_attach (args, from_tty); |
333 |
|
|
push_target (&freebsd_uthread_ops); |
334 |
|
|
freebsd_uthread_attaching = 1; |
335 |
|
|
} |
336 |
|
|
|
337 |
|
|
/* After an attach, see if the target is threaded */ |
338 |
|
|
|
339 |
|
|
static void |
340 |
|
|
freebsd_uthread_post_attach (int pid) |
341 |
|
|
{ |
342 |
|
|
if (freebsd_uthread_active) |
343 |
|
|
{ |
344 |
|
|
read_thread_offsets (); |
345 |
|
|
inferior_ptid = find_active_ptid (); |
346 |
|
|
add_thread (inferior_ptid); |
347 |
|
|
} |
348 |
|
|
else |
349 |
|
|
{ |
350 |
|
|
unpush_target (&freebsd_uthread_ops); |
351 |
|
|
push_target (&child_ops); |
352 |
|
|
} |
353 |
|
|
|
354 |
|
|
freebsd_uthread_attaching = 0; |
355 |
|
|
} |
356 |
|
|
|
357 |
|
|
/* Take a program previously attached to and detaches it. |
358 |
|
|
The program resumes execution and will no longer stop |
359 |
|
|
on signals, etc. We'd better not have left any breakpoints |
360 |
|
|
in the program or it'll die when it hits one. For this |
361 |
|
|
to work, it may be necessary for the process to have been |
362 |
|
|
previously attached. It *might* work if the program was |
363 |
|
|
started via the normal ptrace (PTRACE_TRACEME). */ |
364 |
|
|
|
365 |
|
|
static void |
366 |
|
|
freebsd_uthread_detach (char *args, int from_tty) |
367 |
|
|
{ |
368 |
|
|
child_ops.to_detach (args, from_tty); |
369 |
|
|
} |
370 |
|
|
|
371 |
|
|
/* Resume execution of process PID. If STEP is nozero, then |
372 |
|
|
just single step it. If SIGNAL is nonzero, restart it with that |
373 |
|
|
signal activated. We may have to convert pid from a thread-id to an LWP id |
374 |
|
|
for procfs. */ |
375 |
|
|
|
376 |
|
|
static void |
377 |
|
|
freebsd_uthread_resume (ptid_t ptid, int step, enum target_signal signo) |
378 |
|
|
{ |
379 |
|
|
if (freebsd_uthread_attaching) |
380 |
|
|
{ |
381 |
|
|
child_ops.to_resume (ptid, step, signo); |
382 |
|
|
return; |
383 |
|
|
} |
384 |
|
|
|
385 |
|
|
child_ops.to_resume (ptid, step, signo); |
386 |
|
|
cached_ptid = MERGEPID(0, 0); |
387 |
|
|
} |
388 |
|
|
|
389 |
|
|
/* Wait for any threads to stop. We may have to convert PID from a thread id |
390 |
|
|
to a LWP id, and vice versa on the way out. */ |
391 |
|
|
|
392 |
|
|
static ptid_t |
393 |
|
|
freebsd_uthread_wait (ptid_t ptid, struct target_waitstatus *ourstatus) |
394 |
|
|
{ |
395 |
|
|
ptid_t rtnval; |
396 |
|
|
|
397 |
|
|
if (freebsd_uthread_attaching) |
398 |
|
|
{ |
399 |
|
|
return child_ops.to_wait (ptid, ourstatus); |
400 |
|
|
} |
401 |
|
|
|
402 |
|
|
rtnval = child_ops.to_wait (ptid, ourstatus); |
403 |
|
|
|
404 |
|
|
if (PIDGET(rtnval) >= 0) |
405 |
|
|
{ |
406 |
|
|
rtnval = find_active_ptid (); |
407 |
|
|
if (!in_thread_list (rtnval)) |
408 |
|
|
add_thread (rtnval); |
409 |
|
|
} |
410 |
|
|
|
411 |
|
|
return rtnval; |
412 |
|
|
} |
413 |
|
|
|
414 |
|
|
/* XXX: this needs to be selected by target, not [build] host */ |
415 |
|
|
#ifdef __i386__ |
416 |
|
|
|
417 |
|
|
#include "i386-tdep.h" |
418 |
|
|
|
419 |
|
|
static char sigmap[I386_SSE_NUM_REGS] = /* map reg to sigcontext */ |
420 |
|
|
{ |
421 |
|
|
12, /* eax */ |
422 |
|
|
11, /* ecx */ |
423 |
|
|
10, /* edx */ |
424 |
|
|
9, /* ebx */ |
425 |
|
|
8, /* esp */ |
426 |
|
|
7, /* ebp */ |
427 |
|
|
6, /* esi */ |
428 |
|
|
5, /* edi */ |
429 |
|
|
15, /* eip */ |
430 |
|
|
17, /* eflags */ |
431 |
|
|
16, /* cs */ |
432 |
|
|
19, /* ss */ |
433 |
|
|
4, /* ds */ |
434 |
|
|
3, /* es */ |
435 |
|
|
2, /* fs */ |
436 |
|
|
1, /* gs */ |
437 |
|
|
-1, -1, -1, -1, -1, -1, -1, /* st0-st7 */ |
438 |
|
|
-1, -1, -1, -1, -1, -1, -1, /* fctrl-fop */ |
439 |
|
|
-1, -1, -1, -1, -1, -1, -1, /* xmm0-xmm7 */ |
440 |
|
|
-1, /* mxcsr */ |
441 |
|
|
}; |
442 |
|
|
|
443 |
|
|
static char jmpmap[I386_SSE_NUM_REGS] = /* map reg to jmp_buf */ |
444 |
|
|
{ |
445 |
|
|
6, /* eax */ |
446 |
|
|
-1, /* ecx */ |
447 |
|
|
-1, /* edx */ |
448 |
|
|
1, /* ebx */ |
449 |
|
|
2, /* esp */ |
450 |
|
|
3, /* ebp */ |
451 |
|
|
4, /* esi */ |
452 |
|
|
5, /* edi */ |
453 |
|
|
0, /* eip */ |
454 |
|
|
-1, /* eflags */ |
455 |
|
|
-1, /* cs */ |
456 |
|
|
-1, /* ss */ |
457 |
|
|
-1, /* ds */ |
458 |
|
|
-1, /* es */ |
459 |
|
|
-1, /* fs */ |
460 |
|
|
-1, /* gs */ |
461 |
|
|
-1, -1, -1, -1, -1, -1, -1, /* st0-st7 */ |
462 |
|
|
-1, -1, -1, -1, -1, -1, -1, /* fctrl-fop */ |
463 |
|
|
-1, -1, -1, -1, -1, -1, -1, /* xmm0-xmm7 */ |
464 |
|
|
-1, /* mxcsr */ |
465 |
|
|
}; |
466 |
|
|
|
467 |
|
|
#endif |
468 |
|
|
|
469 |
|
|
#ifdef __amd64__ |
470 |
|
|
|
471 |
|
|
#include "amd64-tdep.h" |
472 |
|
|
|
473 |
|
|
// XXX:DEO not fully ported from i386 yet!! |
474 |
|
|
|
475 |
|
|
static char sigmap[AMD64_NUM_REGS_TOTAL] = /* map reg to sigcontext */ |
476 |
|
|
{ |
477 |
|
|
12, /* rax */ |
478 |
|
|
11, /* rcx */ |
479 |
|
|
10, /* rdx */ |
480 |
|
|
9, /* rbx */ |
481 |
|
|
8, /* rsp */ |
482 |
|
|
7, /* rbp */ |
483 |
|
|
6, /* rsi */ |
484 |
|
|
5, /* rdi */ |
485 |
|
|
15, /* rip */ |
486 |
|
|
17, /* rflags */ |
487 |
|
|
16, /* cs */ |
488 |
|
|
19, /* ss */ |
489 |
|
|
4, /* ds */ |
490 |
|
|
3, /* es */ |
491 |
|
|
2, /* fs */ |
492 |
|
|
1, /* gs */ |
493 |
|
|
-1, -1, -1, -1, -1, -1, -1, /* st0-st7 */ |
494 |
|
|
-1, -1, -1, -1, -1, -1, -1, /* fctrl-fop */ |
495 |
|
|
-1, -1, -1, -1, -1, -1, -1, /* xmm0-xmm7 */ |
496 |
|
|
-1, /* mxcsr */ |
497 |
|
|
}; |
498 |
|
|
|
499 |
|
|
static char jmpmap[AMD64_NUM_REGS_TOTAL] = /* map reg to jmp_buf */ |
500 |
|
|
{ |
501 |
|
|
6, /* rax */ |
502 |
|
|
-1, /* rcx */ |
503 |
|
|
-1, /* rdx */ |
504 |
|
|
1, /* rbx */ |
505 |
|
|
2, /* rsp */ |
506 |
|
|
3, /* rbp */ |
507 |
|
|
4, /* rsi */ |
508 |
|
|
5, /* rdi */ |
509 |
|
|
0, /* rip */ |
510 |
|
|
-1, /* rflags */ |
511 |
|
|
-1, /* cs */ |
512 |
|
|
-1, /* ss */ |
513 |
|
|
-1, /* ds */ |
514 |
|
|
-1, /* es */ |
515 |
|
|
-1, /* fs */ |
516 |
|
|
-1, /* gs */ |
517 |
|
|
-1, -1, -1, -1, -1, -1, -1, /* st0-st7 */ |
518 |
|
|
-1, -1, -1, -1, -1, -1, -1, /* fctrl-fop */ |
519 |
|
|
-1, -1, -1, -1, -1, -1, -1, /* xmm0-xmm7 */ |
520 |
|
|
-1, /* mxcsr */ |
521 |
|
|
}; |
522 |
|
|
|
523 |
|
|
#endif |
524 |
|
|
|
525 |
|
|
#ifdef __alpha__ |
526 |
|
|
|
527 |
|
|
#include "alpha-tdep.h" |
528 |
|
|
|
529 |
|
|
static char sigmap[ALPHA_NUM_REGS] = /* map reg to sigcontext */ |
530 |
|
|
{ |
531 |
|
|
1, 2, 3, 4, 5, 6, 7, 8, /* v0 - t6 */ |
532 |
|
|
9, 10, 11, 12, 13, 14, 15, 16, /* t7 - fp */ |
533 |
|
|
17, 18, 19, 20, 21, 22, 23, 24, /* a0 - t9 */ |
534 |
|
|
25, 26, 27, 28, 29, 30, 31, 32, /* t10 - zero */ |
535 |
|
|
38, 39, 40, 41, 42, 43, 44, 45, /* f0 - f7 */ |
536 |
|
|
46, 47, 48, 49, 50, 51, 52, 53, /* f8 - f15 */ |
537 |
|
|
54, 55, 56, 57, 58, 59, 60, 61, /* f16 - f23 */ |
538 |
|
|
62, 63, 64, 65, 66, 67, 68, 69, /* f24 - f31 */ |
539 |
|
|
33, -1 /* pc, vfp */ |
540 |
|
|
}; |
541 |
|
|
static char jmpmap[ALPHA_NUM_REGS] = { |
542 |
|
|
4, 5, 6, 7, 8, 9, 10, 11, /* v0 - t6 */ |
543 |
|
|
12, 13, 14, 15, 16, 17, 18, 19, /* t7 - fp */ |
544 |
|
|
20, 21, 22, 23, 24, 25, 26, 27, /* a0 - t9 */ |
545 |
|
|
28, 29, 30, 31, 32, 33, 34, 35, /* t10 - zero */ |
546 |
|
|
37, 38, 39, 40, 41, 42, 43, 44, /* f0 - f7 */ |
547 |
|
|
45, 46, 47, 48, 49, 50, 51, 52, /* f8 - f15 */ |
548 |
|
|
53, 54, 55, 56, 57, 58, 59, 60, /* f16 - f23 */ |
549 |
|
|
61, 62, 63, 64, 65, 66, 67, 68, /* f24 - f31 */ |
550 |
|
|
2, -1, /* pc, vfp */ |
551 |
|
|
}; |
552 |
|
|
|
553 |
|
|
#endif |
554 |
|
|
|
555 |
|
|
#ifdef __sparc64__ |
556 |
|
|
|
557 |
|
|
static char sigmap[125] = /* map reg to sigcontext */ |
558 |
|
|
{ |
559 |
|
|
-1 |
560 |
|
|
}; |
561 |
|
|
static char jmpmap[125] = { |
562 |
|
|
-1 |
563 |
|
|
}; |
564 |
|
|
|
565 |
|
|
#endif |
566 |
|
|
|
567 |
|
|
static void |
568 |
|
|
freebsd_uthread_fetch_registers (int regno) |
569 |
|
|
{ |
570 |
|
|
struct cached_pthread *thread; |
571 |
|
|
int active; |
572 |
|
|
int first_regno, last_regno; |
573 |
|
|
register_t *regbase; |
574 |
|
|
char *regmap; |
575 |
|
|
|
576 |
|
|
if (freebsd_uthread_attaching || TIDGET(inferior_ptid) == 0) |
577 |
|
|
{ |
578 |
|
|
child_ops.to_fetch_registers (regno); |
579 |
|
|
return; |
580 |
|
|
} |
581 |
|
|
|
582 |
|
|
thread = find_pthread (inferior_ptid); |
583 |
|
|
active = (ptid_equal(inferior_ptid, find_active_ptid())); |
584 |
|
|
|
585 |
|
|
if (active) |
586 |
|
|
{ |
587 |
|
|
child_ops.to_fetch_registers (regno); |
588 |
|
|
return; |
589 |
|
|
} |
590 |
|
|
|
591 |
|
|
if (regno == -1) |
592 |
|
|
{ |
593 |
|
|
first_regno = 0; |
594 |
|
|
last_regno = NUM_REGS - 1; |
595 |
|
|
} |
596 |
|
|
else |
597 |
|
|
{ |
598 |
|
|
first_regno = regno; |
599 |
|
|
last_regno = regno; |
600 |
|
|
} |
601 |
|
|
|
602 |
|
|
regbase = (register_t*) &thread->ctx.jb[0]; |
603 |
|
|
regmap = jmpmap; |
604 |
|
|
|
605 |
|
|
for (regno = first_regno; regno <= last_regno; regno++) |
606 |
|
|
{ |
607 |
|
|
if (regmap[regno] == -1) |
608 |
|
|
child_ops.to_fetch_registers (regno); |
609 |
|
|
else |
610 |
|
|
if (thread) |
611 |
|
|
regcache_raw_supply (current_regcache, regno, (char*) ®base[regmap[regno]]); |
612 |
|
|
else |
613 |
|
|
regcache_raw_supply (current_regcache, regno, NULL); |
614 |
|
|
} |
615 |
|
|
} |
616 |
|
|
|
617 |
|
|
static void |
618 |
|
|
freebsd_uthread_store_registers (int regno) |
619 |
|
|
{ |
620 |
|
|
struct cached_pthread *thread; |
621 |
|
|
CORE_ADDR ptr; |
622 |
|
|
int first_regno, last_regno; |
623 |
|
|
u_int32_t *regbase; |
624 |
|
|
char *regmap; |
625 |
|
|
|
626 |
|
|
if (freebsd_uthread_attaching) |
627 |
|
|
{ |
628 |
|
|
child_ops.to_store_registers (regno); |
629 |
|
|
return; |
630 |
|
|
} |
631 |
|
|
|
632 |
|
|
thread = find_pthread (inferior_ptid); |
633 |
|
|
|
634 |
|
|
if (thread->state == PS_RUNNING_value) |
635 |
|
|
{ |
636 |
|
|
child_ops.to_store_registers (regno); |
637 |
|
|
return; |
638 |
|
|
} |
639 |
|
|
|
640 |
|
|
if (regno == -1) |
641 |
|
|
{ |
642 |
|
|
first_regno = 0; |
643 |
|
|
last_regno = NUM_REGS - 1; |
644 |
|
|
} |
645 |
|
|
else |
646 |
|
|
{ |
647 |
|
|
first_regno = regno; |
648 |
|
|
last_regno = regno; |
649 |
|
|
} |
650 |
|
|
|
651 |
|
|
regbase = (u_int32_t*) &thread->ctx.jb[0]; |
652 |
|
|
regmap = jmpmap; |
653 |
|
|
|
654 |
|
|
ptr = find_pthread_addr (inferior_ptid); |
655 |
|
|
for (regno = first_regno; regno <= last_regno; regno++) |
656 |
|
|
{ |
657 |
|
|
if (regmap[regno] == -1) |
658 |
|
|
child_ops.to_store_registers (regno); |
659 |
|
|
else |
660 |
|
|
{ |
661 |
|
|
u_int32_t *reg = ®base[regmap[regno]]; |
662 |
|
|
int off; |
663 |
|
|
|
664 |
|
|
/* Hang onto cached value */ |
665 |
|
|
/*DEO:XXX*/ |
666 |
|
|
memcpy(reg, deprecated_registers /*regcache_collect ()*/+ DEPRECATED_REGISTER_BYTE (regno), |
667 |
|
|
DEPRECATED_REGISTER_RAW_SIZE (regno)); |
668 |
|
|
|
669 |
|
|
/* And push out to inferior */ |
670 |
|
|
off = (char *) reg - (char *) thread; |
671 |
|
|
write_memory (ptr + off, |
672 |
|
|
/*DEO:XXX*/ |
673 |
|
|
deprecated_registers /*regcache_collect ()*/+ DEPRECATED_REGISTER_BYTE (regno), |
674 |
|
|
DEPRECATED_REGISTER_RAW_SIZE (regno)); |
675 |
|
|
} |
676 |
|
|
} |
677 |
|
|
} |
678 |
|
|
|
679 |
|
|
/* Get ready to modify the registers array. On machines which store |
680 |
|
|
individual registers, this doesn't need to do anything. On machines |
681 |
|
|
which store all the registers in one fell swoop, this makes sure |
682 |
|
|
that registers contains all the registers from the program being |
683 |
|
|
debugged. */ |
684 |
|
|
|
685 |
|
|
static void |
686 |
|
|
freebsd_uthread_prepare_to_store (void) |
687 |
|
|
{ |
688 |
|
|
child_ops.to_prepare_to_store (); |
689 |
|
|
} |
690 |
|
|
|
691 |
|
|
static int |
692 |
|
|
freebsd_uthread_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, |
693 |
|
|
int dowrite, struct mem_attrib *attrib, |
694 |
|
|
struct target_ops *target) |
695 |
|
|
{ |
696 |
|
|
return child_ops.to_xfer_memory (memaddr, myaddr, len, dowrite, |
697 |
|
|
attrib, target); |
698 |
|
|
} |
699 |
|
|
|
700 |
|
|
/* Print status information about what we're accessing. */ |
701 |
|
|
|
702 |
|
|
static void |
703 |
|
|
freebsd_uthread_files_info (struct target_ops *ignore) |
704 |
|
|
{ |
705 |
|
|
child_ops.to_files_info (ignore); |
706 |
|
|
} |
707 |
|
|
|
708 |
|
|
static void |
709 |
|
|
freebsd_uthread_kill_inferior (void) |
710 |
|
|
{ |
711 |
|
|
child_ops.to_kill (); |
712 |
|
|
} |
713 |
|
|
|
714 |
|
|
static void |
715 |
|
|
freebsd_uthread_notice_signals (ptid_t ptid) |
716 |
|
|
{ |
717 |
|
|
child_ops.to_notice_signals (ptid); |
718 |
|
|
} |
719 |
|
|
|
720 |
|
|
/* Fork an inferior process, and start debugging it with /proc. */ |
721 |
|
|
|
722 |
|
|
static void |
723 |
|
|
freebsd_uthread_create_inferior (char *exec_file, char *allargs, char **env, |
724 |
|
|
int from_tty) |
725 |
|
|
{ |
726 |
|
|
child_ops.to_create_inferior (exec_file, allargs, env, from_tty); |
727 |
|
|
|
728 |
|
|
if (PIDGET(inferior_ptid) && freebsd_uthread_active) |
729 |
|
|
{ |
730 |
|
|
read_thread_offsets (); |
731 |
|
|
push_target (&freebsd_uthread_ops); |
732 |
|
|
inferior_ptid = find_active_ptid (); |
733 |
|
|
add_thread (inferior_ptid); |
734 |
|
|
} |
735 |
|
|
} |
736 |
|
|
|
737 |
|
|
/* This routine is called to find out if the inferior is using threads. |
738 |
|
|
We check for the _thread_run and _thread_list globals. */ |
739 |
|
|
|
740 |
|
|
void |
741 |
|
|
freebsd_uthread_new_objfile (struct objfile *objfile) |
742 |
|
|
{ |
743 |
|
|
struct minimal_symbol *ms; |
744 |
|
|
|
745 |
|
|
if (!objfile) |
746 |
|
|
{ |
747 |
|
|
freebsd_uthread_active = 0; |
748 |
|
|
return; |
749 |
|
|
} |
750 |
|
|
|
751 |
|
|
ms = lookup_minimal_symbol ("_thread_run", NULL, objfile); |
752 |
|
|
|
753 |
|
|
if (!ms) |
754 |
|
|
return; |
755 |
|
|
|
756 |
|
|
P_thread_run = SYMBOL_VALUE_ADDRESS (ms); |
757 |
|
|
|
758 |
|
|
ms = lookup_minimal_symbol ("_thread_list", NULL, objfile); |
759 |
|
|
|
760 |
|
|
if (!ms) |
761 |
|
|
return; |
762 |
|
|
|
763 |
|
|
P_thread_list = SYMBOL_VALUE_ADDRESS (ms); |
764 |
|
|
|
765 |
|
|
#define OFFSET_SYM(field) "_thread_" #field "_offset" |
766 |
|
|
#define LOOKUP_OFFSET(field) \ |
767 |
|
|
do { \ |
768 |
|
|
ms = lookup_minimal_symbol (OFFSET_SYM(field), NULL, objfile); \ |
769 |
|
|
if (!ms) \ |
770 |
|
|
return; \ |
771 |
|
|
P_thread_##field##_offset = SYMBOL_VALUE_ADDRESS (ms); \ |
772 |
|
|
} while (0); |
773 |
|
|
|
774 |
|
|
#define VALUE_SYM(name) "_thread_" #name "_value" |
775 |
|
|
#define LOOKUP_VALUE(name) \ |
776 |
|
|
do { \ |
777 |
|
|
ms = lookup_minimal_symbol (VALUE_SYM(name), NULL, objfile); \ |
778 |
|
|
if (!ms) \ |
779 |
|
|
return; \ |
780 |
|
|
P_thread_##name##_value = SYMBOL_VALUE_ADDRESS (ms); \ |
781 |
|
|
} while (0); |
782 |
|
|
|
783 |
|
|
LOOKUP_OFFSET(next); |
784 |
|
|
LOOKUP_OFFSET(uniqueid); |
785 |
|
|
LOOKUP_OFFSET(state); |
786 |
|
|
LOOKUP_OFFSET(name); |
787 |
|
|
LOOKUP_OFFSET(ctx); |
788 |
|
|
|
789 |
|
|
LOOKUP_VALUE(PS_RUNNING); |
790 |
|
|
LOOKUP_VALUE(PS_DEAD); |
791 |
|
|
|
792 |
|
|
freebsd_uthread_active = 1; |
793 |
|
|
} |
794 |
|
|
|
795 |
|
|
/* Clean up after the inferior dies. */ |
796 |
|
|
|
797 |
|
|
static void |
798 |
|
|
freebsd_uthread_mourn_inferior () |
799 |
|
|
{ |
800 |
|
|
child_ops.to_mourn_inferior (); |
801 |
|
|
unpush_target (&freebsd_uthread_ops); |
802 |
|
|
} |
803 |
|
|
|
804 |
|
|
/* Mark our target-struct as eligible for stray "run" and "attach" commands. */ |
805 |
|
|
|
806 |
|
|
static int |
807 |
|
|
freebsd_uthread_can_run () |
808 |
|
|
{ |
809 |
|
|
return child_suppress_run; |
810 |
|
|
} |
811 |
|
|
|
812 |
|
|
static int |
813 |
|
|
freebsd_uthread_thread_alive (ptid_t ptid) |
814 |
|
|
{ |
815 |
|
|
struct cached_pthread *thread; |
816 |
|
|
int ret = 0; |
817 |
|
|
|
818 |
|
|
if (freebsd_uthread_attaching) |
819 |
|
|
return 1; |
820 |
|
|
|
821 |
|
|
/* |
822 |
|
|
* We can get called from child_ops.to_wait() which passes the underlying |
823 |
|
|
* pid (without a thread number). |
824 |
|
|
*/ |
825 |
|
|
if (TIDGET(ptid) == 0) |
826 |
|
|
return 1; |
827 |
|
|
|
828 |
|
|
if (find_pthread_addr (ptid) != 0) |
829 |
|
|
{ |
830 |
|
|
thread = find_pthread (ptid); |
831 |
|
|
ret = (thread->state != PS_DEAD_value); |
832 |
|
|
} |
833 |
|
|
|
834 |
|
|
if (!ret) |
835 |
|
|
free_ptid(ptid); |
836 |
|
|
|
837 |
|
|
return ret; |
838 |
|
|
} |
839 |
|
|
|
840 |
|
|
static void |
841 |
|
|
freebsd_uthread_stop (void) |
842 |
|
|
{ |
843 |
|
|
child_ops.to_stop (); |
844 |
|
|
} |
845 |
|
|
|
846 |
|
|
static void |
847 |
|
|
freebsd_uthread_find_new_threads (void) |
848 |
|
|
{ |
849 |
|
|
CORE_ADDR ptr; |
850 |
|
|
int state; |
851 |
|
|
u_int64_t uniqueid; |
852 |
|
|
|
853 |
|
|
read_memory ((CORE_ADDR)P_thread_list, |
854 |
|
|
(char *)&ptr, |
855 |
|
|
sizeof ptr); |
856 |
|
|
|
857 |
|
|
while (ptr != 0) |
858 |
|
|
{ |
859 |
|
|
READ_FIELD(ptr, int, state, state); |
860 |
|
|
READ_FIELD(ptr, u_int64_t, uniqueid, uniqueid); |
861 |
|
|
if (state != PS_DEAD_value && |
862 |
|
|
!in_thread_list (find_ptid(uniqueid))) |
863 |
|
|
add_thread (find_ptid(uniqueid)); |
864 |
|
|
ptr = read_pthread_next(ptr); |
865 |
|
|
} |
866 |
|
|
} |
867 |
|
|
|
868 |
|
|
/* MUST MATCH enum pthread_state */ |
869 |
|
|
static const char *statenames[] = { |
870 |
|
|
"RUNNING", |
871 |
|
|
"SIGTHREAD", |
872 |
|
|
"MUTEX_WAIT", |
873 |
|
|
"COND_WAIT", |
874 |
|
|
"FDLR_WAIT", |
875 |
|
|
"FDLW_WAIT", |
876 |
|
|
"FDR_WAIT", |
877 |
|
|
"FDW_WAIT", |
878 |
|
|
"POLL_WAIT", |
879 |
|
|
"FILE_WAIT", |
880 |
|
|
"SELECT_WAIT", |
881 |
|
|
"SLEEP_WAIT", |
882 |
|
|
"WAIT_WAIT", |
883 |
|
|
"SIGSUSPEND", |
884 |
|
|
"SIGWAIT", |
885 |
|
|
"SPINBLOCK", |
886 |
|
|
"JOIN", |
887 |
|
|
"SUSPENDED", |
888 |
|
|
"DEAD", |
889 |
|
|
"DEADLOCK", |
890 |
|
|
}; |
891 |
|
|
|
892 |
|
|
#if 0 |
893 |
|
|
|
894 |
|
|
static int |
895 |
|
|
freebsd_uthread_get_thread_info (ref, selection, info) |
896 |
|
|
gdb_threadref *ref; |
897 |
|
|
int selection; |
898 |
|
|
struct gdb_ext_thread_info *info; |
899 |
|
|
{ |
900 |
|
|
int pid = *ref; |
901 |
|
|
struct cached_pthread *thread = find_pthread (pid); |
902 |
|
|
struct cleanup *old_chain; |
903 |
|
|
|
904 |
|
|
old_chain = save_inferior_pid (); |
905 |
|
|
inferior_pid = main_pid; |
906 |
|
|
|
907 |
|
|
memset(&info->threadid, 0, OPAQUETHREADBYTES); |
908 |
|
|
|
909 |
|
|
memcpy(&info->threadid, ref, sizeof *ref); |
910 |
|
|
info->active = thread->state == PS_RUNNING_value; |
911 |
|
|
strcpy(info->display, statenames[thread->state]); |
912 |
|
|
if (thread->name) |
913 |
|
|
read_memory ((CORE_ADDR) thread->name, info->shortname, 32); |
914 |
|
|
else |
915 |
|
|
strcpy(info->shortname, ""); |
916 |
|
|
|
917 |
|
|
do_cleanups (old_chain); |
918 |
|
|
return (0); |
919 |
|
|
} |
920 |
|
|
|
921 |
|
|
#endif |
922 |
|
|
|
923 |
|
|
char * |
924 |
|
|
freebsd_uthread_pid_to_str (ptid_t ptid) |
925 |
|
|
{ |
926 |
|
|
static char buf[30]; |
927 |
|
|
|
928 |
|
|
if (DEPRECATED_STREQ (current_target.to_shortname, "freebsd-uthreads")) |
929 |
|
|
sprintf (buf, "Process %d, Thread %ld", |
930 |
|
|
PIDGET(ptid), TIDGET(ptid)); |
931 |
|
|
else |
932 |
|
|
sprintf (buf, "Process %d", PIDGET(ptid)); |
933 |
|
|
|
934 |
|
|
return buf; |
935 |
|
|
} |
936 |
|
|
|
937 |
|
|
|
938 |
|
|
static void |
939 |
|
|
init_freebsd_uthread_ops () |
940 |
|
|
{ |
941 |
|
|
freebsd_uthread_ops.to_shortname = "freebsd-uthreads"; |
942 |
|
|
freebsd_uthread_ops.to_longname = "FreeBSD uthreads"; |
943 |
|
|
freebsd_uthread_ops.to_doc = "FreeBSD user threads support."; |
944 |
|
|
freebsd_uthread_ops.to_open = freebsd_uthread_open; |
945 |
|
|
freebsd_uthread_ops.to_attach = freebsd_uthread_attach; |
946 |
|
|
freebsd_uthread_ops.to_post_attach = freebsd_uthread_post_attach; |
947 |
|
|
freebsd_uthread_ops.to_detach = freebsd_uthread_detach; |
948 |
|
|
freebsd_uthread_ops.to_resume = freebsd_uthread_resume; |
949 |
|
|
freebsd_uthread_ops.to_wait = freebsd_uthread_wait; |
950 |
|
|
freebsd_uthread_ops.to_fetch_registers = freebsd_uthread_fetch_registers; |
951 |
|
|
freebsd_uthread_ops.to_store_registers = freebsd_uthread_store_registers; |
952 |
|
|
freebsd_uthread_ops.to_prepare_to_store = freebsd_uthread_prepare_to_store; |
953 |
|
|
freebsd_uthread_ops.to_xfer_memory = freebsd_uthread_xfer_memory; |
954 |
|
|
freebsd_uthread_ops.to_files_info = freebsd_uthread_files_info; |
955 |
|
|
freebsd_uthread_ops.to_insert_breakpoint = memory_insert_breakpoint; |
956 |
|
|
freebsd_uthread_ops.to_remove_breakpoint = memory_remove_breakpoint; |
957 |
|
|
freebsd_uthread_ops.to_terminal_init = terminal_init_inferior; |
958 |
|
|
freebsd_uthread_ops.to_terminal_inferior = terminal_inferior; |
959 |
|
|
freebsd_uthread_ops.to_terminal_ours_for_output = terminal_ours_for_output; |
960 |
|
|
freebsd_uthread_ops.to_terminal_ours = terminal_ours; |
961 |
|
|
freebsd_uthread_ops.to_terminal_info = child_terminal_info; |
962 |
|
|
freebsd_uthread_ops.to_kill = freebsd_uthread_kill_inferior; |
963 |
|
|
freebsd_uthread_ops.to_create_inferior = freebsd_uthread_create_inferior; |
964 |
|
|
freebsd_uthread_ops.to_mourn_inferior = freebsd_uthread_mourn_inferior; |
965 |
|
|
freebsd_uthread_ops.to_can_run = freebsd_uthread_can_run; |
966 |
|
|
freebsd_uthread_ops.to_notice_signals = freebsd_uthread_notice_signals; |
967 |
|
|
freebsd_uthread_ops.to_thread_alive = freebsd_uthread_thread_alive; |
968 |
|
|
freebsd_uthread_ops.to_stop = freebsd_uthread_stop; |
969 |
|
|
freebsd_uthread_ops.to_stratum = process_stratum; |
970 |
|
|
freebsd_uthread_ops.to_has_all_memory = 1; |
971 |
|
|
freebsd_uthread_ops.to_has_memory = 1; |
972 |
|
|
freebsd_uthread_ops.to_has_stack = 1; |
973 |
|
|
freebsd_uthread_ops.to_has_registers = 1; |
974 |
|
|
freebsd_uthread_ops.to_has_execution = 1; |
975 |
|
|
freebsd_uthread_ops.to_has_thread_control = 0; |
976 |
|
|
freebsd_uthread_ops.to_magic = OPS_MAGIC; |
977 |
|
|
freebsd_uthread_ops.to_find_new_threads = freebsd_uthread_find_new_threads; |
978 |
|
|
freebsd_uthread_ops.to_pid_to_str = freebsd_uthread_pid_to_str; |
979 |
|
|
#if 0 |
980 |
|
|
freebsd_uthread_vec.get_thread_info = freebsd_uthread_get_thread_info; |
981 |
|
|
#endif |
982 |
|
|
} |
983 |
|
|
|
984 |
|
|
void |
985 |
|
|
_initialize_freebsd_uthread () |
986 |
|
|
{ |
987 |
|
|
init_freebsd_uthread_ops (); |
988 |
|
|
add_target (&freebsd_uthread_ops); |
989 |
|
|
|
990 |
|
|
target_new_objfile_chain = deprecated_target_new_objfile_hook; |
991 |
|
|
deprecated_target_new_objfile_hook = freebsd_uthread_new_objfile; |
992 |
|
|
|
993 |
|
|
child_suppress_run = 1; |
994 |
|
|
} |