GNU Binutils with patches for OS216
Revisión | f6327dcbf0bc91bb9d99e12232d2b1a2f959fce6 (tree) |
---|---|
Tiempo | 2017-09-22 03:49:47 |
Autor | Kevin Buettner <kevinb@redh...> |
Commiter | Kevin Buettner |
Add thread_handle_to_thread_info support for remote targets
This patch adds support to remote targets for converting a thread
handle to a thread_info struct pointer.
A thread handle is fetched via a "handle" attribute which has been
added to the qXfer:threads:read query packet. An implementation is
provided in gdbserver for targets using the Linux kernel.
gdb/gdbserver/ChangeLog:
* linux-low.h (struct lwp_info): Add new field, thread_handle.
(thread_db_thread_handle): Declare.
* linux-low.c (linux_target_ops): Initialize thread_handle.
* server.c (handle_qxfer_threads_worker): Add support for
"handle" attribute.
* target.h (struct target_ops): Add new function pointer,
thread_handle.
(target_thread_handle): Define.
* thread-db.c (find_one_thread, attach_thread): Set thread_handle
field in lwp.
(thread_db_thread_handle): New function.
gdb/ChangeLog:
* remote.c (vector): Include.
(struct private_thread_info): Add field, thread_handle.
(free_private_thread_info): Deallocate storage associated with
thread handle.
(get_private_info_thread): Initialize thread_handle' field.
(struct thread_item): Add field, thread_handle.
(clear_threads_listing_context): Deallocate storage associated
with thread handle.
(start_thread): Add support for "handle" attribute.
(thread_attributes): Add "handle".
(remote_get_threads_with_qthreadinfo): Initialize thread_handle
field.
(remote_update_thread_list): Update thread_handle.
(remote_thread_handle_to_thread_info): New function.
(init_remote_ops): Initialize to_thread_handle_to_thread_info.
@@ -1,5 +1,23 @@ | ||
1 | 1 | 2017-09-21 Kevin Buettner <kevinb@redhat.com> |
2 | 2 | |
3 | + * remote.c (vector): Include. | |
4 | + (struct private_thread_info): Add field, thread_handle. | |
5 | + (free_private_thread_info): Deallocate storage associated with | |
6 | + thread handle. | |
7 | + (get_private_info_thread): Initialize `thread_handle' field. | |
8 | + (struct thread_item): Add field, thread_handle. | |
9 | + (clear_threads_listing_context): Deallocate storage associated | |
10 | + with thread handle. | |
11 | + (start_thread): Add support for "handle" attribute. | |
12 | + (thread_attributes): Add "handle". | |
13 | + (remote_get_threads_with_qthreadinfo): Initialize thread_handle | |
14 | + field. | |
15 | + (remote_update_thread_list): Update thread_handle. | |
16 | + (remote_thread_handle_to_thread_info): New function. | |
17 | + (init_remote_ops): Initialize to_thread_handle_to_thread_info. | |
18 | + | |
19 | +2017-09-21 Kevin Buettner <kevinb@redhat.com> | |
20 | + | |
3 | 21 | * python/py-inferior.c (gdbpy_thread_from_thread_handle): New |
4 | 22 | function. |
5 | 23 | (inferior_object_methods): Add gdbpy_thread_from_thread_handle. |
@@ -1,5 +1,19 @@ | ||
1 | 1 | 2017-09-21 Kevin Buettner <kevinb@redhat.com> |
2 | 2 | |
3 | + * linux-low.h (struct lwp_info): Add new field, thread_handle. | |
4 | + (thread_db_thread_handle): Declare. | |
5 | + * linux-low.c (linux_target_ops): Initialize thread_handle. | |
6 | + * server.c (handle_qxfer_threads_worker): Add support for | |
7 | + "handle" attribute. | |
8 | + * target.h (struct target_ops): Add new function pointer, | |
9 | + thread_handle. | |
10 | + (target_thread_handle): Define. | |
11 | + * thread-db.c (find_one_thread, attach_thread): Set thread_handle | |
12 | + field in lwp. | |
13 | + (thread_db_thread_handle): New function. | |
14 | + | |
15 | +2017-09-21 Kevin Buettner <kevinb@redhat.com> | |
16 | + | |
3 | 17 | * linux-low.c (handle_extended_wait): Call thread_db_notice_clone(). |
4 | 18 | * linux-low.h (thread_db_notice_clone): Declare. |
5 | 19 | * thread-db.c (thread_db_notice_clone): New function. |
@@ -7705,6 +7705,11 @@ static struct target_ops linux_target_ops = { | ||
7705 | 7705 | linux_supports_software_single_step, |
7706 | 7706 | linux_supports_catch_syscall, |
7707 | 7707 | linux_get_ipa_tdesc_idx, |
7708 | +#if USE_THREAD_DB | |
7709 | + thread_db_thread_handle, | |
7710 | +#else | |
7711 | + NULL, | |
7712 | +#endif | |
7708 | 7713 | }; |
7709 | 7714 | |
7710 | 7715 | #ifdef HAVE_LINUX_REGSETS |
@@ -374,6 +374,9 @@ struct lwp_info | ||
374 | 374 | /* The thread handle, used for e.g. TLS access. Only valid if |
375 | 375 | THREAD_KNOWN is set. */ |
376 | 376 | td_thrhandle_t th; |
377 | + | |
378 | + /* The pthread_t handle. */ | |
379 | + thread_t thread_handle; | |
377 | 380 | #endif |
378 | 381 | |
379 | 382 | /* Arch-specific additions. */ |
@@ -416,4 +419,6 @@ int thread_db_look_up_one_symbol (const char *name, CORE_ADDR *addrp); | ||
416 | 419 | |
417 | 420 | void thread_db_notice_clone (struct process_info *proc, ptid_t lwp); |
418 | 421 | |
422 | +bool thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int *handle_len); | |
423 | + | |
419 | 424 | extern int have_ptrace_getregset; |
@@ -1648,6 +1648,9 @@ handle_qxfer_threads_worker (struct inferior_list_entry *inf, void *arg) | ||
1648 | 1648 | int core = target_core_of_thread (ptid); |
1649 | 1649 | char core_s[21]; |
1650 | 1650 | const char *name = target_thread_name (ptid); |
1651 | + int handle_len; | |
1652 | + gdb_byte *handle; | |
1653 | + bool handle_status = target_thread_handle (ptid, &handle, &handle_len); | |
1651 | 1654 | |
1652 | 1655 | write_ptid (ptid_s, ptid); |
1653 | 1656 |
@@ -1662,6 +1665,13 @@ handle_qxfer_threads_worker (struct inferior_list_entry *inf, void *arg) | ||
1662 | 1665 | if (name != NULL) |
1663 | 1666 | buffer_xml_printf (buffer, " name=\"%s\"", name); |
1664 | 1667 | |
1668 | + if (handle_status) | |
1669 | + { | |
1670 | + char *handle_s = (char *) alloca (handle_len * 2 + 1); | |
1671 | + bin2hex (handle, handle_s, handle_len); | |
1672 | + buffer_xml_printf (buffer, " handle=\"%s\"", handle_s); | |
1673 | + } | |
1674 | + | |
1665 | 1675 | buffer_xml_printf (buffer, "/>\n"); |
1666 | 1676 | } |
1667 | 1677 |
@@ -475,6 +475,11 @@ struct target_ops | ||
475 | 475 | |
476 | 476 | /* Return tdesc index for IPA. */ |
477 | 477 | int (*get_ipa_tdesc_idx) (void); |
478 | + | |
479 | + /* Thread ID to (numeric) thread handle: Return true on success and | |
480 | + false for failure. Return pointer to thread handle via HANDLE | |
481 | + and the handle's length via HANDLE_LEN. */ | |
482 | + bool (*thread_handle) (ptid_t ptid, gdb_byte **handle, int *handle_len); | |
478 | 483 | }; |
479 | 484 | |
480 | 485 | extern struct target_ops *the_target; |
@@ -693,6 +698,11 @@ void done_accessing_memory (void); | ||
693 | 698 | (the_target->thread_name ? (*the_target->thread_name) (ptid) \ |
694 | 699 | : NULL) |
695 | 700 | |
701 | +#define target_thread_handle(ptid, handle, handle_len) \ | |
702 | + (the_target->thread_handle ? (*the_target->thread_handle) \ | |
703 | + (ptid, handle, handle_len) \ | |
704 | + : false) | |
705 | + | |
696 | 706 | int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len); |
697 | 707 | |
698 | 708 | int write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr, |
@@ -200,6 +200,7 @@ find_one_thread (ptid_t ptid) | ||
200 | 200 | |
201 | 201 | lwp->thread_known = 1; |
202 | 202 | lwp->th = th; |
203 | + lwp->thread_handle = ti.ti_tid; | |
203 | 204 | |
204 | 205 | return 1; |
205 | 206 | } |
@@ -231,6 +232,7 @@ attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p) | ||
231 | 232 | gdb_assert (lwp != NULL); |
232 | 233 | lwp->thread_known = 1; |
233 | 234 | lwp->th = *th_p; |
235 | + lwp->thread_handle = ti_p->ti_tid; | |
234 | 236 | |
235 | 237 | return 1; |
236 | 238 | } |
@@ -439,6 +441,36 @@ thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, | ||
439 | 441 | return err; |
440 | 442 | } |
441 | 443 | |
444 | +/* See linux-low.h. */ | |
445 | + | |
446 | +bool | |
447 | +thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int *handle_len) | |
448 | +{ | |
449 | + struct thread_db *thread_db; | |
450 | + struct lwp_info *lwp; | |
451 | + struct thread_info *thread | |
452 | + = (struct thread_info *) find_inferior_id (&all_threads, ptid); | |
453 | + | |
454 | + if (thread == NULL) | |
455 | + return false; | |
456 | + | |
457 | + thread_db = get_thread_process (thread)->priv->thread_db; | |
458 | + | |
459 | + if (thread_db == NULL) | |
460 | + return false; | |
461 | + | |
462 | + lwp = get_thread_lwp (thread); | |
463 | + | |
464 | + if (!lwp->thread_known && !find_one_thread (thread->entry.id)) | |
465 | + return false; | |
466 | + | |
467 | + gdb_assert (lwp->thread_known); | |
468 | + | |
469 | + *handle = (gdb_byte *) &lwp->thread_handle; | |
470 | + *handle_len = sizeof (lwp->thread_handle); | |
471 | + return true; | |
472 | +} | |
473 | + | |
442 | 474 | #ifdef USE_LIBTHREAD_DB_DIRECTLY |
443 | 475 | |
444 | 476 | static int |
@@ -74,6 +74,7 @@ | ||
74 | 74 | #include <algorithm> |
75 | 75 | #include "common/scoped_restore.h" |
76 | 76 | #include "environ.h" |
77 | +#include "common/byte-vector.h" | |
77 | 78 | |
78 | 79 | /* Temp hacks for tracepoint encoding migration. */ |
79 | 80 | static char *target_buf; |
@@ -451,6 +452,10 @@ struct private_thread_info | ||
451 | 452 | char *name; |
452 | 453 | int core; |
453 | 454 | |
455 | + /* Thread handle, perhaps a pthread_t or thread_t value, stored as a | |
456 | + sequence of bytes. */ | |
457 | + gdb::byte_vector *thread_handle; | |
458 | + | |
454 | 459 | /* Whether the target stopped for a breakpoint/watchpoint. */ |
455 | 460 | enum target_stop_reason stop_reason; |
456 | 461 |
@@ -482,6 +487,7 @@ free_private_thread_info (struct private_thread_info *info) | ||
482 | 487 | { |
483 | 488 | xfree (info->extra); |
484 | 489 | xfree (info->name); |
490 | + delete info->thread_handle; | |
485 | 491 | xfree (info); |
486 | 492 | } |
487 | 493 |
@@ -1971,6 +1977,7 @@ get_private_info_thread (struct thread_info *thread) | ||
1971 | 1977 | priv->last_resume_step = 0; |
1972 | 1978 | priv->last_resume_sig = GDB_SIGNAL_0; |
1973 | 1979 | priv->vcont_resumed = 0; |
1980 | + priv->thread_handle = nullptr; | |
1974 | 1981 | } |
1975 | 1982 | |
1976 | 1983 | return thread->priv; |
@@ -2997,6 +3004,10 @@ typedef struct thread_item | ||
2997 | 3004 | |
2998 | 3005 | /* The core the thread was running on. -1 if not known. */ |
2999 | 3006 | int core; |
3007 | + | |
3008 | + /* The thread handle associated with the thread. */ | |
3009 | + gdb::byte_vector *thread_handle; | |
3010 | + | |
3000 | 3011 | } thread_item_t; |
3001 | 3012 | DEF_VEC_O(thread_item_t); |
3002 | 3013 |
@@ -3024,6 +3035,7 @@ clear_threads_listing_context (void *p) | ||
3024 | 3035 | { |
3025 | 3036 | xfree (item->extra); |
3026 | 3037 | xfree (item->name); |
3038 | + delete item->thread_handle; | |
3027 | 3039 | } |
3028 | 3040 | |
3029 | 3041 | VEC_free (thread_item_t, context->items); |
@@ -3062,6 +3074,7 @@ remote_newthread_step (threadref *ref, void *data) | ||
3062 | 3074 | item.core = -1; |
3063 | 3075 | item.name = NULL; |
3064 | 3076 | item.extra = NULL; |
3077 | + item.thread_handle = nullptr; | |
3065 | 3078 | |
3066 | 3079 | VEC_safe_push (thread_item_t, context->items, &item); |
3067 | 3080 |
@@ -3132,6 +3145,17 @@ start_thread (struct gdb_xml_parser *parser, | ||
3132 | 3145 | attr = xml_find_attribute (attributes, "name"); |
3133 | 3146 | item.name = attr != NULL ? xstrdup ((const char *) attr->value) : NULL; |
3134 | 3147 | |
3148 | + attr = xml_find_attribute (attributes, "handle"); | |
3149 | + if (attr != NULL) | |
3150 | + { | |
3151 | + item.thread_handle = new gdb::byte_vector | |
3152 | + (strlen ((const char *) attr->value) / 2); | |
3153 | + hex2bin ((const char *) attr->value, item.thread_handle->data (), | |
3154 | + item.thread_handle->size ()); | |
3155 | + } | |
3156 | + else | |
3157 | + item.thread_handle = nullptr; | |
3158 | + | |
3135 | 3159 | item.extra = 0; |
3136 | 3160 | |
3137 | 3161 | VEC_safe_push (thread_item_t, data->items, &item); |
@@ -3153,6 +3177,7 @@ const struct gdb_xml_attribute thread_attributes[] = { | ||
3153 | 3177 | { "id", GDB_XML_AF_NONE, NULL, NULL }, |
3154 | 3178 | { "core", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL }, |
3155 | 3179 | { "name", GDB_XML_AF_OPTIONAL, NULL, NULL }, |
3180 | + { "handle", GDB_XML_AF_OPTIONAL, NULL, NULL }, | |
3156 | 3181 | { NULL, GDB_XML_AF_NONE, NULL, NULL } |
3157 | 3182 | }; |
3158 | 3183 |
@@ -3228,6 +3253,7 @@ remote_get_threads_with_qthreadinfo (struct target_ops *ops, | ||
3228 | 3253 | item.core = -1; |
3229 | 3254 | item.name = NULL; |
3230 | 3255 | item.extra = NULL; |
3256 | + item.thread_handle = nullptr; | |
3231 | 3257 | |
3232 | 3258 | VEC_safe_push (thread_item_t, context->items, &item); |
3233 | 3259 | } |
@@ -3333,6 +3359,8 @@ remote_update_thread_list (struct target_ops *ops) | ||
3333 | 3359 | item->extra = NULL; |
3334 | 3360 | info->name = item->name; |
3335 | 3361 | item->name = NULL; |
3362 | + info->thread_handle = item->thread_handle; | |
3363 | + item->thread_handle = nullptr; | |
3336 | 3364 | } |
3337 | 3365 | } |
3338 | 3366 | } |
@@ -13526,6 +13554,35 @@ remote_execution_direction (struct target_ops *self) | ||
13526 | 13554 | return rs->last_resume_exec_dir; |
13527 | 13555 | } |
13528 | 13556 | |
13557 | +/* Return pointer to the thread_info struct which corresponds to | |
13558 | + THREAD_HANDLE (having length HANDLE_LEN). */ | |
13559 | + | |
13560 | +static struct thread_info * | |
13561 | +remote_thread_handle_to_thread_info (struct target_ops *ops, | |
13562 | + const gdb_byte *thread_handle, | |
13563 | + int handle_len, | |
13564 | + struct inferior *inf) | |
13565 | +{ | |
13566 | + struct thread_info *tp; | |
13567 | + | |
13568 | + ALL_NON_EXITED_THREADS (tp) | |
13569 | + { | |
13570 | + struct private_thread_info *priv = get_private_info_thread (tp); | |
13571 | + | |
13572 | + if (tp->inf == inf && priv != NULL) | |
13573 | + { | |
13574 | + if (handle_len != priv->thread_handle->size ()) | |
13575 | + error (_("Thread handle size mismatch: %d vs %zu (from remote)"), | |
13576 | + handle_len, priv->thread_handle->size ()); | |
13577 | + if (memcmp (thread_handle, priv->thread_handle->data (), | |
13578 | + handle_len) == 0) | |
13579 | + return tp; | |
13580 | + } | |
13581 | + } | |
13582 | + | |
13583 | + return NULL; | |
13584 | +} | |
13585 | + | |
13529 | 13586 | static void |
13530 | 13587 | init_remote_ops (void) |
13531 | 13588 | { |
@@ -13674,6 +13731,8 @@ Specify the serial device it is connected to\n\ | ||
13674 | 13731 | remote_ops.to_insert_exec_catchpoint = remote_insert_exec_catchpoint; |
13675 | 13732 | remote_ops.to_remove_exec_catchpoint = remote_remove_exec_catchpoint; |
13676 | 13733 | remote_ops.to_execution_direction = remote_execution_direction; |
13734 | + remote_ops.to_thread_handle_to_thread_info = | |
13735 | + remote_thread_handle_to_thread_info; | |
13677 | 13736 | } |
13678 | 13737 | |
13679 | 13738 | /* Set up the extended remote vector by making a copy of the standard |