1 | /* Validate a thread handle. |
2 | Copyright (C) 1999-2021 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. |
5 | |
6 | The GNU C Library is free software; you can redistribute it and/or |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either |
9 | version 2.1 of the License, or (at your option) any later version. |
10 | |
11 | The GNU C Library is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | Lesser General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU Lesser General Public |
17 | License along with the GNU C Library; if not, see |
18 | <https://www.gnu.org/licenses/>. */ |
19 | |
20 | #include "thread_dbP.h" |
21 | #include <stdbool.h> |
22 | |
23 | td_err_e |
24 | __td_ta_stack_user (td_thragent_t *ta, psaddr_t *plist) |
25 | { |
26 | if (__td_ta_rtld_global (ta)) |
27 | return DB_GET_FIELD_ADDRESS (*plist, ta, ta->ta_addr__rtld_global, |
28 | rtld_global, _dl_stack_user, 0); |
29 | else |
30 | { |
31 | if (ta->ta_addr__dl_stack_user == 0 |
32 | && td_mod_lookup (ta->ph, NULL, SYM__dl_stack_user, |
33 | &ta->ta_addr__dl_stack_user) != PS_OK) |
34 | return TD_ERR; |
35 | *plist = ta->ta_addr__dl_stack_user; |
36 | return TD_OK; |
37 | } |
38 | } |
39 | |
40 | td_err_e |
41 | __td_ta_stack_used (td_thragent_t *ta, psaddr_t *plist) |
42 | { |
43 | |
44 | if (__td_ta_rtld_global (ta)) |
45 | return DB_GET_FIELD_ADDRESS (*plist, ta, ta->ta_addr__rtld_global, |
46 | rtld_global, _dl_stack_used, 0); |
47 | else |
48 | { |
49 | if (ta->ta_addr__dl_stack_used == 0 |
50 | && td_mod_lookup (ta->ph, NULL, SYM__dl_stack_used, |
51 | &ta->ta_addr__dl_stack_used) != PS_OK) |
52 | return TD_ERR; |
53 | *plist = ta->ta_addr__dl_stack_used; |
54 | return TD_OK; |
55 | } |
56 | } |
57 | |
58 | static td_err_e |
59 | check_thread_list (const td_thrhandle_t *th, psaddr_t head, bool *uninit) |
60 | { |
61 | td_err_e err; |
62 | psaddr_t next, ofs; |
63 | |
64 | err = DB_GET_FIELD (next, th->th_ta_p, head, list_t, next, 0); |
65 | if (err == TD_OK) |
66 | { |
67 | if (next == 0) |
68 | { |
69 | *uninit = true; |
70 | return TD_NOTHR; |
71 | } |
72 | err = DB_GET_FIELD_ADDRESS (ofs, th->th_ta_p, 0, pthread, list, 0); |
73 | } |
74 | |
75 | while (err == TD_OK) |
76 | { |
77 | if (next == head) |
78 | return TD_NOTHR; |
79 | |
80 | if (next - (ofs - (psaddr_t) 0) == th->th_unique) |
81 | return TD_OK; |
82 | |
83 | err = DB_GET_FIELD (next, th->th_ta_p, next, list_t, next, 0); |
84 | } |
85 | |
86 | return err; |
87 | } |
88 | |
89 | |
90 | td_err_e |
91 | td_thr_validate (const td_thrhandle_t *th) |
92 | { |
93 | td_err_e err; |
94 | psaddr_t list; |
95 | |
96 | LOG ("td_thr_validate" ); |
97 | |
98 | /* First check the list with threads using user allocated stacks. */ |
99 | bool uninit = false; |
100 | err = __td_ta_stack_user (th->th_ta_p, &list); |
101 | if (err == TD_OK) |
102 | err = check_thread_list (th, list, &uninit); |
103 | |
104 | /* If our thread is not on this list search the list with stack |
105 | using implementation allocated stacks. */ |
106 | if (err == TD_NOTHR) |
107 | { |
108 | err = __td_ta_stack_used (th->th_ta_p, &list); |
109 | if (err == TD_OK) |
110 | err = check_thread_list (th, list, &uninit); |
111 | |
112 | if (err == TD_NOTHR && uninit && th->th_unique == 0) |
113 | /* __pthread_initialize_minimal has not run yet. |
114 | There is only the special case thread handle. */ |
115 | err = TD_OK; |
116 | } |
117 | |
118 | return err; |
119 | } |
120 | |