mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-29 15:00:34 +00:00
* dec-thread.c: New file.
* config/alpha/alpha-osf3.mh (NATDEPFILES): Add dec-thread.o. (NAT_CLIBS): Define.
This commit is contained in:
parent
cb8f3167e3
commit
7a052092c3
@ -1,3 +1,9 @@
|
||||
2008-10-19 Joel Brobecker <brobecker@adacore.com>
|
||||
|
||||
* dec-thread.c: New file.
|
||||
* config/alpha/alpha-osf3.mh (NATDEPFILES): Add dec-thread.o.
|
||||
(NAT_CLIBS): Define.
|
||||
|
||||
2008-10-19 Hui Zhu <teawater@gmail.com>
|
||||
|
||||
* infrun.c (handle_inferior_event): Set "stop_pc" when
|
||||
|
@ -2,4 +2,5 @@
|
||||
NAT_FILE= nm-osf3.h
|
||||
NATDEPFILES= corelow.o alpha-nat.o fork-child.o \
|
||||
solib-osf.o solib.o procfs.o proc-api.o proc-events.o proc-flags.o \
|
||||
proc-why.o
|
||||
proc-why.o dec-thread.o
|
||||
NAT_CLIBS= -lpthreaddebug
|
||||
|
683
gdb/dec-thread.c
Normal file
683
gdb/dec-thread.c
Normal file
@ -0,0 +1,683 @@
|
||||
/* Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "command.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "target.h"
|
||||
#include "observer.h"
|
||||
#include <sys/procfs.h>
|
||||
#include "gregset.h"
|
||||
#include "regcache.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbthread.h"
|
||||
|
||||
#include <pthread_debug.h>
|
||||
|
||||
/* Print debugging traces if set to non-zero. */
|
||||
static int debug_dec_thread = 0;
|
||||
|
||||
/* Non-zero if the dec-thread layer is active. */
|
||||
static int dec_thread_active = 0;
|
||||
|
||||
/* The pthread_debug context. */
|
||||
pthreadDebugContext_t debug_context;
|
||||
|
||||
/* The dec-thread target_ops structure. */
|
||||
static struct target_ops dec_thread_ops;
|
||||
|
||||
/* A copy of the target_ops over which our dec_thread_ops is pushed. */
|
||||
static struct target_ops base_target;
|
||||
|
||||
/* Print a debug trace if DEBUG_DEC_THREAD is set (its value is adjusted
|
||||
by the user using "set debug dec-thread ..."). */
|
||||
|
||||
static void
|
||||
debug (char *format, ...)
|
||||
{
|
||||
if (debug_dec_thread)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
printf_unfiltered ("DEC Threads: ");
|
||||
vprintf_unfiltered (format, args);
|
||||
printf_unfiltered ("\n");
|
||||
va_end (args);
|
||||
}
|
||||
}
|
||||
|
||||
/* pthread debug callbacks. */
|
||||
|
||||
static int
|
||||
suspend_clbk (void *caller_context)
|
||||
{
|
||||
return ESUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
resume_clbk (void *caller_context)
|
||||
{
|
||||
return ESUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
hold_clbk (void *caller_context, pthreadDebugKId_t kernel_tid)
|
||||
{
|
||||
return ESUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
unhold_clbk (void *caller_context, pthreadDebugKId_t kernel_tid)
|
||||
{
|
||||
return ESUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
read_clbk (void *caller_context, void *address, void *buffer,
|
||||
unsigned long size)
|
||||
{
|
||||
int status = target_read_memory ((CORE_ADDR) address, buffer, size);
|
||||
|
||||
if (status != 0)
|
||||
return EINVAL;
|
||||
|
||||
return ESUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
write_clbk (void *caller_context, void *address, void *buffer,
|
||||
unsigned long size)
|
||||
{
|
||||
int status = target_write_memory ((CORE_ADDR) address, buffer, size);
|
||||
|
||||
if (status != 0)
|
||||
return EINVAL;
|
||||
|
||||
return ESUCCESS;
|
||||
}
|
||||
|
||||
/* Get integer regs */
|
||||
|
||||
static int
|
||||
get_reg_clbk(void *caller_context, pthreadDebugGetRegRtn_t regs,
|
||||
pthreadDebugKId_t kernel_tid)
|
||||
{
|
||||
debug ("get_reg_clbk");
|
||||
|
||||
/* Not sure that we actually need to do anything in this callback. */
|
||||
return ESUCCESS;
|
||||
}
|
||||
|
||||
/* Set integer regs */
|
||||
|
||||
static int
|
||||
set_reg_clbk(void *caller_context, const pthreadDebugRegs_t *regs,
|
||||
pthreadDebugKId_t kernel_tid)
|
||||
{
|
||||
debug ("set_reg_clbk");
|
||||
|
||||
/* Not sure that we actually need to do anything in this callback. */
|
||||
return ESUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
output_clbk (void *caller_context, char *line)
|
||||
{
|
||||
printf_filtered ("%s\n", line);
|
||||
return ESUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
error_clbk (void *caller_context, char *line)
|
||||
{
|
||||
fprintf_filtered (gdb_stderr, "%s\n", line);
|
||||
return ESUCCESS;
|
||||
}
|
||||
|
||||
/* Get floating-point regs. */
|
||||
|
||||
static int
|
||||
get_fpreg_clbk (void *caller_context, pthreadDebugFregs_p fregs,
|
||||
pthreadDebugKId_t kernel_tid)
|
||||
{
|
||||
debug ("get_fpreg_clbk");
|
||||
|
||||
/* Not sure that we actually need to do anything in this callback. */
|
||||
return ESUCCESS;
|
||||
}
|
||||
|
||||
/* Set floating-point regs. */
|
||||
|
||||
static int
|
||||
set_fpreg_clbk (void *caller_context, const pthreadDebugFregs_t *fregs,
|
||||
pthreadDebugKId_t kernel_tid)
|
||||
{
|
||||
debug ("set_fpreg_clbk");
|
||||
|
||||
/* Not sure that we actually need to do anything in this callback. */
|
||||
return ESUCCESS;
|
||||
}
|
||||
|
||||
static void *
|
||||
malloc_clbk (void *caller_context, size_t size)
|
||||
{
|
||||
return xmalloc (size);
|
||||
}
|
||||
|
||||
static void
|
||||
free_clbk (void *caller_context, void *address)
|
||||
{
|
||||
xfree (address);
|
||||
}
|
||||
|
||||
static int
|
||||
kthdinfo_clbk (pthreadDebugClient_t caller_context,
|
||||
pthreadDebugKId_t kernel_tid,
|
||||
pthreadDebugKThreadInfo_p thread_info)
|
||||
{
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
static int
|
||||
speckthd_clbk (pthreadDebugClient_t caller_context,
|
||||
pthreadDebugSpecialType_t type,
|
||||
pthreadDebugKId_t *kernel_tid)
|
||||
{
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
static pthreadDebugCallbacks_t debug_callbacks =
|
||||
{
|
||||
PTHREAD_DEBUG_VERSION,
|
||||
(pthreadDebugGetMemRtn_t) read_clbk,
|
||||
(pthreadDebugSetMemRtn_t) write_clbk,
|
||||
suspend_clbk,
|
||||
resume_clbk,
|
||||
kthdinfo_clbk,
|
||||
hold_clbk,
|
||||
unhold_clbk,
|
||||
(pthreadDebugGetFregRtn_t) get_fpreg_clbk,
|
||||
(pthreadDebugSetFregRtn_t) set_fpreg_clbk,
|
||||
(pthreadDebugGetRegRtn_t) get_reg_clbk,
|
||||
(pthreadDebugSetRegRtn_t) set_reg_clbk,
|
||||
(pthreadDebugOutputRtn_t) output_clbk,
|
||||
(pthreadDebugOutputRtn_t) error_clbk,
|
||||
malloc_clbk,
|
||||
free_clbk,
|
||||
speckthd_clbk
|
||||
};
|
||||
|
||||
/* Activate thread support if appropriate. Do nothing if thread
|
||||
support is already active. */
|
||||
|
||||
static void
|
||||
enable_dec_thread (void)
|
||||
{
|
||||
struct minimal_symbol *msym;
|
||||
void* caller_context;
|
||||
int status;
|
||||
|
||||
/* If already active, nothing more to do. */
|
||||
if (dec_thread_active)
|
||||
return;
|
||||
|
||||
msym = lookup_minimal_symbol ("__pthread_dbg_symtable", NULL, NULL);
|
||||
if (msym == NULL)
|
||||
{
|
||||
debug ("enable_dec_thread: No __pthread_dbg_symtable");
|
||||
return;
|
||||
}
|
||||
|
||||
status = pthreadDebugContextInit (&caller_context, &debug_callbacks,
|
||||
(void *) SYMBOL_VALUE_ADDRESS (msym),
|
||||
&debug_context);
|
||||
if (status != ESUCCESS)
|
||||
{
|
||||
debug ("enable_dec_thread: pthreadDebugContextInit -> %d",
|
||||
status);
|
||||
return;
|
||||
}
|
||||
|
||||
base_target = current_target;
|
||||
push_target (&dec_thread_ops);
|
||||
dec_thread_active = 1;
|
||||
|
||||
debug ("enable_dec_thread: Thread support enabled.");
|
||||
}
|
||||
|
||||
/* Deactivate thread support. Do nothing is thread support is
|
||||
already inactive. */
|
||||
|
||||
static void
|
||||
disable_dec_thread (void)
|
||||
{
|
||||
if (!dec_thread_active)
|
||||
return;
|
||||
|
||||
pthreadDebugContextDestroy (debug_context);
|
||||
unpush_target (&dec_thread_ops);
|
||||
dec_thread_active = 0;
|
||||
}
|
||||
|
||||
/* A structure that contains a thread ID and is associated
|
||||
pthreadDebugThreadInfo_t data. */
|
||||
|
||||
struct dec_thread_info
|
||||
{
|
||||
pthreadDebugId_t thread;
|
||||
pthreadDebugThreadInfo_t info;
|
||||
};
|
||||
typedef struct dec_thread_info dec_thread_info_s;
|
||||
|
||||
/* The list of user threads. */
|
||||
|
||||
DEF_VEC_O (dec_thread_info_s);
|
||||
VEC(dec_thread_info_s) *dec_thread_list;
|
||||
|
||||
/* Release the memory used by the given VECP thread list pointer.
|
||||
Then set *VECP to NULL. */
|
||||
|
||||
static void
|
||||
free_dec_thread_info_vec (VEC(dec_thread_info_s) **vecp)
|
||||
{
|
||||
int i;
|
||||
struct dec_thread_info *item;
|
||||
VEC(dec_thread_info_s) *vec = *vecp;
|
||||
|
||||
for (i = 0; VEC_iterate (dec_thread_info_s, vec, i, item); i++)
|
||||
xfree (item);
|
||||
VEC_free (dec_thread_info_s, vec);
|
||||
*vecp = NULL;
|
||||
}
|
||||
|
||||
/* Return a thread's ptid given its associated INFO. */
|
||||
|
||||
static ptid_t
|
||||
ptid_build_from_info (struct dec_thread_info info)
|
||||
{
|
||||
int pid = ptid_get_pid (inferior_ptid);
|
||||
|
||||
return ptid_build (pid, 0, (long) info.thread);
|
||||
}
|
||||
|
||||
/* Recompute the list of user threads and store the result in
|
||||
DEC_THREAD_LIST. */
|
||||
|
||||
static void
|
||||
update_dec_thread_list (void)
|
||||
{
|
||||
pthreadDebugId_t thread;
|
||||
pthreadDebugThreadInfo_t info;
|
||||
int res;
|
||||
|
||||
free_dec_thread_info_vec (&dec_thread_list);
|
||||
res = pthreadDebugThdSeqInit (debug_context, &thread);
|
||||
while (res == ESUCCESS)
|
||||
{
|
||||
|
||||
res = pthreadDebugThdGetInfo (debug_context, thread, &info);
|
||||
if (res != ESUCCESS)
|
||||
warning (_("unable to get thread info, ignoring thread %ld"),
|
||||
thread);
|
||||
else if (info.kind == PTHREAD_DEBUG_THD_KIND_INITIAL
|
||||
|| info.kind == PTHREAD_DEBUG_THD_KIND_NORMAL)
|
||||
{
|
||||
struct dec_thread_info *item =
|
||||
xmalloc (sizeof (struct dec_thread_info));
|
||||
|
||||
item->thread = thread;
|
||||
item->info = info;
|
||||
VEC_safe_push (dec_thread_info_s, dec_thread_list, item);
|
||||
}
|
||||
res = pthreadDebugThdSeqNext (debug_context, &thread);
|
||||
}
|
||||
pthreadDebugThdSeqDestroy (debug_context);
|
||||
}
|
||||
|
||||
/* A callback to count the number of threads known to GDB. */
|
||||
|
||||
static int
|
||||
dec_thread_count_gdb_threads (struct thread_info *ignored, void *context)
|
||||
{
|
||||
int *count = (int *) context;
|
||||
|
||||
*count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A callback that saves the given thread INFO at the end of an
|
||||
array. The end of the array is given in the CONTEXT and is
|
||||
incremented once the info has been added. */
|
||||
|
||||
static int
|
||||
dec_thread_add_gdb_thread (struct thread_info *info, void *context)
|
||||
{
|
||||
struct thread_info ***listp = (struct thread_info ***) context;
|
||||
|
||||
**listp = info;
|
||||
*listp++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Resynchronize the list of threads known by GDB with the actual
|
||||
list of threads reported by libpthread_debug. */
|
||||
|
||||
static void
|
||||
resync_thread_list (void)
|
||||
{
|
||||
int i;
|
||||
struct dec_thread_info *info;
|
||||
int num_gdb_threads = 0;
|
||||
struct thread_info **gdb_thread_list;
|
||||
struct thread_info **next_thread_info;
|
||||
|
||||
update_dec_thread_list ();
|
||||
|
||||
/* Add new threads. */
|
||||
|
||||
for (i = 0; VEC_iterate (dec_thread_info_s, dec_thread_list, i, info);
|
||||
i++)
|
||||
{
|
||||
ptid_t ptid = ptid_build_from_info (*info);
|
||||
|
||||
if (!in_thread_list (ptid))
|
||||
add_thread (ptid);
|
||||
}
|
||||
|
||||
/* Remove threads that no longer exist. To help with the search,
|
||||
we build an array of GDB threads, and then iterate over this
|
||||
array. */
|
||||
|
||||
iterate_over_threads (dec_thread_count_gdb_threads,
|
||||
(void *) &num_gdb_threads);
|
||||
gdb_thread_list = alloca (num_gdb_threads * sizeof (struct thread_info *));
|
||||
next_thread_info = gdb_thread_list;
|
||||
iterate_over_threads (dec_thread_add_gdb_thread, (void *) &next_thread_info);
|
||||
for (i = 0; i < num_gdb_threads; i++)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; VEC_iterate (dec_thread_info_s, dec_thread_list, j, info);
|
||||
j++)
|
||||
if (ptid_equal (gdb_thread_list[i]->ptid,
|
||||
ptid_build_from_info (*info)))
|
||||
break;
|
||||
delete_thread (gdb_thread_list[i]->ptid);
|
||||
}
|
||||
}
|
||||
|
||||
/* The "to_detach" method of the dec_thread_ops. */
|
||||
|
||||
static void
|
||||
dec_thread_detach (char *args, int from_tty)
|
||||
{
|
||||
debug ("dec_thread_detach");
|
||||
|
||||
disable_dec_thread ();
|
||||
base_target.to_detach (args, from_tty);
|
||||
}
|
||||
|
||||
/* Return the ptid of the thread that is currently active. */
|
||||
|
||||
static ptid_t
|
||||
get_active_ptid (void)
|
||||
{
|
||||
int i;
|
||||
struct dec_thread_info *info;
|
||||
|
||||
for (i = 0; VEC_iterate (dec_thread_info_s, dec_thread_list, i, info);
|
||||
i++)
|
||||
if (info->info.state == PTHREAD_DEBUG_STATE_RUNNING)
|
||||
return ptid_build_from_info (*info);
|
||||
|
||||
/* No active thread found. This can happen when the program
|
||||
has just exited. */
|
||||
return null_ptid;
|
||||
}
|
||||
|
||||
/* The "to_wait" method of the dec_thread_ops. */
|
||||
|
||||
static ptid_t
|
||||
dec_thread_wait (ptid_t ptid, struct target_waitstatus *status)
|
||||
{
|
||||
ptid_t active_ptid;
|
||||
|
||||
debug ("dec_thread_wait");
|
||||
|
||||
ptid = base_target.to_wait (ptid, status);
|
||||
|
||||
/* The ptid returned by the base_target is the ptid of the process.
|
||||
We need to find which thread is currently active and return its
|
||||
ptid. */
|
||||
resync_thread_list ();
|
||||
active_ptid = get_active_ptid ();
|
||||
if (ptid_equal (active_ptid, null_ptid))
|
||||
return ptid;
|
||||
return active_ptid;
|
||||
}
|
||||
|
||||
/* Fetch the general purpose and floating point registers for the given
|
||||
thread TID, and store the result in GREGSET and FPREGSET. Return
|
||||
zero if successful. */
|
||||
|
||||
static int
|
||||
dec_thread_get_regsets (pthreadDebugId_t tid, gdb_gregset_t *gregset,
|
||||
gdb_fpregset_t *fpregset)
|
||||
{
|
||||
int res;
|
||||
pthreadDebugRegs_t regs;
|
||||
pthreadDebugFregs_t fregs;
|
||||
|
||||
res = pthreadDebugThdGetReg (debug_context, tid, ®s);
|
||||
if (res != ESUCCESS)
|
||||
{
|
||||
debug ("dec_thread_fetch_registers: pthreadDebugThdGetReg -> %d", res);
|
||||
return -1;
|
||||
}
|
||||
memcpy (gregset->regs, ®s, sizeof (regs));
|
||||
|
||||
res = pthreadDebugThdGetFreg (debug_context, tid, &fregs);
|
||||
if (res != ESUCCESS)
|
||||
{
|
||||
debug ("dec_thread_fetch_registers: pthreadDebugThdGetFreg -> %d", res);
|
||||
return -1;
|
||||
}
|
||||
memcpy (fpregset->regs, &fregs, sizeof (fregs));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The "to_fetch_registers" method of the dec_thread_ops.
|
||||
|
||||
Because the dec-thread debug API doesn't allow us to fetch
|
||||
only one register, we simply ignore regno and fetch+supply all
|
||||
registers. */
|
||||
|
||||
static void
|
||||
dec_thread_fetch_registers (struct regcache *regcache, int regno)
|
||||
{
|
||||
pthreadDebugId_t tid = ptid_get_tid (inferior_ptid);
|
||||
gregset_t gregset;
|
||||
fpregset_t fpregset;
|
||||
int res;
|
||||
|
||||
debug ("dec_thread_fetch_registers (tid=%ld, regno=%d)", tid, regno);
|
||||
|
||||
|
||||
if (tid == 0 || ptid_equal (inferior_ptid, get_active_ptid ()))
|
||||
{
|
||||
base_target.to_fetch_registers (regcache, regno);
|
||||
return;
|
||||
}
|
||||
|
||||
res = dec_thread_get_regsets (tid, &gregset, &fpregset);
|
||||
if (res != 0)
|
||||
return;
|
||||
|
||||
supply_gregset (regcache, &gregset);
|
||||
supply_fpregset (regcache, &fpregset);
|
||||
}
|
||||
|
||||
/* Store the registers given in GREGSET and FPREGSET into the associated
|
||||
general purpose and floating point registers of thread TID. Return
|
||||
zero if successful. */
|
||||
|
||||
static int
|
||||
dec_thread_set_regsets (pthreadDebugId_t tid, gdb_gregset_t gregset,
|
||||
gdb_fpregset_t fpregset)
|
||||
{
|
||||
int res;
|
||||
pthreadDebugRegs_t regs;
|
||||
pthreadDebugFregs_t fregs;
|
||||
|
||||
memcpy (®s, gregset.regs, sizeof (regs));
|
||||
res = pthreadDebugThdSetReg (debug_context, tid, ®s);
|
||||
if (res != ESUCCESS)
|
||||
{
|
||||
debug ("dec_thread_fetch_registers: pthreadDebugThdSetReg -> %d", res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy (&fregs, fpregset.regs, sizeof (fregs));
|
||||
res = pthreadDebugThdSetFreg (debug_context, tid, &fregs);
|
||||
if (res != ESUCCESS)
|
||||
{
|
||||
debug ("dec_thread_fetch_registers: pthreadDebugThdSetFreg -> %d", res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The "to_store_registers" method of the dec_thread_ops.
|
||||
|
||||
Because the dec-thread debug API doesn't allow us to store
|
||||
just one register, we store all the registers. */
|
||||
|
||||
static void
|
||||
dec_thread_store_registers (struct regcache *regcache, int regno)
|
||||
{
|
||||
pthreadDebugId_t tid = ptid_get_tid (inferior_ptid);
|
||||
gregset_t gregset;
|
||||
fpregset_t fpregset;
|
||||
int res;
|
||||
|
||||
debug ("dec_thread_store_registers (tid=%ld, regno=%d)", tid, regno);
|
||||
|
||||
if (tid == 0 || ptid_equal (inferior_ptid, get_active_ptid ()))
|
||||
{
|
||||
base_target.to_store_registers (regcache, regno);
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME: brobecker/2008-05-28: I wonder if we could simply check
|
||||
in which register set the register is and then only store the
|
||||
registers for that register set, instead of storing both register
|
||||
sets. */
|
||||
fill_gregset (regcache, &gregset, -1);
|
||||
fill_fpregset (regcache, &fpregset, -1);
|
||||
|
||||
res = dec_thread_set_regsets (tid, gregset, fpregset);
|
||||
if (res != 0)
|
||||
warning (_("failed to store registers."));
|
||||
}
|
||||
|
||||
/* The "to_mourn_inferior" method of the dec_thread_ops. */
|
||||
|
||||
static void
|
||||
dec_thread_mourn_inferior (void)
|
||||
{
|
||||
debug ("dec_thread_mourn_inferior");
|
||||
|
||||
disable_dec_thread ();
|
||||
base_target.to_mourn_inferior ();
|
||||
}
|
||||
|
||||
/* The "to_thread_alive" method of the dec_thread_ops. */
|
||||
static int
|
||||
dec_thread_thread_alive (ptid_t ptid)
|
||||
{
|
||||
debug ("dec_thread_thread_alive (tid=%ld)", ptid_get_tid (ptid));
|
||||
|
||||
/* The thread list maintained by GDB is up to date, since we update
|
||||
it everytime we stop. So check this list. */
|
||||
return in_thread_list (ptid);
|
||||
}
|
||||
|
||||
/* The "to_pid_to_str" method of the dec_thread_ops. */
|
||||
|
||||
static char *
|
||||
dec_thread_pid_to_str (ptid_t ptid)
|
||||
{
|
||||
static char *ret = NULL;
|
||||
|
||||
if (ptid_get_tid (ptid) == 0)
|
||||
return base_target.to_pid_to_str (ptid);
|
||||
|
||||
/* Free previous return value; a new one will be allocated by
|
||||
xstrprintf(). */
|
||||
xfree (ret);
|
||||
|
||||
ret = xstrprintf (_("Thread %ld"), ptid_get_tid (ptid));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* A "new-objfile" observer. Used to activate/deactivate dec-thread
|
||||
support. */
|
||||
|
||||
static void
|
||||
dec_thread_new_objfile_observer (struct objfile *objfile)
|
||||
{
|
||||
if (objfile != NULL)
|
||||
enable_dec_thread ();
|
||||
else
|
||||
disable_dec_thread ();
|
||||
}
|
||||
|
||||
static void
|
||||
init_dec_thread_ops (void)
|
||||
{
|
||||
dec_thread_ops.to_shortname = "dec-threads";
|
||||
dec_thread_ops.to_longname = _("DEC threads support");
|
||||
dec_thread_ops.to_doc = _("DEC threads support");
|
||||
dec_thread_ops.to_detach = dec_thread_detach;
|
||||
dec_thread_ops.to_wait = dec_thread_wait;
|
||||
dec_thread_ops.to_fetch_registers = dec_thread_fetch_registers;
|
||||
dec_thread_ops.to_store_registers = dec_thread_store_registers;
|
||||
dec_thread_ops.to_mourn_inferior = dec_thread_mourn_inferior;
|
||||
dec_thread_ops.to_thread_alive = dec_thread_thread_alive;
|
||||
dec_thread_ops.to_pid_to_str = dec_thread_pid_to_str;
|
||||
dec_thread_ops.to_stratum = thread_stratum;
|
||||
dec_thread_ops.to_magic = OPS_MAGIC;
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_dec_thread (void)
|
||||
{
|
||||
init_dec_thread_ops ();
|
||||
add_target (&dec_thread_ops);
|
||||
|
||||
observer_attach_new_objfile (dec_thread_new_objfile_observer);
|
||||
|
||||
add_setshow_boolean_cmd ("dec-thread", class_maintenance, &debug_dec_thread,
|
||||
_("Set debugging of DEC threads module."),
|
||||
_("Show debugging of DEC threads module."),
|
||||
_("Enables debugging output (used to debug GDB)."),
|
||||
NULL, NULL,
|
||||
&setdebuglist, &showdebuglist);
|
||||
}
|
Loading…
Reference in New Issue
Block a user