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