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