Branch data Line data Source code
1 : : /* Get Dwarf Frame state for target core file.
2 : : Copyright (C) 2013, 2014 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : :
5 : : This file is free software; you can redistribute it and/or modify
6 : : it under the terms of either
7 : :
8 : : * the GNU Lesser General Public License as published by the Free
9 : : Software Foundation; either version 3 of the License, or (at
10 : : your option) any later version
11 : :
12 : : or
13 : :
14 : : * the GNU General Public License as published by the Free
15 : : Software Foundation; either version 2 of the License, or (at
16 : : your option) any later version
17 : :
18 : : or both in parallel, as here.
19 : :
20 : : elfutils is distributed in the hope that it will be useful, but
21 : : WITHOUT ANY WARRANTY; without even the implied warranty of
22 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 : : General Public License for more details.
24 : :
25 : : You should have received copies of the GNU General Public License and
26 : : the GNU Lesser General Public License along with this program. If
27 : : not, see <http://www.gnu.org/licenses/>. */
28 : :
29 : : #ifdef HAVE_CONFIG_H
30 : : # include <config.h>
31 : : #endif
32 : :
33 : : #include "libdwflP.h"
34 : : #include <fcntl.h>
35 : : #include "system.h"
36 : :
37 : : #include "memory-access.h"
38 : :
39 : : struct core_arg
40 : : {
41 : : Elf *core;
42 : : Elf_Data *note_data;
43 : : size_t thread_note_offset;
44 : : Ebl *ebl;
45 : : };
46 : :
47 : : struct thread_arg
48 : : {
49 : : struct core_arg *core_arg;
50 : : size_t note_offset;
51 : : };
52 : :
53 : : static bool
54 : 1190 : core_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result,
55 : : void *dwfl_arg)
56 : : {
57 : 1190 : Dwfl_Process *process = dwfl->process;
58 : 1190 : struct core_arg *core_arg = dwfl_arg;
59 : 1190 : Elf *core = core_arg->core;
60 [ - + ]: 1190 : assert (core != NULL);
61 : 1190 : static size_t phnum;
62 [ - + ]: 1190 : if (elf_getphdrnum (core, &phnum) < 0)
63 : : {
64 : 0 : __libdwfl_seterrno (DWFL_E_LIBELF);
65 : 0 : return false;
66 : : }
67 [ + + ]: 14400 : for (size_t cnt = 0; cnt < phnum; ++cnt)
68 : : {
69 : 14376 : GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
70 [ + - + + ]: 14376 : if (phdr == NULL || phdr->p_type != PT_LOAD)
71 : 13210 : continue;
72 : : /* Bias is zero here, a core file itself has no bias. */
73 : 13186 : GElf_Addr start = __libdwfl_segment_start (dwfl, phdr->p_vaddr);
74 : 26372 : GElf_Addr end = __libdwfl_segment_end (dwfl,
75 : 13186 : phdr->p_vaddr + phdr->p_memsz);
76 [ + + ]: 13186 : unsigned bytes = ebl_get_elfclass (process->ebl) == ELFCLASS64 ? 8 : 4;
77 [ + + + + ]: 13186 : if (addr < start || addr + bytes > end)
78 : 12020 : continue;
79 : 1166 : Elf_Data *data;
80 : 1166 : data = elf_getdata_rawchunk (core, phdr->p_offset + addr - start,
81 : : bytes, ELF_T_ADDR);
82 [ - + ]: 1166 : if (data == NULL)
83 : : {
84 : 0 : __libdwfl_seterrno (DWFL_E_LIBELF);
85 : 1166 : return false;
86 : : }
87 [ - + ]: 1166 : assert (data->d_size == bytes);
88 [ + + ]: 1166 : if (bytes == 8)
89 : 822 : *result = read_8ubyte_unaligned_noncvt (data->d_buf);
90 : : else
91 : 344 : *result = read_4ubyte_unaligned_noncvt (data->d_buf);
92 : : return true;
93 : : }
94 : 24 : __libdwfl_seterrno (DWFL_E_ADDR_OUTOFRANGE);
95 : 24 : return false;
96 : : }
97 : :
98 : : static pid_t
99 : 128 : core_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg,
100 : : void **thread_argp)
101 : : {
102 : 128 : struct core_arg *core_arg = dwfl_arg;
103 : 128 : Elf *core = core_arg->core;
104 : 128 : GElf_Nhdr nhdr;
105 : 128 : size_t name_offset;
106 : 128 : size_t desc_offset;
107 : 128 : Elf_Data *note_data = core_arg->note_data;
108 : 128 : size_t offset;
109 : :
110 : 128 : struct thread_arg *thread_arg;
111 [ + + ]: 128 : if (*thread_argp == NULL)
112 : : {
113 : 52 : core_arg->thread_note_offset = 0;
114 : 52 : thread_arg = malloc (sizeof (*thread_arg));
115 [ - + ]: 52 : if (thread_arg == NULL)
116 : : {
117 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
118 : 0 : return -1;
119 : : }
120 : 52 : thread_arg->core_arg = core_arg;
121 : 52 : *thread_argp = thread_arg;
122 : : }
123 : : else
124 : 128 : thread_arg = (struct thread_arg *) *thread_argp;
125 : :
126 : 454 : while (offset = core_arg->thread_note_offset, offset < note_data->d_size
127 [ + + + - ]: 454 : && (core_arg->thread_note_offset = gelf_getnote (note_data, offset,
128 : : &nhdr, &name_offset,
129 : : &desc_offset)) > 0)
130 : : {
131 : : /* Do not check NAME for now, help broken Linux kernels. */
132 : 804 : const char *name = (nhdr.n_namesz == 0
133 [ + - ]: 402 : ? "" : note_data->d_buf + name_offset);
134 : 402 : const char *desc = note_data->d_buf + desc_offset;
135 : 402 : GElf_Word regs_offset;
136 : 402 : size_t nregloc;
137 : 402 : const Ebl_Register_Location *reglocs;
138 : 402 : size_t nitems;
139 : 402 : const Ebl_Core_Item *items;
140 [ + + ]: 402 : if (! ebl_core_note (core_arg->ebl, &nhdr, name, desc,
141 : : ®s_offset, &nregloc, ®locs, &nitems, &items))
142 : : {
143 : : /* This note may be just not recognized, skip it. */
144 : 326 : continue;
145 : : }
146 [ + + ]: 240 : if (nhdr.n_type != NT_PRSTATUS)
147 : 164 : continue;
148 : 76 : const Ebl_Core_Item *item;
149 [ + - ]: 532 : for (item = items; item < items + nitems; item++)
150 [ + + ]: 532 : if (strcmp (item->name, "pid") == 0)
151 : : break;
152 [ - + ]: 76 : if (item == items + nitems)
153 : 0 : continue;
154 : 76 : uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
155 : 76 : val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
156 [ + + ]: 76 : ? be32toh (val32) : le32toh (val32));
157 : 76 : pid_t tid = (int32_t) val32;
158 : 76 : eu_static_assert (sizeof val32 <= sizeof tid);
159 : 76 : thread_arg->note_offset = offset;
160 : 76 : return tid;
161 : : }
162 : :
163 : 52 : free (thread_arg);
164 : 52 : return 0;
165 : : }
166 : :
167 : : static bool
168 : 76 : core_set_initial_registers (Dwfl_Thread *thread, void *thread_arg_voidp)
169 : : {
170 : 76 : struct thread_arg *thread_arg = thread_arg_voidp;
171 : 76 : struct core_arg *core_arg = thread_arg->core_arg;
172 : 76 : Elf *core = core_arg->core;
173 : 76 : size_t offset = thread_arg->note_offset;
174 : 76 : GElf_Nhdr nhdr;
175 : 76 : size_t name_offset;
176 : 76 : size_t desc_offset;
177 : 76 : Elf_Data *note_data = core_arg->note_data;
178 : 76 : size_t nregs = ebl_frame_nregs (core_arg->ebl);
179 [ - + ]: 76 : assert (nregs > 0);
180 [ - + ]: 76 : assert (offset < note_data->d_size);
181 : 76 : size_t getnote_err = gelf_getnote (note_data, offset, &nhdr, &name_offset,
182 : : &desc_offset);
183 : : /* __libdwfl_attach_state_for_core already verified the note is there. */
184 [ - + ]: 76 : if (getnote_err == 0)
185 : : return false;
186 : : /* Do not check NAME for now, help broken Linux kernels. */
187 : 152 : const char *name = (nhdr.n_namesz == 0
188 [ + - ]: 76 : ? "" : note_data->d_buf + name_offset);
189 : 76 : const char *desc = note_data->d_buf + desc_offset;
190 : 76 : GElf_Word regs_offset;
191 : 76 : size_t nregloc;
192 : 76 : const Ebl_Register_Location *reglocs;
193 : 76 : size_t nitems;
194 : 76 : const Ebl_Core_Item *items;
195 : 76 : int core_note_err = ebl_core_note (core_arg->ebl, &nhdr, name, desc,
196 : : ®s_offset, &nregloc, ®locs,
197 : : &nitems, &items);
198 : : /* __libdwfl_attach_state_for_core already verified the note is there. */
199 [ - + - + ]: 76 : if (core_note_err == 0 || nhdr.n_type != NT_PRSTATUS)
200 : : return false;
201 : 76 : const Ebl_Core_Item *item;
202 [ + - ]: 532 : for (item = items; item < items + nitems; item++)
203 [ + + ]: 532 : if (strcmp (item->name, "pid") == 0)
204 : : break;
205 [ - + ]: 76 : assert (item < items + nitems);
206 : 76 : pid_t tid;
207 : : {
208 : 76 : uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
209 : 76 : val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
210 [ + + ]: 76 : ? be32toh (val32) : le32toh (val32));
211 : 76 : tid = (int32_t) val32;
212 : 76 : eu_static_assert (sizeof val32 <= sizeof tid);
213 : : }
214 : : /* core_next_thread already found this TID there. */
215 [ - + ]: 76 : assert (tid == INTUSE(dwfl_thread_tid) (thread));
216 [ + + ]: 1248 : for (item = items; item < items + nitems; item++)
217 [ + + ]: 1194 : if (item->pc_register)
218 : : break;
219 [ + + ]: 76 : if (item < items + nitems)
220 : : {
221 : 22 : Dwarf_Word pc;
222 [ + + ]: 22 : switch (gelf_getclass (core) == ELFCLASS32 ? 32 : 64)
223 : : {
224 : 4 : case 32:;
225 : 4 : uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
226 : 4 : val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
227 [ + - ]: 4 : ? be32toh (val32) : le32toh (val32));
228 : : /* Do a host width conversion. */
229 : 4 : pc = val32;
230 : 4 : break;
231 : 18 : case 64:;
232 : 18 : uint64_t val64 = read_8ubyte_unaligned_noncvt (desc + item->offset);
233 : 18 : val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
234 [ + + ]: 18 : ? be64toh (val64) : le64toh (val64));
235 : : pc = val64;
236 : : break;
237 : : default:
238 : : abort ();
239 : : }
240 : 22 : INTUSE(dwfl_thread_state_register_pc) (thread, pc);
241 : : }
242 : 76 : desc += regs_offset;
243 [ + + ]: 1192 : for (size_t regloci = 0; regloci < nregloc; regloci++)
244 : : {
245 : 1116 : const Ebl_Register_Location *regloc = reglocs + regloci;
246 : : // Iterate even regs out of NREGS range so that we can find pc_register.
247 [ + + ]: 1116 : if (regloc->bits != 32 && regloc->bits != 64)
248 : 238 : continue;
249 : 878 : const char *reg_desc = desc + regloc->offset;
250 : 878 : for (unsigned regno = regloc->regno;
251 [ + + ]: 2774 : regno < regloc->regno + (regloc->count ?: 1U);
252 : 1896 : regno++)
253 : : {
254 : : /* PPC provides DWARF register 65 irrelevant for
255 : : CFI which clashes with register 108 (LR) we need.
256 : : LR (108) is provided earlier (in NT_PRSTATUS) than the # 65.
257 : : FIXME: It depends now on their order in core notes.
258 : : FIXME: It uses private function. */
259 [ + + ]: 1896 : if (regno < nregs
260 [ - + ]: 1630 : && __libdwfl_frame_reg_get (thread->unwound, regno, NULL) == 0)
261 : 0 : continue;
262 : 1896 : Dwarf_Word val;
263 [ + + - ]: 1896 : switch (regloc->bits)
264 : : {
265 : 440 : case 32:;
266 : 440 : uint32_t val32 = read_4ubyte_unaligned_noncvt (reg_desc);
267 : 440 : reg_desc += sizeof val32;
268 : 440 : val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
269 [ + + ]: 440 : ? be32toh (val32) : le32toh (val32));
270 : : /* Do a host width conversion. */
271 : 440 : val = val32;
272 : 440 : break;
273 : 1456 : case 64:;
274 : 1456 : uint64_t val64 = read_8ubyte_unaligned_noncvt (reg_desc);
275 : 1456 : reg_desc += sizeof val64;
276 : 1456 : val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
277 [ + + ]: 1456 : ? be64toh (val64) : le64toh (val64));
278 : 1456 : assert (sizeof (*thread->unwound->regs) == sizeof val64);
279 : 1456 : val = val64;
280 : 1456 : break;
281 : 0 : default:
282 : 0 : abort ();
283 : : }
284 : : /* Registers not valid for CFI are just ignored. */
285 [ + + ]: 1896 : if (regno < nregs)
286 : 1630 : INTUSE(dwfl_thread_state_registers) (thread, regno, 1, &val);
287 [ + + ]: 1896 : if (regloc->pc_register)
288 : 8 : INTUSE(dwfl_thread_state_register_pc) (thread, val);
289 : 1896 : reg_desc += regloc->pad;
290 : : }
291 : : }
292 : :
293 : : /* look for any Pointer Authentication code masks on AArch64 machines */
294 : 76 : GElf_Ehdr ehdr_mem;
295 : 76 : GElf_Ehdr *ehdr = gelf_getehdr(core, &ehdr_mem);
296 [ + - + + ]: 76 : if (ehdr && ehdr->e_machine == EM_AARCH64)
297 : : {
298 : 108 : while (offset < note_data->d_size
299 [ + + - + ]: 108 : && (offset = gelf_getnote (note_data, offset,
300 : : &nhdr, &name_offset, &desc_offset)) > 0)
301 : : {
302 [ + - ]: 98 : if (nhdr.n_type != NT_ARM_PAC_MASK)
303 : 98 : continue;
304 : :
305 [ # # ]: 0 : name = (nhdr.n_namesz == 0 ? "" : note_data->d_buf + name_offset);
306 : 0 : desc = note_data->d_buf + desc_offset;
307 : 0 : core_note_err = ebl_core_note (core_arg->ebl, &nhdr, name, desc,
308 : : ®s_offset, &nregloc, ®locs,
309 : : &nitems, &items);
310 [ # # ]: 0 : if (!core_note_err)
311 : : break;
312 : :
313 [ # # ]: 0 : for (item = items; item < items + nitems; item++)
314 [ # # ]: 0 : if (strcmp(item->name, "insn_mask") == 0)
315 : : break;
316 : :
317 [ # # ]: 0 : if (item == items + nitems)
318 : 0 : continue;
319 : :
320 : 0 : uint64_t insn_mask = read_8ubyte_unaligned_noncvt(desc + item->offset);
321 : 0 : INTUSE(dwfl_thread_state_registers)(thread, -2, 1, &insn_mask);
322 : 0 : break;
323 : : }
324 : : }
325 : :
326 : : return true;
327 : : }
328 : :
329 : : static void
330 : 74 : core_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg)
331 : : {
332 : 74 : struct core_arg *core_arg = dwfl_arg;
333 : 74 : ebl_closebackend (core_arg->ebl);
334 : 74 : free (core_arg);
335 : 74 : }
336 : :
337 : : static const Dwfl_Thread_Callbacks core_thread_callbacks =
338 : : {
339 : : core_next_thread,
340 : : NULL, /* get_thread */
341 : : core_memory_read,
342 : : core_set_initial_registers,
343 : : core_detach,
344 : : NULL, /* core_thread_detach */
345 : : };
346 : :
347 : : int
348 : 74 : dwfl_core_file_attach (Dwfl *dwfl, Elf *core)
349 : : {
350 : 74 : Dwfl_Error err = DWFL_E_NOERROR;
351 : 74 : Ebl *ebl = ebl_openbackend (core);
352 [ - + ]: 74 : if (ebl == NULL)
353 : : {
354 : : err = DWFL_E_LIBEBL;
355 : 0 : fail_err:
356 [ # # # # ]: 0 : if (dwfl->process == NULL && dwfl->attacherr == DWFL_E_NOERROR)
357 : 0 : dwfl->attacherr = __libdwfl_canon_error (err);
358 : 0 : __libdwfl_seterrno (err);
359 : 0 : return -1;
360 : : }
361 : 74 : size_t nregs = ebl_frame_nregs (ebl);
362 [ - + ]: 74 : if (nregs == 0)
363 : : {
364 : : err = DWFL_E_NO_UNWIND;
365 : 0 : fail:
366 : 0 : ebl_closebackend (ebl);
367 : 0 : goto fail_err;
368 : : }
369 : 74 : GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (core, &ehdr_mem);
370 [ - + ]: 74 : if (ehdr == NULL)
371 : : {
372 : 0 : err = DWFL_E_LIBELF;
373 : 0 : goto fail;
374 : : }
375 [ - + ]: 74 : if (ehdr->e_type != ET_CORE)
376 : : {
377 : 0 : err = DWFL_E_NO_CORE_FILE;
378 : 0 : goto fail;
379 : : }
380 : 74 : size_t phnum;
381 [ - + ]: 74 : if (elf_getphdrnum (core, &phnum) < 0)
382 : : {
383 : 0 : err = DWFL_E_LIBELF;
384 : 0 : goto fail;
385 : : }
386 : 74 : pid_t pid = -1;
387 : 74 : Elf_Data *note_data = NULL;
388 [ + - ]: 74 : for (size_t cnt = 0; cnt < phnum; ++cnt)
389 : : {
390 : 74 : GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
391 [ + - + - ]: 74 : if (phdr != NULL && phdr->p_type == PT_NOTE)
392 : : {
393 : 74 : note_data = elf_getdata_rawchunk (core, phdr->p_offset,
394 [ + - ]: 74 : phdr->p_filesz, (phdr->p_align == 8
395 : : ? ELF_T_NHDR8
396 : : : ELF_T_NHDR));
397 : 74 : break;
398 : : }
399 : : }
400 [ - + ]: 74 : if (note_data == NULL)
401 : : {
402 : 0 : err = DWFL_E_LIBELF;
403 : 0 : goto fail;
404 : : }
405 : : size_t offset = 0;
406 : : GElf_Nhdr nhdr;
407 : : size_t name_offset;
408 : : size_t desc_offset;
409 : 148 : while (offset < note_data->d_size
410 [ - + + - ]: 148 : && (offset = gelf_getnote (note_data, offset,
411 : : &nhdr, &name_offset, &desc_offset)) > 0)
412 : : {
413 : : /* Do not check NAME for now, help broken Linux kernels. */
414 : 296 : const char *name = (nhdr.n_namesz == 0
415 [ + - ]: 148 : ? "" : note_data->d_buf + name_offset);
416 : 148 : const char *desc = note_data->d_buf + desc_offset;
417 : 148 : GElf_Word regs_offset;
418 : 148 : size_t nregloc;
419 : 148 : const Ebl_Register_Location *reglocs;
420 : 148 : size_t nitems;
421 : 148 : const Ebl_Core_Item *items;
422 [ - + ]: 148 : if (! ebl_core_note (ebl, &nhdr, name, desc,
423 : : ®s_offset, &nregloc, ®locs, &nitems, &items))
424 : : {
425 : : /* This note may be just not recognized, skip it. */
426 : 74 : continue;
427 : : }
428 [ + + ]: 148 : if (nhdr.n_type != NT_PRPSINFO)
429 : 74 : continue;
430 : 74 : const Ebl_Core_Item *item;
431 [ + - ]: 592 : for (item = items; item < items + nitems; item++)
432 [ + + ]: 592 : if (strcmp (item->name, "pid") == 0)
433 : : break;
434 [ - + ]: 74 : if (item == items + nitems)
435 : 0 : continue;
436 : 74 : uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
437 : 74 : val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
438 [ + + ]: 74 : ? be32toh (val32) : le32toh (val32));
439 : 74 : pid = (int32_t) val32;
440 : 74 : eu_static_assert (sizeof val32 <= sizeof pid);
441 : 74 : break;
442 : : }
443 [ - + ]: 74 : if (pid == -1)
444 : : {
445 : : /* No valid NT_PRPSINFO recognized in this CORE. */
446 : 0 : err = DWFL_E_BADELF;
447 : 0 : goto fail;
448 : : }
449 : 74 : struct core_arg *core_arg = malloc (sizeof *core_arg);
450 [ - + ]: 74 : if (core_arg == NULL)
451 : : {
452 : 0 : err = DWFL_E_NOMEM;
453 : 0 : goto fail;
454 : : }
455 : 74 : core_arg->core = core;
456 : 74 : core_arg->note_data = note_data;
457 : 74 : core_arg->thread_note_offset = 0;
458 : 74 : core_arg->ebl = ebl;
459 [ - + ]: 74 : if (! INTUSE(dwfl_attach_state) (dwfl, core, pid, &core_thread_callbacks,
460 : : core_arg))
461 : : {
462 : 0 : free (core_arg);
463 : 0 : ebl_closebackend (ebl);
464 : 0 : return -1;
465 : : }
466 : : return pid;
467 : : }
468 : : INTDEF (dwfl_core_file_attach)
|