| 1 | /* thread_db.h -- interface to libthread_db.so library for debugging -lpthread |
| 2 | Copyright (C) 1999-2026 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 */ |