1 /* Get Dwarf Frame state for target core file.
2 Copyright (C) 2013, 2014 Red Hat, Inc.
3 This file is part of elfutils.
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
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
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
18 or both in parallel, as here.
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.
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/>. */
33 #include "../libdw/memory-access.h"
36 # define MIN(a, b) ((a) < (b) ? (a) : (b))
43 size_t thread_note_offset;
49 struct core_arg *core_arg;
54 core_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result,
57 Dwfl_Process *process = dwfl->process;
58 struct core_arg *core_arg = dwfl_arg;
59 Elf *core = core_arg->core;
60 assert (core != NULL);
62 if (elf_getphdrnum (core, &phnum) < 0)
64 __libdwfl_seterrno (DWFL_E_LIBELF);
67 for (size_t cnt = 0; cnt < phnum; ++cnt)
69 GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
70 if (phdr == NULL || phdr->p_type != PT_LOAD)
72 /* Bias is zero here, a core file itself has no bias. */
73 GElf_Addr start = __libdwfl_segment_start (dwfl, phdr->p_vaddr);
74 GElf_Addr end = __libdwfl_segment_end (dwfl,
75 phdr->p_vaddr + phdr->p_memsz);
76 unsigned bytes = ebl_get_elfclass (process->ebl) == ELFCLASS64 ? 8 : 4;
77 if (addr < start || addr + bytes > end)
80 data = elf_getdata_rawchunk (core, phdr->p_offset + addr - start,
84 __libdwfl_seterrno (DWFL_E_LIBELF);
87 assert (data->d_size == bytes);
89 *result = read_8ubyte_unaligned_noncvt (data->d_buf);
91 *result = read_4ubyte_unaligned_noncvt (data->d_buf);
94 __libdwfl_seterrno (DWFL_E_ADDR_OUTOFRANGE);
99 core_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg,
102 struct core_arg *core_arg = dwfl_arg;
103 Elf *core = core_arg->core;
107 Elf_Data *note_data = core_arg->note_data;
110 struct thread_arg *thread_arg;
111 if (*thread_argp == NULL)
113 core_arg->thread_note_offset = 0;
114 thread_arg = malloc (sizeof (*thread_arg));
115 if (thread_arg == NULL)
117 __libdwfl_seterrno (DWFL_E_NOMEM);
120 thread_arg->core_arg = core_arg;
121 *thread_argp = thread_arg;
124 thread_arg = (struct thread_arg *) *thread_argp;
126 while (offset = core_arg->thread_note_offset, offset < note_data->d_size
127 && (core_arg->thread_note_offset = gelf_getnote (note_data, offset,
131 /* Do not check NAME for now, help broken Linux kernels. */
132 const char *name = note_data->d_buf + name_offset;
133 const char *desc = note_data->d_buf + desc_offset;
134 GElf_Word regs_offset;
136 const Ebl_Register_Location *reglocs;
138 const Ebl_Core_Item *items;
139 if (! ebl_core_note (core_arg->ebl, &nhdr, name,
140 ®s_offset, &nregloc, ®locs, &nitems, &items))
142 /* This note may be just not recognized, skip it. */
145 if (nhdr.n_type != NT_PRSTATUS)
147 const Ebl_Core_Item *item;
148 for (item = items; item < items + nitems; item++)
149 if (strcmp (item->name, "pid") == 0)
151 if (item == items + nitems)
153 uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
154 val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
155 ? be32toh (val32) : le32toh (val32));
156 pid_t tid = (int32_t) val32;
157 eu_static_assert (sizeof val32 <= sizeof tid);
158 thread_arg->note_offset = offset;
167 core_set_initial_registers (Dwfl_Thread *thread, void *thread_arg_voidp)
169 struct thread_arg *thread_arg = thread_arg_voidp;
170 struct core_arg *core_arg = thread_arg->core_arg;
171 Elf *core = core_arg->core;
172 size_t offset = thread_arg->note_offset;
176 Elf_Data *note_data = core_arg->note_data;
177 size_t nregs = ebl_frame_nregs (core_arg->ebl);
179 assert (offset < note_data->d_size);
180 size_t getnote_err = gelf_getnote (note_data, offset, &nhdr, &name_offset,
182 /* __libdwfl_attach_state_for_core already verified the note is there. */
183 assert (getnote_err != 0);
184 /* Do not check NAME for now, help broken Linux kernels. */
185 const char *name = note_data->d_buf + name_offset;
186 const char *desc = note_data->d_buf + desc_offset;
187 GElf_Word regs_offset;
189 const Ebl_Register_Location *reglocs;
191 const Ebl_Core_Item *items;
192 int core_note_err = ebl_core_note (core_arg->ebl, &nhdr, name, ®s_offset,
193 &nregloc, ®locs, &nitems, &items);
194 /* __libdwfl_attach_state_for_core already verified the note is there. */
195 assert (core_note_err != 0);
196 assert (nhdr.n_type == NT_PRSTATUS);
197 const Ebl_Core_Item *item;
198 for (item = items; item < items + nitems; item++)
199 if (strcmp (item->name, "pid") == 0)
201 assert (item < items + nitems);
204 uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
205 val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
206 ? be32toh (val32) : le32toh (val32));
207 tid = (int32_t) val32;
208 eu_static_assert (sizeof val32 <= sizeof tid);
210 /* core_next_thread already found this TID there. */
211 assert (tid == INTUSE(dwfl_thread_tid) (thread));
212 for (item = items; item < items + nitems; item++)
213 if (item->pc_register)
215 if (item < items + nitems)
218 switch (gelf_getclass (core) == ELFCLASS32 ? 32 : 64)
221 uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
222 val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
223 ? be32toh (val32) : le32toh (val32));
224 /* Do a host width conversion. */
228 uint64_t val64 = read_8ubyte_unaligned_noncvt (desc + item->offset);
229 val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
230 ? be64toh (val64) : le64toh (val64));
236 INTUSE(dwfl_thread_state_register_pc) (thread, pc);
239 for (size_t regloci = 0; regloci < nregloc; regloci++)
241 const Ebl_Register_Location *regloc = reglocs + regloci;
242 // Iterate even regs out of NREGS range so that we can find pc_register.
243 if (regloc->bits != 32 && regloc->bits != 64)
245 const char *reg_desc = desc + regloc->offset;
246 for (unsigned regno = regloc->regno;
247 regno < regloc->regno + (regloc->count ?: 1U);
250 /* PPC provides DWARF register 65 irrelevant for
251 CFI which clashes with register 108 (LR) we need.
252 LR (108) is provided earlier (in NT_PRSTATUS) than the # 65.
253 FIXME: It depends now on their order in core notes.
254 FIXME: It uses private function. */
256 && __libdwfl_frame_reg_get (thread->unwound, regno, NULL))
259 switch (regloc->bits)
262 uint32_t val32 = read_4ubyte_unaligned_noncvt (reg_desc);
263 reg_desc += sizeof val32;
264 val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
265 ? be32toh (val32) : le32toh (val32));
266 /* Do a host width conversion. */
270 uint64_t val64 = read_8ubyte_unaligned_noncvt (reg_desc);
271 reg_desc += sizeof val64;
272 val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
273 ? be64toh (val64) : le64toh (val64));
274 assert (sizeof (*thread->unwound->regs) == sizeof val64);
280 /* Registers not valid for CFI are just ignored. */
282 INTUSE(dwfl_thread_state_registers) (thread, regno, 1, &val);
283 if (regloc->pc_register)
284 INTUSE(dwfl_thread_state_register_pc) (thread, val);
285 reg_desc += regloc->pad;
292 core_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg)
294 struct core_arg *core_arg = dwfl_arg;
295 ebl_closebackend (core_arg->ebl);
299 static const Dwfl_Thread_Callbacks core_thread_callbacks =
302 NULL, /* get_thread */
304 core_set_initial_registers,
306 NULL, /* core_thread_detach */
310 dwfl_core_file_attach (Dwfl *dwfl, Elf *core)
312 Dwfl_Error err = DWFL_E_NOERROR;
313 Ebl *ebl = ebl_openbackend (core);
318 if (dwfl->process == NULL && dwfl->attacherr == DWFL_E_NOERROR)
319 dwfl->attacherr = __libdwfl_canon_error (err);
320 __libdwfl_seterrno (err);
323 size_t nregs = ebl_frame_nregs (ebl);
326 err = DWFL_E_NO_UNWIND;
328 ebl_closebackend (ebl);
331 GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (core, &ehdr_mem);
337 if (ehdr->e_type != ET_CORE)
339 err = DWFL_E_NO_CORE_FILE;
343 if (elf_getphdrnum (core, &phnum) < 0)
349 Elf_Data *note_data = NULL;
350 for (size_t cnt = 0; cnt < phnum; ++cnt)
352 GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
353 if (phdr != NULL && phdr->p_type == PT_NOTE)
355 note_data = elf_getdata_rawchunk (core, phdr->p_offset,
356 phdr->p_filesz, ELF_T_NHDR);
360 if (note_data == NULL)
369 while (offset < note_data->d_size
370 && (offset = gelf_getnote (note_data, offset,
371 &nhdr, &name_offset, &desc_offset)) > 0)
373 /* Do not check NAME for now, help broken Linux kernels. */
374 const char *name = note_data->d_buf + name_offset;
375 const char *desc = note_data->d_buf + desc_offset;
376 GElf_Word regs_offset;
378 const Ebl_Register_Location *reglocs;
380 const Ebl_Core_Item *items;
381 if (! ebl_core_note (ebl, &nhdr, name,
382 ®s_offset, &nregloc, ®locs, &nitems, &items))
384 /* This note may be just not recognized, skip it. */
387 if (nhdr.n_type != NT_PRPSINFO)
389 const Ebl_Core_Item *item;
390 for (item = items; item < items + nitems; item++)
391 if (strcmp (item->name, "pid") == 0)
393 if (item == items + nitems)
395 uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
396 val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
397 ? be32toh (val32) : le32toh (val32));
398 pid = (int32_t) val32;
399 eu_static_assert (sizeof val32 <= sizeof pid);
404 /* No valid NT_PRPSINFO recognized in this CORE. */
408 struct core_arg *core_arg = malloc (sizeof *core_arg);
409 if (core_arg == NULL)
414 core_arg->core = core;
415 core_arg->note_data = note_data;
416 core_arg->thread_note_offset = 0;
418 if (! INTUSE(dwfl_attach_state) (dwfl, core, pid, &core_thread_callbacks,
422 ebl_closebackend (ebl);
427 INTDEF (dwfl_core_file_attach)