1*7304104dSAndroid Build Coastguard Worker /* Get Dwarf Frame state for target 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 "libdwflP.h"
34*7304104dSAndroid Build Coastguard Worker #include <fcntl.h>
35*7304104dSAndroid Build Coastguard Worker #include "system.h"
36*7304104dSAndroid Build Coastguard Worker
37*7304104dSAndroid Build Coastguard Worker #include "memory-access.h"
38*7304104dSAndroid Build Coastguard Worker
39*7304104dSAndroid Build Coastguard Worker struct core_arg
40*7304104dSAndroid Build Coastguard Worker {
41*7304104dSAndroid Build Coastguard Worker Elf *core;
42*7304104dSAndroid Build Coastguard Worker Elf_Data *note_data;
43*7304104dSAndroid Build Coastguard Worker size_t thread_note_offset;
44*7304104dSAndroid Build Coastguard Worker Ebl *ebl;
45*7304104dSAndroid Build Coastguard Worker };
46*7304104dSAndroid Build Coastguard Worker
47*7304104dSAndroid Build Coastguard Worker struct thread_arg
48*7304104dSAndroid Build Coastguard Worker {
49*7304104dSAndroid Build Coastguard Worker struct core_arg *core_arg;
50*7304104dSAndroid Build Coastguard Worker size_t note_offset;
51*7304104dSAndroid Build Coastguard Worker };
52*7304104dSAndroid Build Coastguard Worker
53*7304104dSAndroid Build Coastguard Worker static bool
core_memory_read(Dwfl * dwfl,Dwarf_Addr addr,Dwarf_Word * result,void * dwfl_arg)54*7304104dSAndroid Build Coastguard Worker core_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result,
55*7304104dSAndroid Build Coastguard Worker void *dwfl_arg)
56*7304104dSAndroid Build Coastguard Worker {
57*7304104dSAndroid Build Coastguard Worker Dwfl_Process *process = dwfl->process;
58*7304104dSAndroid Build Coastguard Worker struct core_arg *core_arg = dwfl_arg;
59*7304104dSAndroid Build Coastguard Worker Elf *core = core_arg->core;
60*7304104dSAndroid Build Coastguard Worker assert (core != NULL);
61*7304104dSAndroid Build Coastguard Worker static size_t phnum;
62*7304104dSAndroid Build Coastguard Worker if (elf_getphdrnum (core, &phnum) < 0)
63*7304104dSAndroid Build Coastguard Worker {
64*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_LIBELF);
65*7304104dSAndroid Build Coastguard Worker return false;
66*7304104dSAndroid Build Coastguard Worker }
67*7304104dSAndroid Build Coastguard Worker for (size_t cnt = 0; cnt < phnum; ++cnt)
68*7304104dSAndroid Build Coastguard Worker {
69*7304104dSAndroid Build Coastguard Worker GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
70*7304104dSAndroid Build Coastguard Worker if (phdr == NULL || phdr->p_type != PT_LOAD)
71*7304104dSAndroid Build Coastguard Worker continue;
72*7304104dSAndroid Build Coastguard Worker /* Bias is zero here, a core file itself has no bias. */
73*7304104dSAndroid Build Coastguard Worker GElf_Addr start = __libdwfl_segment_start (dwfl, phdr->p_vaddr);
74*7304104dSAndroid Build Coastguard Worker GElf_Addr end = __libdwfl_segment_end (dwfl,
75*7304104dSAndroid Build Coastguard Worker phdr->p_vaddr + phdr->p_memsz);
76*7304104dSAndroid Build Coastguard Worker unsigned bytes = ebl_get_elfclass (process->ebl) == ELFCLASS64 ? 8 : 4;
77*7304104dSAndroid Build Coastguard Worker if (addr < start || addr + bytes > end)
78*7304104dSAndroid Build Coastguard Worker continue;
79*7304104dSAndroid Build Coastguard Worker Elf_Data *data;
80*7304104dSAndroid Build Coastguard Worker data = elf_getdata_rawchunk (core, phdr->p_offset + addr - start,
81*7304104dSAndroid Build Coastguard Worker bytes, ELF_T_ADDR);
82*7304104dSAndroid Build Coastguard Worker if (data == NULL)
83*7304104dSAndroid Build Coastguard Worker {
84*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_LIBELF);
85*7304104dSAndroid Build Coastguard Worker return false;
86*7304104dSAndroid Build Coastguard Worker }
87*7304104dSAndroid Build Coastguard Worker assert (data->d_size == bytes);
88*7304104dSAndroid Build Coastguard Worker if (bytes == 8)
89*7304104dSAndroid Build Coastguard Worker *result = read_8ubyte_unaligned_noncvt (data->d_buf);
90*7304104dSAndroid Build Coastguard Worker else
91*7304104dSAndroid Build Coastguard Worker *result = read_4ubyte_unaligned_noncvt (data->d_buf);
92*7304104dSAndroid Build Coastguard Worker return true;
93*7304104dSAndroid Build Coastguard Worker }
94*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_ADDR_OUTOFRANGE);
95*7304104dSAndroid Build Coastguard Worker return false;
96*7304104dSAndroid Build Coastguard Worker }
97*7304104dSAndroid Build Coastguard Worker
98*7304104dSAndroid Build Coastguard Worker static pid_t
core_next_thread(Dwfl * dwfl,void * dwfl_arg,void ** thread_argp)99*7304104dSAndroid Build Coastguard Worker core_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg,
100*7304104dSAndroid Build Coastguard Worker void **thread_argp)
101*7304104dSAndroid Build Coastguard Worker {
102*7304104dSAndroid Build Coastguard Worker struct core_arg *core_arg = dwfl_arg;
103*7304104dSAndroid Build Coastguard Worker Elf *core = core_arg->core;
104*7304104dSAndroid Build Coastguard Worker GElf_Nhdr nhdr;
105*7304104dSAndroid Build Coastguard Worker size_t name_offset;
106*7304104dSAndroid Build Coastguard Worker size_t desc_offset;
107*7304104dSAndroid Build Coastguard Worker Elf_Data *note_data = core_arg->note_data;
108*7304104dSAndroid Build Coastguard Worker size_t offset;
109*7304104dSAndroid Build Coastguard Worker
110*7304104dSAndroid Build Coastguard Worker struct thread_arg *thread_arg;
111*7304104dSAndroid Build Coastguard Worker if (*thread_argp == NULL)
112*7304104dSAndroid Build Coastguard Worker {
113*7304104dSAndroid Build Coastguard Worker core_arg->thread_note_offset = 0;
114*7304104dSAndroid Build Coastguard Worker thread_arg = malloc (sizeof (*thread_arg));
115*7304104dSAndroid Build Coastguard Worker if (thread_arg == NULL)
116*7304104dSAndroid Build Coastguard Worker {
117*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_NOMEM);
118*7304104dSAndroid Build Coastguard Worker return -1;
119*7304104dSAndroid Build Coastguard Worker }
120*7304104dSAndroid Build Coastguard Worker thread_arg->core_arg = core_arg;
121*7304104dSAndroid Build Coastguard Worker *thread_argp = thread_arg;
122*7304104dSAndroid Build Coastguard Worker }
123*7304104dSAndroid Build Coastguard Worker else
124*7304104dSAndroid Build Coastguard Worker thread_arg = (struct thread_arg *) *thread_argp;
125*7304104dSAndroid Build Coastguard Worker
126*7304104dSAndroid Build Coastguard Worker while (offset = core_arg->thread_note_offset, offset < note_data->d_size
127*7304104dSAndroid Build Coastguard Worker && (core_arg->thread_note_offset = gelf_getnote (note_data, offset,
128*7304104dSAndroid Build Coastguard Worker &nhdr, &name_offset,
129*7304104dSAndroid Build Coastguard Worker &desc_offset)) > 0)
130*7304104dSAndroid Build Coastguard Worker {
131*7304104dSAndroid Build Coastguard Worker /* Do not check NAME for now, help broken Linux kernels. */
132*7304104dSAndroid Build Coastguard Worker const char *name = (nhdr.n_namesz == 0
133*7304104dSAndroid Build Coastguard Worker ? "" : note_data->d_buf + name_offset);
134*7304104dSAndroid Build Coastguard Worker const char *desc = note_data->d_buf + desc_offset;
135*7304104dSAndroid Build Coastguard Worker GElf_Word regs_offset;
136*7304104dSAndroid Build Coastguard Worker size_t nregloc;
137*7304104dSAndroid Build Coastguard Worker const Ebl_Register_Location *reglocs;
138*7304104dSAndroid Build Coastguard Worker size_t nitems;
139*7304104dSAndroid Build Coastguard Worker const Ebl_Core_Item *items;
140*7304104dSAndroid Build Coastguard Worker if (! ebl_core_note (core_arg->ebl, &nhdr, name, desc,
141*7304104dSAndroid Build Coastguard Worker ®s_offset, &nregloc, ®locs, &nitems, &items))
142*7304104dSAndroid Build Coastguard Worker {
143*7304104dSAndroid Build Coastguard Worker /* This note may be just not recognized, skip it. */
144*7304104dSAndroid Build Coastguard Worker continue;
145*7304104dSAndroid Build Coastguard Worker }
146*7304104dSAndroid Build Coastguard Worker if (nhdr.n_type != NT_PRSTATUS)
147*7304104dSAndroid Build Coastguard Worker continue;
148*7304104dSAndroid Build Coastguard Worker const Ebl_Core_Item *item;
149*7304104dSAndroid Build Coastguard Worker for (item = items; item < items + nitems; item++)
150*7304104dSAndroid Build Coastguard Worker if (strcmp (item->name, "pid") == 0)
151*7304104dSAndroid Build Coastguard Worker break;
152*7304104dSAndroid Build Coastguard Worker if (item == items + nitems)
153*7304104dSAndroid Build Coastguard Worker continue;
154*7304104dSAndroid Build Coastguard Worker uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
155*7304104dSAndroid Build Coastguard Worker val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
156*7304104dSAndroid Build Coastguard Worker ? be32toh (val32) : le32toh (val32));
157*7304104dSAndroid Build Coastguard Worker pid_t tid = (int32_t) val32;
158*7304104dSAndroid Build Coastguard Worker eu_static_assert (sizeof val32 <= sizeof tid);
159*7304104dSAndroid Build Coastguard Worker thread_arg->note_offset = offset;
160*7304104dSAndroid Build Coastguard Worker return tid;
161*7304104dSAndroid Build Coastguard Worker }
162*7304104dSAndroid Build Coastguard Worker
163*7304104dSAndroid Build Coastguard Worker free (thread_arg);
164*7304104dSAndroid Build Coastguard Worker return 0;
165*7304104dSAndroid Build Coastguard Worker }
166*7304104dSAndroid Build Coastguard Worker
167*7304104dSAndroid Build Coastguard Worker static bool
core_set_initial_registers(Dwfl_Thread * thread,void * thread_arg_voidp)168*7304104dSAndroid Build Coastguard Worker core_set_initial_registers (Dwfl_Thread *thread, void *thread_arg_voidp)
169*7304104dSAndroid Build Coastguard Worker {
170*7304104dSAndroid Build Coastguard Worker struct thread_arg *thread_arg = thread_arg_voidp;
171*7304104dSAndroid Build Coastguard Worker struct core_arg *core_arg = thread_arg->core_arg;
172*7304104dSAndroid Build Coastguard Worker Elf *core = core_arg->core;
173*7304104dSAndroid Build Coastguard Worker size_t offset = thread_arg->note_offset;
174*7304104dSAndroid Build Coastguard Worker GElf_Nhdr nhdr;
175*7304104dSAndroid Build Coastguard Worker size_t name_offset;
176*7304104dSAndroid Build Coastguard Worker size_t desc_offset;
177*7304104dSAndroid Build Coastguard Worker Elf_Data *note_data = core_arg->note_data;
178*7304104dSAndroid Build Coastguard Worker size_t nregs = ebl_frame_nregs (core_arg->ebl);
179*7304104dSAndroid Build Coastguard Worker assert (nregs > 0);
180*7304104dSAndroid Build Coastguard Worker assert (offset < note_data->d_size);
181*7304104dSAndroid Build Coastguard Worker size_t getnote_err = gelf_getnote (note_data, offset, &nhdr, &name_offset,
182*7304104dSAndroid Build Coastguard Worker &desc_offset);
183*7304104dSAndroid Build Coastguard Worker /* __libdwfl_attach_state_for_core already verified the note is there. */
184*7304104dSAndroid Build Coastguard Worker if (getnote_err == 0)
185*7304104dSAndroid Build Coastguard Worker return false;
186*7304104dSAndroid Build Coastguard Worker /* Do not check NAME for now, help broken Linux kernels. */
187*7304104dSAndroid Build Coastguard Worker const char *name = (nhdr.n_namesz == 0
188*7304104dSAndroid Build Coastguard Worker ? "" : note_data->d_buf + name_offset);
189*7304104dSAndroid Build Coastguard Worker const char *desc = note_data->d_buf + desc_offset;
190*7304104dSAndroid Build Coastguard Worker GElf_Word regs_offset;
191*7304104dSAndroid Build Coastguard Worker size_t nregloc;
192*7304104dSAndroid Build Coastguard Worker const Ebl_Register_Location *reglocs;
193*7304104dSAndroid Build Coastguard Worker size_t nitems;
194*7304104dSAndroid Build Coastguard Worker const Ebl_Core_Item *items;
195*7304104dSAndroid Build Coastguard Worker int core_note_err = ebl_core_note (core_arg->ebl, &nhdr, name, desc,
196*7304104dSAndroid Build Coastguard Worker ®s_offset, &nregloc, ®locs,
197*7304104dSAndroid Build Coastguard Worker &nitems, &items);
198*7304104dSAndroid Build Coastguard Worker /* __libdwfl_attach_state_for_core already verified the note is there. */
199*7304104dSAndroid Build Coastguard Worker if (core_note_err == 0 || nhdr.n_type != NT_PRSTATUS)
200*7304104dSAndroid Build Coastguard Worker return false;
201*7304104dSAndroid Build Coastguard Worker const Ebl_Core_Item *item;
202*7304104dSAndroid Build Coastguard Worker for (item = items; item < items + nitems; item++)
203*7304104dSAndroid Build Coastguard Worker if (strcmp (item->name, "pid") == 0)
204*7304104dSAndroid Build Coastguard Worker break;
205*7304104dSAndroid Build Coastguard Worker assert (item < items + nitems);
206*7304104dSAndroid Build Coastguard Worker pid_t tid;
207*7304104dSAndroid Build Coastguard Worker {
208*7304104dSAndroid Build Coastguard Worker uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
209*7304104dSAndroid Build Coastguard Worker val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
210*7304104dSAndroid Build Coastguard Worker ? be32toh (val32) : le32toh (val32));
211*7304104dSAndroid Build Coastguard Worker tid = (int32_t) val32;
212*7304104dSAndroid Build Coastguard Worker eu_static_assert (sizeof val32 <= sizeof tid);
213*7304104dSAndroid Build Coastguard Worker }
214*7304104dSAndroid Build Coastguard Worker /* core_next_thread already found this TID there. */
215*7304104dSAndroid Build Coastguard Worker assert (tid == INTUSE(dwfl_thread_tid) (thread));
216*7304104dSAndroid Build Coastguard Worker for (item = items; item < items + nitems; item++)
217*7304104dSAndroid Build Coastguard Worker if (item->pc_register)
218*7304104dSAndroid Build Coastguard Worker break;
219*7304104dSAndroid Build Coastguard Worker if (item < items + nitems)
220*7304104dSAndroid Build Coastguard Worker {
221*7304104dSAndroid Build Coastguard Worker Dwarf_Word pc;
222*7304104dSAndroid Build Coastguard Worker switch (gelf_getclass (core) == ELFCLASS32 ? 32 : 64)
223*7304104dSAndroid Build Coastguard Worker {
224*7304104dSAndroid Build Coastguard Worker case 32:;
225*7304104dSAndroid Build Coastguard Worker uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
226*7304104dSAndroid Build Coastguard Worker val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
227*7304104dSAndroid Build Coastguard Worker ? be32toh (val32) : le32toh (val32));
228*7304104dSAndroid Build Coastguard Worker /* Do a host width conversion. */
229*7304104dSAndroid Build Coastguard Worker pc = val32;
230*7304104dSAndroid Build Coastguard Worker break;
231*7304104dSAndroid Build Coastguard Worker case 64:;
232*7304104dSAndroid Build Coastguard Worker uint64_t val64 = read_8ubyte_unaligned_noncvt (desc + item->offset);
233*7304104dSAndroid Build Coastguard Worker val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
234*7304104dSAndroid Build Coastguard Worker ? be64toh (val64) : le64toh (val64));
235*7304104dSAndroid Build Coastguard Worker pc = val64;
236*7304104dSAndroid Build Coastguard Worker break;
237*7304104dSAndroid Build Coastguard Worker default:
238*7304104dSAndroid Build Coastguard Worker abort ();
239*7304104dSAndroid Build Coastguard Worker }
240*7304104dSAndroid Build Coastguard Worker INTUSE(dwfl_thread_state_register_pc) (thread, pc);
241*7304104dSAndroid Build Coastguard Worker }
242*7304104dSAndroid Build Coastguard Worker desc += regs_offset;
243*7304104dSAndroid Build Coastguard Worker for (size_t regloci = 0; regloci < nregloc; regloci++)
244*7304104dSAndroid Build Coastguard Worker {
245*7304104dSAndroid Build Coastguard Worker const Ebl_Register_Location *regloc = reglocs + regloci;
246*7304104dSAndroid Build Coastguard Worker // Iterate even regs out of NREGS range so that we can find pc_register.
247*7304104dSAndroid Build Coastguard Worker if (regloc->bits != 32 && regloc->bits != 64)
248*7304104dSAndroid Build Coastguard Worker continue;
249*7304104dSAndroid Build Coastguard Worker const char *reg_desc = desc + regloc->offset;
250*7304104dSAndroid Build Coastguard Worker for (unsigned regno = regloc->regno;
251*7304104dSAndroid Build Coastguard Worker regno < regloc->regno + (regloc->count ?: 1U);
252*7304104dSAndroid Build Coastguard Worker regno++)
253*7304104dSAndroid Build Coastguard Worker {
254*7304104dSAndroid Build Coastguard Worker /* PPC provides DWARF register 65 irrelevant for
255*7304104dSAndroid Build Coastguard Worker CFI which clashes with register 108 (LR) we need.
256*7304104dSAndroid Build Coastguard Worker LR (108) is provided earlier (in NT_PRSTATUS) than the # 65.
257*7304104dSAndroid Build Coastguard Worker FIXME: It depends now on their order in core notes.
258*7304104dSAndroid Build Coastguard Worker FIXME: It uses private function. */
259*7304104dSAndroid Build Coastguard Worker if (regno < nregs
260*7304104dSAndroid Build Coastguard Worker && __libdwfl_frame_reg_get (thread->unwound, regno, NULL) == 0)
261*7304104dSAndroid Build Coastguard Worker continue;
262*7304104dSAndroid Build Coastguard Worker Dwarf_Word val;
263*7304104dSAndroid Build Coastguard Worker switch (regloc->bits)
264*7304104dSAndroid Build Coastguard Worker {
265*7304104dSAndroid Build Coastguard Worker case 32:;
266*7304104dSAndroid Build Coastguard Worker uint32_t val32 = read_4ubyte_unaligned_noncvt (reg_desc);
267*7304104dSAndroid Build Coastguard Worker reg_desc += sizeof val32;
268*7304104dSAndroid Build Coastguard Worker val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
269*7304104dSAndroid Build Coastguard Worker ? be32toh (val32) : le32toh (val32));
270*7304104dSAndroid Build Coastguard Worker /* Do a host width conversion. */
271*7304104dSAndroid Build Coastguard Worker val = val32;
272*7304104dSAndroid Build Coastguard Worker break;
273*7304104dSAndroid Build Coastguard Worker case 64:;
274*7304104dSAndroid Build Coastguard Worker uint64_t val64 = read_8ubyte_unaligned_noncvt (reg_desc);
275*7304104dSAndroid Build Coastguard Worker reg_desc += sizeof val64;
276*7304104dSAndroid Build Coastguard Worker val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
277*7304104dSAndroid Build Coastguard Worker ? be64toh (val64) : le64toh (val64));
278*7304104dSAndroid Build Coastguard Worker assert (sizeof (*thread->unwound->regs) == sizeof val64);
279*7304104dSAndroid Build Coastguard Worker val = val64;
280*7304104dSAndroid Build Coastguard Worker break;
281*7304104dSAndroid Build Coastguard Worker default:
282*7304104dSAndroid Build Coastguard Worker abort ();
283*7304104dSAndroid Build Coastguard Worker }
284*7304104dSAndroid Build Coastguard Worker /* Registers not valid for CFI are just ignored. */
285*7304104dSAndroid Build Coastguard Worker if (regno < nregs)
286*7304104dSAndroid Build Coastguard Worker INTUSE(dwfl_thread_state_registers) (thread, regno, 1, &val);
287*7304104dSAndroid Build Coastguard Worker if (regloc->pc_register)
288*7304104dSAndroid Build Coastguard Worker INTUSE(dwfl_thread_state_register_pc) (thread, val);
289*7304104dSAndroid Build Coastguard Worker reg_desc += regloc->pad;
290*7304104dSAndroid Build Coastguard Worker }
291*7304104dSAndroid Build Coastguard Worker }
292*7304104dSAndroid Build Coastguard Worker return true;
293*7304104dSAndroid Build Coastguard Worker }
294*7304104dSAndroid Build Coastguard Worker
295*7304104dSAndroid Build Coastguard Worker static void
core_detach(Dwfl * dwfl,void * dwfl_arg)296*7304104dSAndroid Build Coastguard Worker core_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg)
297*7304104dSAndroid Build Coastguard Worker {
298*7304104dSAndroid Build Coastguard Worker struct core_arg *core_arg = dwfl_arg;
299*7304104dSAndroid Build Coastguard Worker ebl_closebackend (core_arg->ebl);
300*7304104dSAndroid Build Coastguard Worker free (core_arg);
301*7304104dSAndroid Build Coastguard Worker }
302*7304104dSAndroid Build Coastguard Worker
303*7304104dSAndroid Build Coastguard Worker static const Dwfl_Thread_Callbacks core_thread_callbacks =
304*7304104dSAndroid Build Coastguard Worker {
305*7304104dSAndroid Build Coastguard Worker core_next_thread,
306*7304104dSAndroid Build Coastguard Worker NULL, /* get_thread */
307*7304104dSAndroid Build Coastguard Worker core_memory_read,
308*7304104dSAndroid Build Coastguard Worker core_set_initial_registers,
309*7304104dSAndroid Build Coastguard Worker core_detach,
310*7304104dSAndroid Build Coastguard Worker NULL, /* core_thread_detach */
311*7304104dSAndroid Build Coastguard Worker };
312*7304104dSAndroid Build Coastguard Worker
313*7304104dSAndroid Build Coastguard Worker int
dwfl_core_file_attach(Dwfl * dwfl,Elf * core)314*7304104dSAndroid Build Coastguard Worker dwfl_core_file_attach (Dwfl *dwfl, Elf *core)
315*7304104dSAndroid Build Coastguard Worker {
316*7304104dSAndroid Build Coastguard Worker Dwfl_Error err = DWFL_E_NOERROR;
317*7304104dSAndroid Build Coastguard Worker Ebl *ebl = ebl_openbackend (core);
318*7304104dSAndroid Build Coastguard Worker if (ebl == NULL)
319*7304104dSAndroid Build Coastguard Worker {
320*7304104dSAndroid Build Coastguard Worker err = DWFL_E_LIBEBL;
321*7304104dSAndroid Build Coastguard Worker fail_err:
322*7304104dSAndroid Build Coastguard Worker if (dwfl->process == NULL && dwfl->attacherr == DWFL_E_NOERROR)
323*7304104dSAndroid Build Coastguard Worker dwfl->attacherr = __libdwfl_canon_error (err);
324*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (err);
325*7304104dSAndroid Build Coastguard Worker return -1;
326*7304104dSAndroid Build Coastguard Worker }
327*7304104dSAndroid Build Coastguard Worker size_t nregs = ebl_frame_nregs (ebl);
328*7304104dSAndroid Build Coastguard Worker if (nregs == 0)
329*7304104dSAndroid Build Coastguard Worker {
330*7304104dSAndroid Build Coastguard Worker err = DWFL_E_NO_UNWIND;
331*7304104dSAndroid Build Coastguard Worker fail:
332*7304104dSAndroid Build Coastguard Worker ebl_closebackend (ebl);
333*7304104dSAndroid Build Coastguard Worker goto fail_err;
334*7304104dSAndroid Build Coastguard Worker }
335*7304104dSAndroid Build Coastguard Worker GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (core, &ehdr_mem);
336*7304104dSAndroid Build Coastguard Worker if (ehdr == NULL)
337*7304104dSAndroid Build Coastguard Worker {
338*7304104dSAndroid Build Coastguard Worker err = DWFL_E_LIBELF;
339*7304104dSAndroid Build Coastguard Worker goto fail;
340*7304104dSAndroid Build Coastguard Worker }
341*7304104dSAndroid Build Coastguard Worker if (ehdr->e_type != ET_CORE)
342*7304104dSAndroid Build Coastguard Worker {
343*7304104dSAndroid Build Coastguard Worker err = DWFL_E_NO_CORE_FILE;
344*7304104dSAndroid Build Coastguard Worker goto fail;
345*7304104dSAndroid Build Coastguard Worker }
346*7304104dSAndroid Build Coastguard Worker size_t phnum;
347*7304104dSAndroid Build Coastguard Worker if (elf_getphdrnum (core, &phnum) < 0)
348*7304104dSAndroid Build Coastguard Worker {
349*7304104dSAndroid Build Coastguard Worker err = DWFL_E_LIBELF;
350*7304104dSAndroid Build Coastguard Worker goto fail;
351*7304104dSAndroid Build Coastguard Worker }
352*7304104dSAndroid Build Coastguard Worker pid_t pid = -1;
353*7304104dSAndroid Build Coastguard Worker Elf_Data *note_data = NULL;
354*7304104dSAndroid Build Coastguard Worker for (size_t cnt = 0; cnt < phnum; ++cnt)
355*7304104dSAndroid Build Coastguard Worker {
356*7304104dSAndroid Build Coastguard Worker GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
357*7304104dSAndroid Build Coastguard Worker if (phdr != NULL && phdr->p_type == PT_NOTE)
358*7304104dSAndroid Build Coastguard Worker {
359*7304104dSAndroid Build Coastguard Worker note_data = elf_getdata_rawchunk (core, phdr->p_offset,
360*7304104dSAndroid Build Coastguard Worker phdr->p_filesz, (phdr->p_align == 8
361*7304104dSAndroid Build Coastguard Worker ? ELF_T_NHDR8
362*7304104dSAndroid Build Coastguard Worker : ELF_T_NHDR));
363*7304104dSAndroid Build Coastguard Worker break;
364*7304104dSAndroid Build Coastguard Worker }
365*7304104dSAndroid Build Coastguard Worker }
366*7304104dSAndroid Build Coastguard Worker if (note_data == NULL)
367*7304104dSAndroid Build Coastguard Worker {
368*7304104dSAndroid Build Coastguard Worker err = DWFL_E_LIBELF;
369*7304104dSAndroid Build Coastguard Worker goto fail;
370*7304104dSAndroid Build Coastguard Worker }
371*7304104dSAndroid Build Coastguard Worker size_t offset = 0;
372*7304104dSAndroid Build Coastguard Worker GElf_Nhdr nhdr;
373*7304104dSAndroid Build Coastguard Worker size_t name_offset;
374*7304104dSAndroid Build Coastguard Worker size_t desc_offset;
375*7304104dSAndroid Build Coastguard Worker while (offset < note_data->d_size
376*7304104dSAndroid Build Coastguard Worker && (offset = gelf_getnote (note_data, offset,
377*7304104dSAndroid Build Coastguard Worker &nhdr, &name_offset, &desc_offset)) > 0)
378*7304104dSAndroid Build Coastguard Worker {
379*7304104dSAndroid Build Coastguard Worker /* Do not check NAME for now, help broken Linux kernels. */
380*7304104dSAndroid Build Coastguard Worker const char *name = (nhdr.n_namesz == 0
381*7304104dSAndroid Build Coastguard Worker ? "" : note_data->d_buf + name_offset);
382*7304104dSAndroid Build Coastguard Worker const char *desc = note_data->d_buf + desc_offset;
383*7304104dSAndroid Build Coastguard Worker GElf_Word regs_offset;
384*7304104dSAndroid Build Coastguard Worker size_t nregloc;
385*7304104dSAndroid Build Coastguard Worker const Ebl_Register_Location *reglocs;
386*7304104dSAndroid Build Coastguard Worker size_t nitems;
387*7304104dSAndroid Build Coastguard Worker const Ebl_Core_Item *items;
388*7304104dSAndroid Build Coastguard Worker if (! ebl_core_note (ebl, &nhdr, name, desc,
389*7304104dSAndroid Build Coastguard Worker ®s_offset, &nregloc, ®locs, &nitems, &items))
390*7304104dSAndroid Build Coastguard Worker {
391*7304104dSAndroid Build Coastguard Worker /* This note may be just not recognized, skip it. */
392*7304104dSAndroid Build Coastguard Worker continue;
393*7304104dSAndroid Build Coastguard Worker }
394*7304104dSAndroid Build Coastguard Worker if (nhdr.n_type != NT_PRPSINFO)
395*7304104dSAndroid Build Coastguard Worker continue;
396*7304104dSAndroid Build Coastguard Worker const Ebl_Core_Item *item;
397*7304104dSAndroid Build Coastguard Worker for (item = items; item < items + nitems; item++)
398*7304104dSAndroid Build Coastguard Worker if (strcmp (item->name, "pid") == 0)
399*7304104dSAndroid Build Coastguard Worker break;
400*7304104dSAndroid Build Coastguard Worker if (item == items + nitems)
401*7304104dSAndroid Build Coastguard Worker continue;
402*7304104dSAndroid Build Coastguard Worker uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
403*7304104dSAndroid Build Coastguard Worker val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
404*7304104dSAndroid Build Coastguard Worker ? be32toh (val32) : le32toh (val32));
405*7304104dSAndroid Build Coastguard Worker pid = (int32_t) val32;
406*7304104dSAndroid Build Coastguard Worker eu_static_assert (sizeof val32 <= sizeof pid);
407*7304104dSAndroid Build Coastguard Worker break;
408*7304104dSAndroid Build Coastguard Worker }
409*7304104dSAndroid Build Coastguard Worker if (pid == -1)
410*7304104dSAndroid Build Coastguard Worker {
411*7304104dSAndroid Build Coastguard Worker /* No valid NT_PRPSINFO recognized in this CORE. */
412*7304104dSAndroid Build Coastguard Worker err = DWFL_E_BADELF;
413*7304104dSAndroid Build Coastguard Worker goto fail;
414*7304104dSAndroid Build Coastguard Worker }
415*7304104dSAndroid Build Coastguard Worker struct core_arg *core_arg = malloc (sizeof *core_arg);
416*7304104dSAndroid Build Coastguard Worker if (core_arg == NULL)
417*7304104dSAndroid Build Coastguard Worker {
418*7304104dSAndroid Build Coastguard Worker err = DWFL_E_NOMEM;
419*7304104dSAndroid Build Coastguard Worker goto fail;
420*7304104dSAndroid Build Coastguard Worker }
421*7304104dSAndroid Build Coastguard Worker core_arg->core = core;
422*7304104dSAndroid Build Coastguard Worker core_arg->note_data = note_data;
423*7304104dSAndroid Build Coastguard Worker core_arg->thread_note_offset = 0;
424*7304104dSAndroid Build Coastguard Worker core_arg->ebl = ebl;
425*7304104dSAndroid Build Coastguard Worker if (! INTUSE(dwfl_attach_state) (dwfl, core, pid, &core_thread_callbacks,
426*7304104dSAndroid Build Coastguard Worker core_arg))
427*7304104dSAndroid Build Coastguard Worker {
428*7304104dSAndroid Build Coastguard Worker free (core_arg);
429*7304104dSAndroid Build Coastguard Worker ebl_closebackend (ebl);
430*7304104dSAndroid Build Coastguard Worker return -1;
431*7304104dSAndroid Build Coastguard Worker }
432*7304104dSAndroid Build Coastguard Worker return pid;
433*7304104dSAndroid Build Coastguard Worker }
434*7304104dSAndroid Build Coastguard Worker INTDEF (dwfl_core_file_attach)
435