| 1 | #ifdef HAVE_THREAD_DB_H |
| 2 | #include <thread_db.h> |
| 3 | #else |
| 4 | |
| 5 | #ifdef HAVE_STDINT_H |
| 6 | #include <stdint.h> |
| 7 | typedef uint32_t gdb_uint32_t; |
| 8 | #define GDB_UINT32_C(c) UINT32_C(c) |
| 9 | #else |
| 10 | typedef unsigned int gdb_uint32_t; |
| 11 | #define GDB_UINT32_C(c) c ## U |
| 12 | #endif |
| 13 | |
| 14 | /* Copyright (C) 1999, 2000, 2007 Free Software Foundation, Inc. |
| 15 | This file is part of the GNU C Library. |
| 16 | |
| 17 | The GNU C Library is free software; you can redistribute it and/or |
| 18 | modify it under the terms of the GNU Library General Public License as |
| 19 | published by the Free Software Foundation; either version 2 of the |
| 20 | License, or (at your option) any later version. |
| 21 | |
| 22 | The GNU C Library is distributed in the hope that it will be useful, |
| 23 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 25 | Library General Public License for more details. |
| 26 | |
| 27 | You should have received a copy of the GNU Library General Public |
| 28 | License along with the GNU C Library; see the file COPYING.LIB. If not, |
| 29 | write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 30 | Boston, MA 02110-1301, USA. */ |
| 31 | |
| 32 | #ifndef _THREAD_DB_H |
| 33 | #define _THREAD_DB_H 1 |
| 34 | |
| 35 | /* This is the debugger interface for the LinuxThreads library. It is |
| 36 | modelled closely after the interface with same names in Solaris with |
| 37 | the goal to share the same code in the debugger. */ |
| 38 | #include <pthread.h> |
| 39 | #include <sys/types.h> |
| 40 | #include <sys/procfs.h> |
| 41 | |
| 42 | |
| 43 | /* Error codes of the library. */ |
| 44 | typedef enum |
| 45 | { |
| 46 | TD_OK, /* No error. */ |
| 47 | TD_ERR, /* No further specified error. */ |
| 48 | TD_NOTHR, /* No matching thread found. */ |
| 49 | TD_NOSV, /* No matching synchronization handle found. */ |
| 50 | TD_NOLWP, /* No matching light-weighted process found. */ |
| 51 | TD_BADPH, /* Invalid process handle. */ |
| 52 | TD_BADTH, /* Invalid thread handle. */ |
| 53 | TD_BADSH, /* Invalid synchronization handle. */ |
| 54 | TD_BADTA, /* Invalid thread agent. */ |
| 55 | TD_BADKEY, /* Invalid key. */ |
| 56 | TD_NOMSG, /* No event available. */ |
| 57 | TD_NOFPREGS, /* No floating-point register content available. */ |
| 58 | TD_NOLIBTHREAD, /* Application not linked with thread library. */ |
| 59 | TD_NOEVENT, /* Requested event is not supported. */ |
| 60 | TD_NOCAPAB, /* Capability not available. */ |
| 61 | TD_DBERR, /* Internal debug library error. */ |
| 62 | TD_NOAPLIC, /* Operation is not applicable. */ |
| 63 | TD_NOTSD, /* No thread-specific data available. */ |
| 64 | TD_MALLOC, /* Out of memory. */ |
| 65 | TD_PARTIALREG, /* Not entire register set was read or written. */ |
| 66 | TD_NOXREGS, /* X register set not available for given thread. */ |
| 67 | TD_NOTALLOC /* TLS memory not yet allocated. */ |
| 68 | } td_err_e; |
| 69 | |
| 70 | |
| 71 | /* Possible thread states. TD_THR_ANY_STATE is a pseudo-state used to |
| 72 | select threads regardless of state in td_ta_thr_iter(). */ |
| 73 | typedef enum |
| 74 | { |
| 75 | TD_THR_ANY_STATE, |
| 76 | TD_THR_UNKNOWN, |
| 77 | TD_THR_STOPPED, |
| 78 | TD_THR_RUN, |
| 79 | TD_THR_ACTIVE, |
| 80 | TD_THR_ZOMBIE, |
| 81 | TD_THR_SLEEP, |
| 82 | TD_THR_STOPPED_ASLEEP |
| 83 | } td_thr_state_e; |
| 84 | |
| 85 | /* Thread type: user or system. TD_THR_ANY_TYPE is a pseudo-type used |
| 86 | to select threads regardless of type in td_ta_thr_iter(). */ |
| 87 | typedef enum |
| 88 | { |
| 89 | TD_THR_ANY_TYPE, |
| 90 | TD_THR_USER, |
| 91 | TD_THR_SYSTEM |
| 92 | } td_thr_type_e; |
| 93 | |
| 94 | |
| 95 | /* Types of the debugging library. */ |
| 96 | |
| 97 | /* Handle for a process. This type is opaque. */ |
| 98 | typedef struct td_thragent td_thragent_t; |
| 99 | |
| 100 | /* The actual thread handle type. This is also opaque. */ |
| 101 | typedef struct td_thrhandle |
| 102 | { |
| 103 | td_thragent_t *th_ta_p; |
| 104 | psaddr_t th_unique; |
| 105 | } td_thrhandle_t; |
| 106 | |
| 107 | |
| 108 | /* Flags for `td_ta_thr_iter'. */ |
| 109 | #define TD_THR_ANY_USER_FLAGS 0xffffffff |
| 110 | #define TD_THR_LOWEST_PRIORITY -20 |
| 111 | #define TD_SIGNO_MASK NULL |
| 112 | |
| 113 | |
| 114 | #define TD_EVENTSIZE 2 |
| 115 | #define BT_UISHIFT 5 /* log base 2 of BT_NBIPUI, to extract word index */ |
| 116 | #define BT_NBIPUI (1 << BT_UISHIFT) /* n bits per uint */ |
| 117 | #define BT_UIMASK (BT_NBIPUI - 1) /* to extract bit index */ |
| 118 | |
| 119 | /* Bitmask of enabled events. */ |
| 120 | typedef struct td_thr_events |
| 121 | { |
| 122 | gdb_uint32_t event_bits[TD_EVENTSIZE]; |
| 123 | } td_thr_events_t; |
| 124 | |
| 125 | /* Event set manipulation macros. */ |
| 126 | #define __td_eventmask(n) \ |
| 127 | (GDB_UINT32_C (1) << (((n) - 1) & BT_UIMASK)) |
| 128 | #define __td_eventword(n) \ |
| 129 | ((GDB_UINT32_C ((n) - 1)) >> BT_UISHIFT) |
| 130 | |
| 131 | #define td_event_emptyset(setp) \ |
| 132 | do { \ |
| 133 | int __i; \ |
| 134 | for (__i = TD_EVENTSIZE; __i > 0; --__i) \ |
| 135 | (setp)->event_bits[__i - 1] = 0; \ |
| 136 | } while (0) |
| 137 | |
| 138 | #define td_event_fillset(setp) \ |
| 139 | do { \ |
| 140 | int __i; \ |
| 141 | for (__i = TD_EVENTSIZE; __i > 0; --__i) \ |
| 142 | (setp)->event_bits[__i - 1] = GDB_UINT32_C (0xffffffff); \ |
| 143 | } while (0) |
| 144 | |
| 145 | #define td_event_addset(setp, n) \ |
| 146 | (((setp)->event_bits[__td_eventword (n)]) |= __td_eventmask (n)) |
| 147 | #define td_event_delset(setp, n) \ |
| 148 | (((setp)->event_bits[__td_eventword (n)]) &= ~__td_eventmask (n)) |
| 149 | #define td_eventismember(setp, n) \ |
| 150 | (__td_eventmask (n) & ((setp)->event_bits[__td_eventword (n)])) |
| 151 | #if TD_EVENTSIZE == 2 |
| 152 | # define td_eventisempty(setp) \ |
| 153 | (!((setp)->event_bits[0]) && !((setp)->event_bits[1])) |
| 154 | #else |
| 155 | # error "td_eventisempty must be changed to match TD_EVENTSIZE" |
| 156 | #endif |
| 157 | |
| 158 | /* Events reportable by the thread implementation. */ |
| 159 | typedef enum |
| 160 | { |
| 161 | TD_ALL_EVENTS, /* Pseudo-event number. */ |
| 162 | TD_EVENT_NONE = TD_ALL_EVENTS, /* Depends on context. */ |
| 163 | TD_READY, /* Is executable now. */ |
| 164 | TD_SLEEP, /* Blocked in a synchronization obj. */ |
| 165 | TD_SWITCHTO, /* Now assigned to a process. */ |
| 166 | TD_SWITCHFROM, /* Not anymore assigned to a process. */ |
| 167 | TD_LOCK_TRY, /* Trying to get an unavailable lock. */ |
| 168 | TD_CATCHSIG, /* Signal posted to the thread. */ |
| 169 | TD_IDLE, /* Process getting idle. */ |
| 170 | TD_CREATE, /* New thread created. */ |
| 171 | TD_DEATH, /* Thread terminated. */ |
| 172 | TD_PREEMPT, /* Preempted. */ |
| 173 | TD_PRI_INHERIT, /* Inherited elevated priority. */ |
| 174 | TD_REAP, /* Reaped. */ |
| 175 | TD_CONCURRENCY, /* Number of processes changing. */ |
| 176 | TD_TIMEOUT, /* Conditional variable wait timed out. */ |
| 177 | TD_MIN_EVENT_NUM = TD_READY, |
| 178 | TD_MAX_EVENT_NUM = TD_TIMEOUT, |
| 179 | TD_EVENTS_ENABLE = 31 /* Event reporting enabled. */ |
| 180 | } td_event_e; |
| 181 | |
| 182 | /* Values representing the different ways events are reported. */ |
| 183 | typedef enum |
| 184 | { |
| 185 | NOTIFY_BPT, /* User must insert breakpoint at u.bptaddr. */ |
| 186 | NOTIFY_AUTOBPT, /* Breakpoint at u.bptaddr is automatically |
| 187 | inserted. */ |
| 188 | NOTIFY_SYSCALL /* System call u.syscallno will be invoked. */ |
| 189 | } td_notify_e; |
| 190 | |
| 191 | /* Description how event type is reported. */ |
| 192 | typedef struct td_notify |
| 193 | { |
| 194 | td_notify_e type; /* Way the event is reported. */ |
| 195 | union |
| 196 | { |
| 197 | psaddr_t bptaddr; /* Address of breakpoint. */ |
| 198 | int syscallno; /* Number of system call used. */ |
| 199 | } u; |
| 200 | } td_notify_t; |
| 201 | |
| 202 | /* Some people still have libc5 or old glibc with no uintptr_t. |
| 203 | They lose. glibc 2.1.3 was released on 2000-02-25, and it has |
| 204 | uintptr_t, so it's reasonable to force these people to upgrade. */ |
| 205 | |
| 206 | #ifndef HAVE_UINTPTR_T |
| 207 | #error No uintptr_t available; your C library is too old. |
| 208 | /* Inhibit further compilation errors after this error. */ |
| 209 | #define uintptr_t void * |
| 210 | #endif |
| 211 | |
| 212 | /* Structure used to report event. */ |
| 213 | typedef struct td_event_msg |
| 214 | { |
| 215 | td_event_e event; /* Event type being reported. */ |
| 216 | const td_thrhandle_t *th_p; /* Thread reporting the event. */ |
| 217 | union |
| 218 | { |
| 219 | #if 0 |
| 220 | td_synchandle_t *sh; /* Handle of synchronization object. */ |
| 221 | #endif |
| 222 | uintptr_t data; /* Event specific data. */ |
| 223 | } msg; |
| 224 | } td_event_msg_t; |
| 225 | |
| 226 | /* Structure containing event data available in each thread structure. */ |
| 227 | typedef struct |
| 228 | { |
| 229 | td_thr_events_t eventmask; /* Mask of enabled events. */ |
| 230 | td_event_e eventnum; /* Number of last event. */ |
| 231 | void *eventdata; /* Data associated with event. */ |
| 232 | } td_eventbuf_t; |
| 233 | |
| 234 | |
| 235 | /* Gathered statistics about the process. */ |
| 236 | typedef struct td_ta_stats |
| 237 | { |
| 238 | int nthreads; /* Total number of threads in use. */ |
| 239 | int r_concurrency; /* Concurrency level requested by user. */ |
| 240 | int nrunnable_num; /* Average runnable threads, numerator. */ |
| 241 | int nrunnable_den; /* Average runnable threads, denominator. */ |
| 242 | int a_concurrency_num; /* Achieved concurrency level, numerator. */ |
| 243 | int a_concurrency_den; /* Achieved concurrency level, denominator. */ |
| 244 | int nlwps_num; /* Average number of processes in use, |
| 245 | numerator. */ |
| 246 | int nlwps_den; /* Average number of processes in use, |
| 247 | denominator. */ |
| 248 | int nidle_num; /* Average number of idling processes, |
| 249 | numerator. */ |
| 250 | int nidle_den; /* Average number of idling processes, |
| 251 | denominator. */ |
| 252 | } td_ta_stats_t; |
| 253 | |
| 254 | |
| 255 | /* Since Sun's library is based on Solaris threads we have to define a few |
| 256 | types to map them to POSIX threads. */ |
| 257 | typedef pthread_t thread_t; |
| 258 | typedef pthread_key_t thread_key_t; |
| 259 | |
| 260 | |
| 261 | /* Callback for iteration over threads. */ |
| 262 | typedef int td_thr_iter_f (const td_thrhandle_t *, void *); |
| 263 | |
| 264 | /* Callback for iteration over thread local data. */ |
| 265 | typedef int td_key_iter_f (thread_key_t, void (*) (void *), void *); |
| 266 | |
| 267 | |
| 268 | |
| 269 | /* Forward declaration. This has to be defined by the user. */ |
| 270 | struct ps_prochandle; |
| 271 | |
| 272 | |
| 273 | /* Information about the thread. */ |
| 274 | typedef struct td_thrinfo |
| 275 | { |
| 276 | td_thragent_t *ti_ta_p; /* Process handle. */ |
| 277 | unsigned int ti_user_flags; /* Unused. */ |
| 278 | thread_t ti_tid; /* Thread ID returned by |
| 279 | pthread_create(). */ |
| 280 | char *ti_tls; /* Pointer to thread-local data. */ |
| 281 | psaddr_t ti_startfunc; /* Start function passed to |
| 282 | pthread_create(). */ |
| 283 | psaddr_t ti_stkbase; /* Base of thread's stack. */ |
| 284 | long int ti_stksize; /* Size of thread's stack. */ |
| 285 | psaddr_t ti_ro_area; /* Unused. */ |
| 286 | int ti_ro_size; /* Unused. */ |
| 287 | td_thr_state_e ti_state; /* Thread state. */ |
| 288 | unsigned char ti_db_suspended; /* Nonzero if suspended by debugger. */ |
| 289 | td_thr_type_e ti_type; /* Type of the thread (system vs |
| 290 | user thread). */ |
| 291 | intptr_t ti_pc; /* Unused. */ |
| 292 | intptr_t ti_sp; /* Unused. */ |
| 293 | short int ti_flags; /* Unused. */ |
| 294 | int ti_pri; /* Thread priority. */ |
| 295 | lwpid_t ti_lid; /* Kernel pid for this thread. */ |
| 296 | sigset_t ti_sigmask; /* Signal mask. */ |
| 297 | unsigned char ti_traceme; /* Nonzero if event reporting |
| 298 | enabled. */ |
| 299 | unsigned char ti_preemptflag; /* Unused. */ |
| 300 | unsigned char ti_pirecflag; /* Unused. */ |
| 301 | sigset_t ti_pending; /* Set of pending signals. */ |
| 302 | td_thr_events_t ti_events; /* Set of enabled events. */ |
| 303 | } td_thrinfo_t; |
| 304 | |
| 305 | |
| 306 | |
| 307 | /* Prototypes for exported library functions. */ |
| 308 | |
| 309 | /* Initialize the thread debug support library. */ |
| 310 | extern td_err_e td_init (void); |
| 311 | |
| 312 | /* Historical relict. Should not be used anymore. */ |
| 313 | extern td_err_e td_log (void); |
| 314 | |
| 315 | /* Generate new thread debug library handle for process PS. */ |
| 316 | extern td_err_e td_ta_new (struct ps_prochandle *__ps, td_thragent_t **__ta); |
| 317 | |
| 318 | /* Free resources allocated for TA. */ |
| 319 | extern td_err_e td_ta_delete (td_thragent_t *__ta); |
| 320 | |
| 321 | /* Get number of currently running threads in process associated with TA. */ |
| 322 | extern td_err_e td_ta_get_nthreads (const td_thragent_t *__ta, int *__np); |
| 323 | |
| 324 | /* Return process handle passed in `td_ta_new' for process associated with |
| 325 | TA. */ |
| 326 | extern td_err_e td_ta_get_ph (const td_thragent_t *__ta, |
| 327 | struct ps_prochandle **__ph); |
| 328 | |
| 329 | /* Map thread library handle PT to thread debug library handle for process |
| 330 | associated with TA and store result in *TH. */ |
| 331 | extern td_err_e td_ta_map_id2thr (const td_thragent_t *__ta, pthread_t __pt, |
| 332 | td_thrhandle_t *__th); |
| 333 | |
| 334 | /* Map process ID LWPID to thread debug library handle for process |
| 335 | associated with TA and store result in *TH. */ |
| 336 | extern td_err_e td_ta_map_lwp2thr (const td_thragent_t *__ta, lwpid_t __lwpid, |
| 337 | td_thrhandle_t *__th); |
| 338 | |
| 339 | |
| 340 | /* Call for each thread in a process associated with TA the callback function |
| 341 | CALLBACK. */ |
| 342 | extern td_err_e td_ta_thr_iter (const td_thragent_t *__ta, |
| 343 | td_thr_iter_f *__callback, void *__cbdata_p, |
| 344 | td_thr_state_e __state, int __ti_pri, |
| 345 | sigset_t *__ti_sigmask_p, |
| 346 | unsigned int __ti_user_flags); |
| 347 | |
| 348 | /* Call for each defined thread local data entry the callback function KI. */ |
| 349 | extern td_err_e td_ta_tsd_iter (const td_thragent_t *__ta, td_key_iter_f *__ki, |
| 350 | void *__p); |
| 351 | |
| 352 | |
| 353 | /* Get event address for EVENT. */ |
| 354 | extern td_err_e td_ta_event_addr (const td_thragent_t *__ta, |
| 355 | td_event_e __event, td_notify_t *__ptr); |
| 356 | |
| 357 | /* Enable EVENT in global mask. */ |
| 358 | extern td_err_e td_ta_set_event (const td_thragent_t *__ta, |
| 359 | td_thr_events_t *__event); |
| 360 | |
| 361 | /* Disable EVENT in global mask. */ |
| 362 | extern td_err_e td_ta_clear_event (const td_thragent_t *__ta, |
| 363 | td_thr_events_t *__event); |
| 364 | |
| 365 | /* Return information about last event. */ |
| 366 | extern td_err_e td_ta_event_getmsg (const td_thragent_t *__ta, |
| 367 | td_event_msg_t *msg); |
| 368 | |
| 369 | |
| 370 | /* Set suggested concurrency level for process associated with TA. */ |
| 371 | extern td_err_e td_ta_setconcurrency (const td_thragent_t *__ta, int __level); |
| 372 | |
| 373 | |
| 374 | /* Enable collecting statistics for process associated with TA. */ |
| 375 | extern td_err_e td_ta_enable_stats (const td_thragent_t *__ta, int __enable); |
| 376 | |
| 377 | /* Reset statistics. */ |
| 378 | extern td_err_e td_ta_reset_stats (const td_thragent_t *__ta); |
| 379 | |
| 380 | /* Retrieve statistics from process associated with TA. */ |
| 381 | extern td_err_e td_ta_get_stats (const td_thragent_t *__ta, |
| 382 | td_ta_stats_t *__statsp); |
| 383 | |
| 384 | |
| 385 | /* Validate that TH is a thread handle. */ |
| 386 | extern td_err_e td_thr_validate (const td_thrhandle_t *__th); |
| 387 | |
| 388 | /* Return information about thread TH. */ |
| 389 | extern td_err_e td_thr_get_info (const td_thrhandle_t *__th, |
| 390 | td_thrinfo_t *__infop); |
| 391 | |
| 392 | /* Retrieve floating-point register contents of process running thread TH. */ |
| 393 | extern td_err_e td_thr_getfpregs (const td_thrhandle_t *__th, |
| 394 | prfpregset_t *__regset); |
| 395 | |
| 396 | /* Retrieve general register contents of process running thread TH. */ |
| 397 | extern td_err_e td_thr_getgregs (const td_thrhandle_t *__th, |
| 398 | prgregset_t __gregs); |
| 399 | |
| 400 | /* Retrieve extended register contents of process running thread TH. */ |
| 401 | extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th, void *__xregs); |
| 402 | |
| 403 | /* Get size of extended register set of process running thread TH. */ |
| 404 | extern td_err_e td_thr_getxregsize (const td_thrhandle_t *__th, int *__sizep); |
| 405 | |
| 406 | /* Set floating-point register contents of process running thread TH. */ |
| 407 | extern td_err_e td_thr_setfpregs (const td_thrhandle_t *__th, |
| 408 | const prfpregset_t *__fpregs); |
| 409 | |
| 410 | /* Set general register contents of process running thread TH. */ |
| 411 | extern td_err_e td_thr_setgregs (const td_thrhandle_t *__th, |
| 412 | prgregset_t __gregs); |
| 413 | |
| 414 | /* Set extended register contents of process running thread TH. */ |
| 415 | extern td_err_e td_thr_setxregs (const td_thrhandle_t *__th, |
| 416 | const void *__addr); |
| 417 | |
| 418 | |
| 419 | /* Enable reporting for EVENT for thread TH. */ |
| 420 | extern td_err_e td_thr_event_enable (const td_thrhandle_t *__th, int __event); |
| 421 | |
| 422 | /* Enable EVENT for thread TH. */ |
| 423 | extern td_err_e td_thr_set_event (const td_thrhandle_t *__th, |
| 424 | td_thr_events_t *__event); |
| 425 | |
| 426 | /* Disable EVENT for thread TH. */ |
| 427 | extern td_err_e td_thr_clear_event (const td_thrhandle_t *__th, |
| 428 | td_thr_events_t *__event); |
| 429 | |
| 430 | /* Get event message for thread TH. */ |
| 431 | extern td_err_e td_thr_event_getmsg (const td_thrhandle_t *__th, |
| 432 | td_event_msg_t *__msg); |
| 433 | |
| 434 | |
| 435 | /* Set priority of thread TH. */ |
| 436 | extern td_err_e td_thr_setprio (const td_thrhandle_t *__th, int __prio); |
| 437 | |
| 438 | |
| 439 | /* Set pending signals for thread TH. */ |
| 440 | extern td_err_e td_thr_setsigpending (const td_thrhandle_t *__th, |
| 441 | unsigned char __n, const sigset_t *__ss); |
| 442 | |
| 443 | /* Set signal mask for thread TH. */ |
| 444 | extern td_err_e td_thr_sigsetmask (const td_thrhandle_t *__th, |
| 445 | const sigset_t *__ss); |
| 446 | |
| 447 | |
| 448 | /* Return thread local data associated with key TK in thread TH. */ |
| 449 | extern td_err_e td_thr_tsd (const td_thrhandle_t *__th, |
| 450 | const thread_key_t __tk, void **__data); |
| 451 | |
| 452 | |
| 453 | /* Suspend execution of thread TH. */ |
| 454 | extern td_err_e td_thr_dbsuspend (const td_thrhandle_t *__th); |
| 455 | |
| 456 | /* Resume execution of thread TH. */ |
| 457 | extern td_err_e td_thr_dbresume (const td_thrhandle_t *__th); |
| 458 | |
| 459 | #endif /* thread_db.h */ |
| 460 | |
| 461 | #endif /* HAVE_THREAD_DB_H */ |