1*7304104dSAndroid Build Coastguard Worker /* Get Dwarf Frame state for target PID or core file.
2*7304104dSAndroid Build Coastguard Worker Copyright (C) 2013, 2014 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker This file is part of elfutils.
4*7304104dSAndroid Build Coastguard Worker
5*7304104dSAndroid Build Coastguard Worker This file is free software; you can redistribute it and/or modify
6*7304104dSAndroid Build Coastguard Worker it under the terms of either
7*7304104dSAndroid Build Coastguard Worker
8*7304104dSAndroid Build Coastguard Worker * the GNU Lesser General Public License as published by the Free
9*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 3 of the License, or (at
10*7304104dSAndroid Build Coastguard Worker your option) any later version
11*7304104dSAndroid Build Coastguard Worker
12*7304104dSAndroid Build Coastguard Worker or
13*7304104dSAndroid Build Coastguard Worker
14*7304104dSAndroid Build Coastguard Worker * the GNU General Public License as published by the Free
15*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 2 of the License, or (at
16*7304104dSAndroid Build Coastguard Worker your option) any later version
17*7304104dSAndroid Build Coastguard Worker
18*7304104dSAndroid Build Coastguard Worker or both in parallel, as here.
19*7304104dSAndroid Build Coastguard Worker
20*7304104dSAndroid Build Coastguard Worker elfutils is distributed in the hope that it will be useful, but
21*7304104dSAndroid Build Coastguard Worker WITHOUT ANY WARRANTY; without even the implied warranty of
22*7304104dSAndroid Build Coastguard Worker MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23*7304104dSAndroid Build Coastguard Worker General Public License for more details.
24*7304104dSAndroid Build Coastguard Worker
25*7304104dSAndroid Build Coastguard Worker You should have received copies of the GNU General Public License and
26*7304104dSAndroid Build Coastguard Worker the GNU Lesser General Public License along with this program. If
27*7304104dSAndroid Build Coastguard Worker not, see <http://www.gnu.org/licenses/>. */
28*7304104dSAndroid Build Coastguard Worker
29*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
30*7304104dSAndroid Build Coastguard Worker # include <config.h>
31*7304104dSAndroid Build Coastguard Worker #endif
32*7304104dSAndroid Build Coastguard Worker
33*7304104dSAndroid Build Coastguard Worker #include <system.h>
34*7304104dSAndroid Build Coastguard Worker
35*7304104dSAndroid Build Coastguard Worker #include "libdwflP.h"
36*7304104dSAndroid Build Coastguard Worker
37*7304104dSAndroid Build Coastguard Worker /* Set STATE->pc_set from STATE->regs according to the backend. Return true on
38*7304104dSAndroid Build Coastguard Worker success, false on error. */
39*7304104dSAndroid Build Coastguard Worker static bool
state_fetch_pc(Dwfl_Frame * state)40*7304104dSAndroid Build Coastguard Worker state_fetch_pc (Dwfl_Frame *state)
41*7304104dSAndroid Build Coastguard Worker {
42*7304104dSAndroid Build Coastguard Worker switch (state->pc_state)
43*7304104dSAndroid Build Coastguard Worker {
44*7304104dSAndroid Build Coastguard Worker case DWFL_FRAME_STATE_PC_SET:
45*7304104dSAndroid Build Coastguard Worker return true;
46*7304104dSAndroid Build Coastguard Worker case DWFL_FRAME_STATE_PC_UNDEFINED:
47*7304104dSAndroid Build Coastguard Worker abort ();
48*7304104dSAndroid Build Coastguard Worker case DWFL_FRAME_STATE_ERROR:
49*7304104dSAndroid Build Coastguard Worker {
50*7304104dSAndroid Build Coastguard Worker Ebl *ebl = state->thread->process->ebl;
51*7304104dSAndroid Build Coastguard Worker Dwarf_CIE abi_info;
52*7304104dSAndroid Build Coastguard Worker if (ebl_abi_cfi (ebl, &abi_info) != 0)
53*7304104dSAndroid Build Coastguard Worker {
54*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_LIBEBL);
55*7304104dSAndroid Build Coastguard Worker return false;
56*7304104dSAndroid Build Coastguard Worker }
57*7304104dSAndroid Build Coastguard Worker unsigned ra = abi_info.return_address_register;
58*7304104dSAndroid Build Coastguard Worker /* dwarf_frame_state_reg_is_set is not applied here. */
59*7304104dSAndroid Build Coastguard Worker if (ra >= ebl_frame_nregs (ebl))
60*7304104dSAndroid Build Coastguard Worker {
61*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_LIBEBL_BAD);
62*7304104dSAndroid Build Coastguard Worker return false;
63*7304104dSAndroid Build Coastguard Worker }
64*7304104dSAndroid Build Coastguard Worker state->pc = state->regs[ra] + ebl_ra_offset (ebl);
65*7304104dSAndroid Build Coastguard Worker state->pc_state = DWFL_FRAME_STATE_PC_SET;
66*7304104dSAndroid Build Coastguard Worker }
67*7304104dSAndroid Build Coastguard Worker return true;
68*7304104dSAndroid Build Coastguard Worker }
69*7304104dSAndroid Build Coastguard Worker abort ();
70*7304104dSAndroid Build Coastguard Worker }
71*7304104dSAndroid Build Coastguard Worker
72*7304104dSAndroid Build Coastguard Worker /* Do not call it on your own, to be used by thread_* functions only. */
73*7304104dSAndroid Build Coastguard Worker
74*7304104dSAndroid Build Coastguard Worker static void
free_states(Dwfl_Frame * state)75*7304104dSAndroid Build Coastguard Worker free_states (Dwfl_Frame *state)
76*7304104dSAndroid Build Coastguard Worker {
77*7304104dSAndroid Build Coastguard Worker while (state)
78*7304104dSAndroid Build Coastguard Worker {
79*7304104dSAndroid Build Coastguard Worker Dwfl_Frame *next = state->unwound;
80*7304104dSAndroid Build Coastguard Worker free(state);
81*7304104dSAndroid Build Coastguard Worker state = next;
82*7304104dSAndroid Build Coastguard Worker }
83*7304104dSAndroid Build Coastguard Worker }
84*7304104dSAndroid Build Coastguard Worker
85*7304104dSAndroid Build Coastguard Worker static Dwfl_Frame *
state_alloc(Dwfl_Thread * thread)86*7304104dSAndroid Build Coastguard Worker state_alloc (Dwfl_Thread *thread)
87*7304104dSAndroid Build Coastguard Worker {
88*7304104dSAndroid Build Coastguard Worker assert (thread->unwound == NULL);
89*7304104dSAndroid Build Coastguard Worker Ebl *ebl = thread->process->ebl;
90*7304104dSAndroid Build Coastguard Worker size_t nregs = ebl_frame_nregs (ebl);
91*7304104dSAndroid Build Coastguard Worker if (nregs == 0)
92*7304104dSAndroid Build Coastguard Worker return NULL;
93*7304104dSAndroid Build Coastguard Worker assert (nregs < sizeof (((Dwfl_Frame *) NULL)->regs_set) * 8);
94*7304104dSAndroid Build Coastguard Worker Dwfl_Frame *state = malloc (sizeof (*state) + sizeof (*state->regs) * nregs);
95*7304104dSAndroid Build Coastguard Worker if (state == NULL)
96*7304104dSAndroid Build Coastguard Worker return NULL;
97*7304104dSAndroid Build Coastguard Worker state->thread = thread;
98*7304104dSAndroid Build Coastguard Worker state->signal_frame = false;
99*7304104dSAndroid Build Coastguard Worker state->initial_frame = true;
100*7304104dSAndroid Build Coastguard Worker state->pc_state = DWFL_FRAME_STATE_ERROR;
101*7304104dSAndroid Build Coastguard Worker memset (state->regs_set, 0, sizeof (state->regs_set));
102*7304104dSAndroid Build Coastguard Worker thread->unwound = state;
103*7304104dSAndroid Build Coastguard Worker state->unwound = NULL;
104*7304104dSAndroid Build Coastguard Worker return state;
105*7304104dSAndroid Build Coastguard Worker }
106*7304104dSAndroid Build Coastguard Worker
107*7304104dSAndroid Build Coastguard Worker void
108*7304104dSAndroid Build Coastguard Worker internal_function
__libdwfl_process_free(Dwfl_Process * process)109*7304104dSAndroid Build Coastguard Worker __libdwfl_process_free (Dwfl_Process *process)
110*7304104dSAndroid Build Coastguard Worker {
111*7304104dSAndroid Build Coastguard Worker Dwfl *dwfl = process->dwfl;
112*7304104dSAndroid Build Coastguard Worker if (process->callbacks->detach != NULL)
113*7304104dSAndroid Build Coastguard Worker process->callbacks->detach (dwfl, process->callbacks_arg);
114*7304104dSAndroid Build Coastguard Worker assert (dwfl->process == process);
115*7304104dSAndroid Build Coastguard Worker dwfl->process = NULL;
116*7304104dSAndroid Build Coastguard Worker if (process->ebl_close)
117*7304104dSAndroid Build Coastguard Worker ebl_closebackend (process->ebl);
118*7304104dSAndroid Build Coastguard Worker free (process);
119*7304104dSAndroid Build Coastguard Worker dwfl->attacherr = DWFL_E_NOERROR;
120*7304104dSAndroid Build Coastguard Worker }
121*7304104dSAndroid Build Coastguard Worker
122*7304104dSAndroid Build Coastguard Worker /* Allocate new Dwfl_Process for DWFL. */
123*7304104dSAndroid Build Coastguard Worker static void
process_alloc(Dwfl * dwfl)124*7304104dSAndroid Build Coastguard Worker process_alloc (Dwfl *dwfl)
125*7304104dSAndroid Build Coastguard Worker {
126*7304104dSAndroid Build Coastguard Worker Dwfl_Process *process = malloc (sizeof (*process));
127*7304104dSAndroid Build Coastguard Worker if (process == NULL)
128*7304104dSAndroid Build Coastguard Worker return;
129*7304104dSAndroid Build Coastguard Worker process->dwfl = dwfl;
130*7304104dSAndroid Build Coastguard Worker dwfl->process = process;
131*7304104dSAndroid Build Coastguard Worker }
132*7304104dSAndroid Build Coastguard Worker
133*7304104dSAndroid Build Coastguard Worker bool
dwfl_attach_state(Dwfl * dwfl,Elf * elf,pid_t pid,const Dwfl_Thread_Callbacks * thread_callbacks,void * arg)134*7304104dSAndroid Build Coastguard Worker dwfl_attach_state (Dwfl *dwfl, Elf *elf, pid_t pid,
135*7304104dSAndroid Build Coastguard Worker const Dwfl_Thread_Callbacks *thread_callbacks, void *arg)
136*7304104dSAndroid Build Coastguard Worker {
137*7304104dSAndroid Build Coastguard Worker if (dwfl->process != NULL)
138*7304104dSAndroid Build Coastguard Worker {
139*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_ATTACH_STATE_CONFLICT);
140*7304104dSAndroid Build Coastguard Worker return false;
141*7304104dSAndroid Build Coastguard Worker }
142*7304104dSAndroid Build Coastguard Worker
143*7304104dSAndroid Build Coastguard Worker /* Reset any previous error, we are just going to try again. */
144*7304104dSAndroid Build Coastguard Worker dwfl->attacherr = DWFL_E_NOERROR;
145*7304104dSAndroid Build Coastguard Worker /* thread_callbacks is declared NN */
146*7304104dSAndroid Build Coastguard Worker if (thread_callbacks->next_thread == NULL
147*7304104dSAndroid Build Coastguard Worker || thread_callbacks->set_initial_registers == NULL)
148*7304104dSAndroid Build Coastguard Worker {
149*7304104dSAndroid Build Coastguard Worker dwfl->attacherr = DWFL_E_INVALID_ARGUMENT;
150*7304104dSAndroid Build Coastguard Worker fail:
151*7304104dSAndroid Build Coastguard Worker dwfl->attacherr = __libdwfl_canon_error (dwfl->attacherr);
152*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (dwfl->attacherr);
153*7304104dSAndroid Build Coastguard Worker return false;
154*7304104dSAndroid Build Coastguard Worker }
155*7304104dSAndroid Build Coastguard Worker
156*7304104dSAndroid Build Coastguard Worker Ebl *ebl;
157*7304104dSAndroid Build Coastguard Worker bool ebl_close;
158*7304104dSAndroid Build Coastguard Worker if (elf != NULL)
159*7304104dSAndroid Build Coastguard Worker {
160*7304104dSAndroid Build Coastguard Worker ebl = ebl_openbackend (elf);
161*7304104dSAndroid Build Coastguard Worker ebl_close = true;
162*7304104dSAndroid Build Coastguard Worker }
163*7304104dSAndroid Build Coastguard Worker else
164*7304104dSAndroid Build Coastguard Worker {
165*7304104dSAndroid Build Coastguard Worker ebl = NULL;
166*7304104dSAndroid Build Coastguard Worker for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
167*7304104dSAndroid Build Coastguard Worker {
168*7304104dSAndroid Build Coastguard Worker /* Reading of the vDSO or (deleted) modules may fail as
169*7304104dSAndroid Build Coastguard Worker /proc/PID/mem is unreadable without PTRACE_ATTACH and
170*7304104dSAndroid Build Coastguard Worker we may not be PTRACE_ATTACH-ed now. MOD would not be
171*7304104dSAndroid Build Coastguard Worker re-read later to unwind it when we are already
172*7304104dSAndroid Build Coastguard Worker PTRACE_ATTACH-ed to PID. This happens when this function
173*7304104dSAndroid Build Coastguard Worker is called from dwfl_linux_proc_attach with elf == NULL.
174*7304104dSAndroid Build Coastguard Worker __libdwfl_module_getebl will call __libdwfl_getelf which
175*7304104dSAndroid Build Coastguard Worker will call the find_elf callback. */
176*7304104dSAndroid Build Coastguard Worker if (startswith (mod->name, "[vdso: ")
177*7304104dSAndroid Build Coastguard Worker || strcmp (strrchr (mod->name, ' ') ?: "",
178*7304104dSAndroid Build Coastguard Worker " (deleted)") == 0)
179*7304104dSAndroid Build Coastguard Worker continue;
180*7304104dSAndroid Build Coastguard Worker Dwfl_Error error = __libdwfl_module_getebl (mod);
181*7304104dSAndroid Build Coastguard Worker if (error != DWFL_E_NOERROR)
182*7304104dSAndroid Build Coastguard Worker continue;
183*7304104dSAndroid Build Coastguard Worker ebl = mod->ebl;
184*7304104dSAndroid Build Coastguard Worker break;
185*7304104dSAndroid Build Coastguard Worker }
186*7304104dSAndroid Build Coastguard Worker ebl_close = false;
187*7304104dSAndroid Build Coastguard Worker }
188*7304104dSAndroid Build Coastguard Worker if (ebl == NULL)
189*7304104dSAndroid Build Coastguard Worker {
190*7304104dSAndroid Build Coastguard Worker /* Not identified EBL from any of the modules. */
191*7304104dSAndroid Build Coastguard Worker dwfl->attacherr = DWFL_E_PROCESS_NO_ARCH;
192*7304104dSAndroid Build Coastguard Worker goto fail;
193*7304104dSAndroid Build Coastguard Worker }
194*7304104dSAndroid Build Coastguard Worker process_alloc (dwfl);
195*7304104dSAndroid Build Coastguard Worker Dwfl_Process *process = dwfl->process;
196*7304104dSAndroid Build Coastguard Worker if (process == NULL)
197*7304104dSAndroid Build Coastguard Worker {
198*7304104dSAndroid Build Coastguard Worker if (ebl_close)
199*7304104dSAndroid Build Coastguard Worker ebl_closebackend (ebl);
200*7304104dSAndroid Build Coastguard Worker dwfl->attacherr = DWFL_E_NOMEM;
201*7304104dSAndroid Build Coastguard Worker goto fail;
202*7304104dSAndroid Build Coastguard Worker }
203*7304104dSAndroid Build Coastguard Worker process->ebl = ebl;
204*7304104dSAndroid Build Coastguard Worker process->ebl_close = ebl_close;
205*7304104dSAndroid Build Coastguard Worker process->pid = pid;
206*7304104dSAndroid Build Coastguard Worker process->callbacks = thread_callbacks;
207*7304104dSAndroid Build Coastguard Worker process->callbacks_arg = arg;
208*7304104dSAndroid Build Coastguard Worker return true;
209*7304104dSAndroid Build Coastguard Worker }
INTDEF(dwfl_attach_state)210*7304104dSAndroid Build Coastguard Worker INTDEF(dwfl_attach_state)
211*7304104dSAndroid Build Coastguard Worker
212*7304104dSAndroid Build Coastguard Worker pid_t
213*7304104dSAndroid Build Coastguard Worker dwfl_pid (Dwfl *dwfl)
214*7304104dSAndroid Build Coastguard Worker {
215*7304104dSAndroid Build Coastguard Worker if (dwfl->attacherr != DWFL_E_NOERROR)
216*7304104dSAndroid Build Coastguard Worker {
217*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (dwfl->attacherr);
218*7304104dSAndroid Build Coastguard Worker return -1;
219*7304104dSAndroid Build Coastguard Worker }
220*7304104dSAndroid Build Coastguard Worker
221*7304104dSAndroid Build Coastguard Worker if (dwfl->process == NULL)
222*7304104dSAndroid Build Coastguard Worker {
223*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
224*7304104dSAndroid Build Coastguard Worker return -1;
225*7304104dSAndroid Build Coastguard Worker }
226*7304104dSAndroid Build Coastguard Worker return dwfl->process->pid;
227*7304104dSAndroid Build Coastguard Worker }
INTDEF(dwfl_pid)228*7304104dSAndroid Build Coastguard Worker INTDEF(dwfl_pid)
229*7304104dSAndroid Build Coastguard Worker
230*7304104dSAndroid Build Coastguard Worker Dwfl *
231*7304104dSAndroid Build Coastguard Worker dwfl_thread_dwfl (Dwfl_Thread *thread)
232*7304104dSAndroid Build Coastguard Worker {
233*7304104dSAndroid Build Coastguard Worker return thread->process->dwfl;
234*7304104dSAndroid Build Coastguard Worker }
INTDEF(dwfl_thread_dwfl)235*7304104dSAndroid Build Coastguard Worker INTDEF(dwfl_thread_dwfl)
236*7304104dSAndroid Build Coastguard Worker
237*7304104dSAndroid Build Coastguard Worker pid_t
238*7304104dSAndroid Build Coastguard Worker dwfl_thread_tid (Dwfl_Thread *thread)
239*7304104dSAndroid Build Coastguard Worker {
240*7304104dSAndroid Build Coastguard Worker return thread->tid;
241*7304104dSAndroid Build Coastguard Worker }
INTDEF(dwfl_thread_tid)242*7304104dSAndroid Build Coastguard Worker INTDEF(dwfl_thread_tid)
243*7304104dSAndroid Build Coastguard Worker
244*7304104dSAndroid Build Coastguard Worker Dwfl_Thread *
245*7304104dSAndroid Build Coastguard Worker dwfl_frame_thread (Dwfl_Frame *state)
246*7304104dSAndroid Build Coastguard Worker {
247*7304104dSAndroid Build Coastguard Worker return state->thread;
248*7304104dSAndroid Build Coastguard Worker }
INTDEF(dwfl_frame_thread)249*7304104dSAndroid Build Coastguard Worker INTDEF(dwfl_frame_thread)
250*7304104dSAndroid Build Coastguard Worker
251*7304104dSAndroid Build Coastguard Worker int
252*7304104dSAndroid Build Coastguard Worker dwfl_getthreads (Dwfl *dwfl, int (*callback) (Dwfl_Thread *thread, void *arg),
253*7304104dSAndroid Build Coastguard Worker void *arg)
254*7304104dSAndroid Build Coastguard Worker {
255*7304104dSAndroid Build Coastguard Worker if (dwfl->attacherr != DWFL_E_NOERROR)
256*7304104dSAndroid Build Coastguard Worker {
257*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (dwfl->attacherr);
258*7304104dSAndroid Build Coastguard Worker return -1;
259*7304104dSAndroid Build Coastguard Worker }
260*7304104dSAndroid Build Coastguard Worker
261*7304104dSAndroid Build Coastguard Worker Dwfl_Process *process = dwfl->process;
262*7304104dSAndroid Build Coastguard Worker if (process == NULL)
263*7304104dSAndroid Build Coastguard Worker {
264*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
265*7304104dSAndroid Build Coastguard Worker return -1;
266*7304104dSAndroid Build Coastguard Worker }
267*7304104dSAndroid Build Coastguard Worker
268*7304104dSAndroid Build Coastguard Worker Dwfl_Thread thread;
269*7304104dSAndroid Build Coastguard Worker thread.process = process;
270*7304104dSAndroid Build Coastguard Worker thread.unwound = NULL;
271*7304104dSAndroid Build Coastguard Worker thread.callbacks_arg = NULL;
272*7304104dSAndroid Build Coastguard Worker for (;;)
273*7304104dSAndroid Build Coastguard Worker {
274*7304104dSAndroid Build Coastguard Worker thread.tid = process->callbacks->next_thread (dwfl,
275*7304104dSAndroid Build Coastguard Worker process->callbacks_arg,
276*7304104dSAndroid Build Coastguard Worker &thread.callbacks_arg);
277*7304104dSAndroid Build Coastguard Worker if (thread.tid < 0)
278*7304104dSAndroid Build Coastguard Worker return -1;
279*7304104dSAndroid Build Coastguard Worker if (thread.tid == 0)
280*7304104dSAndroid Build Coastguard Worker {
281*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_NOERROR);
282*7304104dSAndroid Build Coastguard Worker return 0;
283*7304104dSAndroid Build Coastguard Worker }
284*7304104dSAndroid Build Coastguard Worker int err = callback (&thread, arg);
285*7304104dSAndroid Build Coastguard Worker if (err != DWARF_CB_OK)
286*7304104dSAndroid Build Coastguard Worker return err;
287*7304104dSAndroid Build Coastguard Worker assert (thread.unwound == NULL);
288*7304104dSAndroid Build Coastguard Worker }
289*7304104dSAndroid Build Coastguard Worker /* NOTREACHED */
290*7304104dSAndroid Build Coastguard Worker }
291*7304104dSAndroid Build Coastguard Worker INTDEF(dwfl_getthreads)
292*7304104dSAndroid Build Coastguard Worker
293*7304104dSAndroid Build Coastguard Worker struct one_arg
294*7304104dSAndroid Build Coastguard Worker {
295*7304104dSAndroid Build Coastguard Worker pid_t tid;
296*7304104dSAndroid Build Coastguard Worker bool seen;
297*7304104dSAndroid Build Coastguard Worker int (*callback) (Dwfl_Thread *thread, void *arg);
298*7304104dSAndroid Build Coastguard Worker void *arg;
299*7304104dSAndroid Build Coastguard Worker int ret;
300*7304104dSAndroid Build Coastguard Worker };
301*7304104dSAndroid Build Coastguard Worker
302*7304104dSAndroid Build Coastguard Worker static int
get_one_thread_cb(Dwfl_Thread * thread,void * arg)303*7304104dSAndroid Build Coastguard Worker get_one_thread_cb (Dwfl_Thread *thread, void *arg)
304*7304104dSAndroid Build Coastguard Worker {
305*7304104dSAndroid Build Coastguard Worker struct one_arg *oa = (struct one_arg *) arg;
306*7304104dSAndroid Build Coastguard Worker if (! oa->seen && INTUSE(dwfl_thread_tid) (thread) == oa->tid)
307*7304104dSAndroid Build Coastguard Worker {
308*7304104dSAndroid Build Coastguard Worker oa->seen = true;
309*7304104dSAndroid Build Coastguard Worker oa->ret = oa->callback (thread, oa->arg);
310*7304104dSAndroid Build Coastguard Worker return DWARF_CB_ABORT;
311*7304104dSAndroid Build Coastguard Worker }
312*7304104dSAndroid Build Coastguard Worker
313*7304104dSAndroid Build Coastguard Worker return DWARF_CB_OK;
314*7304104dSAndroid Build Coastguard Worker }
315*7304104dSAndroid Build Coastguard Worker
316*7304104dSAndroid Build Coastguard Worker /* Note not currently exported, will be when there are more Dwfl_Thread
317*7304104dSAndroid Build Coastguard Worker properties to query. Use dwfl_getthread_frames for now directly. */
318*7304104dSAndroid Build Coastguard Worker static int
getthread(Dwfl * dwfl,pid_t tid,int (* callback)(Dwfl_Thread * thread,void * arg),void * arg)319*7304104dSAndroid Build Coastguard Worker getthread (Dwfl *dwfl, pid_t tid,
320*7304104dSAndroid Build Coastguard Worker int (*callback) (Dwfl_Thread *thread, void *arg),
321*7304104dSAndroid Build Coastguard Worker void *arg)
322*7304104dSAndroid Build Coastguard Worker {
323*7304104dSAndroid Build Coastguard Worker if (dwfl->attacherr != DWFL_E_NOERROR)
324*7304104dSAndroid Build Coastguard Worker {
325*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (dwfl->attacherr);
326*7304104dSAndroid Build Coastguard Worker return -1;
327*7304104dSAndroid Build Coastguard Worker }
328*7304104dSAndroid Build Coastguard Worker
329*7304104dSAndroid Build Coastguard Worker Dwfl_Process *process = dwfl->process;
330*7304104dSAndroid Build Coastguard Worker if (process == NULL)
331*7304104dSAndroid Build Coastguard Worker {
332*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
333*7304104dSAndroid Build Coastguard Worker return -1;
334*7304104dSAndroid Build Coastguard Worker }
335*7304104dSAndroid Build Coastguard Worker
336*7304104dSAndroid Build Coastguard Worker if (process->callbacks->get_thread != NULL)
337*7304104dSAndroid Build Coastguard Worker {
338*7304104dSAndroid Build Coastguard Worker Dwfl_Thread thread;
339*7304104dSAndroid Build Coastguard Worker thread.process = process;
340*7304104dSAndroid Build Coastguard Worker thread.unwound = NULL;
341*7304104dSAndroid Build Coastguard Worker thread.callbacks_arg = NULL;
342*7304104dSAndroid Build Coastguard Worker
343*7304104dSAndroid Build Coastguard Worker if (process->callbacks->get_thread (dwfl, tid, process->callbacks_arg,
344*7304104dSAndroid Build Coastguard Worker &thread.callbacks_arg))
345*7304104dSAndroid Build Coastguard Worker {
346*7304104dSAndroid Build Coastguard Worker thread.tid = tid;
347*7304104dSAndroid Build Coastguard Worker return callback (&thread, arg);
348*7304104dSAndroid Build Coastguard Worker }
349*7304104dSAndroid Build Coastguard Worker
350*7304104dSAndroid Build Coastguard Worker return -1;
351*7304104dSAndroid Build Coastguard Worker }
352*7304104dSAndroid Build Coastguard Worker
353*7304104dSAndroid Build Coastguard Worker struct one_arg oa = { .tid = tid, .callback = callback,
354*7304104dSAndroid Build Coastguard Worker .arg = arg, .seen = false };
355*7304104dSAndroid Build Coastguard Worker int err = INTUSE(dwfl_getthreads) (dwfl, get_one_thread_cb, &oa);
356*7304104dSAndroid Build Coastguard Worker
357*7304104dSAndroid Build Coastguard Worker if (err == DWARF_CB_ABORT && oa.seen)
358*7304104dSAndroid Build Coastguard Worker return oa.ret;
359*7304104dSAndroid Build Coastguard Worker
360*7304104dSAndroid Build Coastguard Worker if (err == DWARF_CB_OK && ! oa.seen)
361*7304104dSAndroid Build Coastguard Worker {
362*7304104dSAndroid Build Coastguard Worker errno = ESRCH;
363*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_ERRNO);
364*7304104dSAndroid Build Coastguard Worker return -1;
365*7304104dSAndroid Build Coastguard Worker }
366*7304104dSAndroid Build Coastguard Worker
367*7304104dSAndroid Build Coastguard Worker return err;
368*7304104dSAndroid Build Coastguard Worker }
369*7304104dSAndroid Build Coastguard Worker
370*7304104dSAndroid Build Coastguard Worker struct one_thread
371*7304104dSAndroid Build Coastguard Worker {
372*7304104dSAndroid Build Coastguard Worker int (*callback) (Dwfl_Frame *frame, void *arg);
373*7304104dSAndroid Build Coastguard Worker void *arg;
374*7304104dSAndroid Build Coastguard Worker };
375*7304104dSAndroid Build Coastguard Worker
376*7304104dSAndroid Build Coastguard Worker static int
get_one_thread_frames_cb(Dwfl_Thread * thread,void * arg)377*7304104dSAndroid Build Coastguard Worker get_one_thread_frames_cb (Dwfl_Thread *thread, void *arg)
378*7304104dSAndroid Build Coastguard Worker {
379*7304104dSAndroid Build Coastguard Worker struct one_thread *ot = (struct one_thread *) arg;
380*7304104dSAndroid Build Coastguard Worker return INTUSE(dwfl_thread_getframes) (thread, ot->callback, ot->arg);
381*7304104dSAndroid Build Coastguard Worker }
382*7304104dSAndroid Build Coastguard Worker
383*7304104dSAndroid Build Coastguard Worker int
dwfl_getthread_frames(Dwfl * dwfl,pid_t tid,int (* callback)(Dwfl_Frame * frame,void * arg),void * arg)384*7304104dSAndroid Build Coastguard Worker dwfl_getthread_frames (Dwfl *dwfl, pid_t tid,
385*7304104dSAndroid Build Coastguard Worker int (*callback) (Dwfl_Frame *frame, void *arg),
386*7304104dSAndroid Build Coastguard Worker void *arg)
387*7304104dSAndroid Build Coastguard Worker {
388*7304104dSAndroid Build Coastguard Worker struct one_thread ot = { .callback = callback, .arg = arg };
389*7304104dSAndroid Build Coastguard Worker return getthread (dwfl, tid, get_one_thread_frames_cb, &ot);
390*7304104dSAndroid Build Coastguard Worker }
INTDEF(dwfl_getthread_frames)391*7304104dSAndroid Build Coastguard Worker INTDEF(dwfl_getthread_frames)
392*7304104dSAndroid Build Coastguard Worker
393*7304104dSAndroid Build Coastguard Worker int
394*7304104dSAndroid Build Coastguard Worker dwfl_thread_getframes (Dwfl_Thread *thread,
395*7304104dSAndroid Build Coastguard Worker int (*callback) (Dwfl_Frame *state, void *arg),
396*7304104dSAndroid Build Coastguard Worker void *arg)
397*7304104dSAndroid Build Coastguard Worker {
398*7304104dSAndroid Build Coastguard Worker Ebl *ebl = thread->process->ebl;
399*7304104dSAndroid Build Coastguard Worker if (ebl_frame_nregs (ebl) == 0)
400*7304104dSAndroid Build Coastguard Worker {
401*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_NO_UNWIND);
402*7304104dSAndroid Build Coastguard Worker return -1;
403*7304104dSAndroid Build Coastguard Worker }
404*7304104dSAndroid Build Coastguard Worker if (state_alloc (thread) == NULL)
405*7304104dSAndroid Build Coastguard Worker {
406*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_NOMEM);
407*7304104dSAndroid Build Coastguard Worker return -1;
408*7304104dSAndroid Build Coastguard Worker }
409*7304104dSAndroid Build Coastguard Worker Dwfl_Process *process = thread->process;
410*7304104dSAndroid Build Coastguard Worker if (! process->callbacks->set_initial_registers (thread,
411*7304104dSAndroid Build Coastguard Worker thread->callbacks_arg))
412*7304104dSAndroid Build Coastguard Worker {
413*7304104dSAndroid Build Coastguard Worker free_states (thread->unwound);
414*7304104dSAndroid Build Coastguard Worker thread->unwound = NULL;
415*7304104dSAndroid Build Coastguard Worker return -1;
416*7304104dSAndroid Build Coastguard Worker }
417*7304104dSAndroid Build Coastguard Worker Dwfl_Frame *state = thread->unwound;
418*7304104dSAndroid Build Coastguard Worker thread->unwound = NULL;
419*7304104dSAndroid Build Coastguard Worker if (! state_fetch_pc (state))
420*7304104dSAndroid Build Coastguard Worker {
421*7304104dSAndroid Build Coastguard Worker if (process->callbacks->thread_detach)
422*7304104dSAndroid Build Coastguard Worker process->callbacks->thread_detach (thread, thread->callbacks_arg);
423*7304104dSAndroid Build Coastguard Worker free_states (state);
424*7304104dSAndroid Build Coastguard Worker return -1;
425*7304104dSAndroid Build Coastguard Worker }
426*7304104dSAndroid Build Coastguard Worker do
427*7304104dSAndroid Build Coastguard Worker {
428*7304104dSAndroid Build Coastguard Worker int err = callback (state, arg);
429*7304104dSAndroid Build Coastguard Worker if (err != DWARF_CB_OK)
430*7304104dSAndroid Build Coastguard Worker {
431*7304104dSAndroid Build Coastguard Worker if (process->callbacks->thread_detach)
432*7304104dSAndroid Build Coastguard Worker process->callbacks->thread_detach (thread, thread->callbacks_arg);
433*7304104dSAndroid Build Coastguard Worker free_states (state);
434*7304104dSAndroid Build Coastguard Worker return err;
435*7304104dSAndroid Build Coastguard Worker }
436*7304104dSAndroid Build Coastguard Worker __libdwfl_frame_unwind (state);
437*7304104dSAndroid Build Coastguard Worker Dwfl_Frame *next = state->unwound;
438*7304104dSAndroid Build Coastguard Worker /* The old frame is no longer needed. */
439*7304104dSAndroid Build Coastguard Worker free (state);
440*7304104dSAndroid Build Coastguard Worker state = next;
441*7304104dSAndroid Build Coastguard Worker }
442*7304104dSAndroid Build Coastguard Worker while (state && state->pc_state == DWFL_FRAME_STATE_PC_SET);
443*7304104dSAndroid Build Coastguard Worker
444*7304104dSAndroid Build Coastguard Worker Dwfl_Error err = dwfl_errno ();
445*7304104dSAndroid Build Coastguard Worker if (process->callbacks->thread_detach)
446*7304104dSAndroid Build Coastguard Worker process->callbacks->thread_detach (thread, thread->callbacks_arg);
447*7304104dSAndroid Build Coastguard Worker if (state == NULL || state->pc_state == DWFL_FRAME_STATE_ERROR)
448*7304104dSAndroid Build Coastguard Worker {
449*7304104dSAndroid Build Coastguard Worker free_states (state);
450*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (err);
451*7304104dSAndroid Build Coastguard Worker return -1;
452*7304104dSAndroid Build Coastguard Worker }
453*7304104dSAndroid Build Coastguard Worker assert (state->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED);
454*7304104dSAndroid Build Coastguard Worker free_states (state);
455*7304104dSAndroid Build Coastguard Worker return 0;
456*7304104dSAndroid Build Coastguard Worker }
457*7304104dSAndroid Build Coastguard Worker INTDEF(dwfl_thread_getframes)
458