xref: /aosp_15_r20/external/elfutils/libdwfl/dwfl_frame.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
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