103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* Get Dwarf Frame state for target core file. 203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Copyright (C) 2013, 2014 Red Hat, Inc. 303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes This file is part of elfutils. 403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes This file is free software; you can redistribute it and/or modify 603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes it under the terms of either 703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes * the GNU Lesser General Public License as published by the Free 903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Software Foundation; either version 3 of the License, or (at 1003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes your option) any later version 1103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 1203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes or 1303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 1403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes * the GNU General Public License as published by the Free 1503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Software Foundation; either version 2 of the License, or (at 1603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes your option) any later version 1703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 1803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes or both in parallel, as here. 1903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 2003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes elfutils is distributed in the hope that it will be useful, but 2103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes WITHOUT ANY WARRANTY; without even the implied warranty of 2203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes General Public License for more details. 2403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 2503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes You should have received copies of the GNU General Public License and 2603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes the GNU Lesser General Public License along with this program. If 2703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes not, see <http://www.gnu.org/licenses/>. */ 2803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 2903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include "libdwflP.h" 3003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <fcntl.h> 3103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include "system.h" 3203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 3303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include "../libdw/memory-access.h" 3403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 3503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#ifndef MIN 3603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes# define MIN(a, b) ((a) < (b) ? (a) : (b)) 3703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#endif 3803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 3903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstruct core_arg 4003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{ 4103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Elf *core; 4203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Elf_Data *note_data; 4303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t thread_note_offset; 4403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Ebl *ebl; 4503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}; 4603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 4703333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstruct thread_arg 4803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{ 4903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes struct core_arg *core_arg; 5003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t note_offset; 5103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}; 5203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 5303333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic bool 5403333823c75a1c1887e923828113a1b0fd12020cElliott Hughescore_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, 5503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes void *dwfl_arg) 5603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{ 5703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Dwfl_Process *process = dwfl->process; 5803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes struct core_arg *core_arg = dwfl_arg; 5903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Elf *core = core_arg->core; 6003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes assert (core != NULL); 6103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes static size_t phnum; 6203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (elf_getphdrnum (core, &phnum) < 0) 6303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 6403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes __libdwfl_seterrno (DWFL_E_LIBELF); 6503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes return false; 6603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 6703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes for (size_t cnt = 0; cnt < phnum; ++cnt) 6803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 6903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem); 7003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (phdr == NULL || phdr->p_type != PT_LOAD) 7103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes continue; 7203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* Bias is zero here, a core file itself has no bias. */ 7303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes GElf_Addr start = __libdwfl_segment_start (dwfl, phdr->p_vaddr); 7403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes GElf_Addr end = __libdwfl_segment_end (dwfl, 7503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes phdr->p_vaddr + phdr->p_memsz); 7603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes unsigned bytes = ebl_get_elfclass (process->ebl) == ELFCLASS64 ? 8 : 4; 7703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (addr < start || addr + bytes > end) 7803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes continue; 7903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Elf_Data *data; 8003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes data = elf_getdata_rawchunk (core, phdr->p_offset + addr - start, 8103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes bytes, ELF_T_ADDR); 8203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (data == NULL) 8303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 8403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes __libdwfl_seterrno (DWFL_E_LIBELF); 8503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes return false; 8603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 8703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes assert (data->d_size == bytes); 8803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (bytes == 8) 8903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes *result = read_8ubyte_unaligned_noncvt (data->d_buf); 9003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes else 9103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes *result = read_4ubyte_unaligned_noncvt (data->d_buf); 9203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes return true; 9303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 9403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes __libdwfl_seterrno (DWFL_E_ADDR_OUTOFRANGE); 9503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes return false; 9603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes} 9703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 9803333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic pid_t 9903333823c75a1c1887e923828113a1b0fd12020cElliott Hughescore_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg, 10003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes void **thread_argp) 10103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{ 10203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes struct core_arg *core_arg = dwfl_arg; 10303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Elf *core = core_arg->core; 10403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes GElf_Nhdr nhdr; 10503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t name_offset; 10603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t desc_offset; 10703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Elf_Data *note_data = core_arg->note_data; 10803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t offset; 10903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 11003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes struct thread_arg *thread_arg; 11103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (*thread_argp == NULL) 11203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 11303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes core_arg->thread_note_offset = 0; 11403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes thread_arg = malloc (sizeof (*thread_arg)); 11503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (thread_arg == NULL) 11603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 11703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes __libdwfl_seterrno (DWFL_E_NOMEM); 11803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes return -1; 11903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 12003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes thread_arg->core_arg = core_arg; 12103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes *thread_argp = thread_arg; 12203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 12303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes else 12403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes thread_arg = (struct thread_arg *) *thread_argp; 12503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 12603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes while (offset = core_arg->thread_note_offset, offset < note_data->d_size 12703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes && (core_arg->thread_note_offset = gelf_getnote (note_data, offset, 12803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes &nhdr, &name_offset, 12903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes &desc_offset)) > 0) 13003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 13103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* Do not check NAME for now, help broken Linux kernels. */ 13203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const char *name = note_data->d_buf + name_offset; 13303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const char *desc = note_data->d_buf + desc_offset; 13403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes GElf_Word regs_offset; 13503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t nregloc; 13603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const Ebl_Register_Location *reglocs; 13703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t nitems; 13803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const Ebl_Core_Item *items; 13903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (! ebl_core_note (core_arg->ebl, &nhdr, name, 14003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes ®s_offset, &nregloc, ®locs, &nitems, &items)) 14103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 14203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* This note may be just not recognized, skip it. */ 14303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes continue; 14403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 14503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (nhdr.n_type != NT_PRSTATUS) 14603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes continue; 14703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const Ebl_Core_Item *item; 14803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes for (item = items; item < items + nitems; item++) 14903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (strcmp (item->name, "pid") == 0) 15003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes break; 15103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (item == items + nitems) 15203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes continue; 15303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset); 15403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 15503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes ? be32toh (val32) : le32toh (val32)); 15603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes pid_t tid = (int32_t) val32; 15703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes eu_static_assert (sizeof val32 <= sizeof tid); 15803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes thread_arg->note_offset = offset; 15903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes return tid; 16003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 16103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 16203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes free (thread_arg); 16303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes return 0; 16403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes} 16503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 16603333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic bool 16703333823c75a1c1887e923828113a1b0fd12020cElliott Hughescore_set_initial_registers (Dwfl_Thread *thread, void *thread_arg_voidp) 16803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{ 16903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes struct thread_arg *thread_arg = thread_arg_voidp; 17003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes struct core_arg *core_arg = thread_arg->core_arg; 17103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Elf *core = core_arg->core; 17203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t offset = thread_arg->note_offset; 17303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes GElf_Nhdr nhdr; 17403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t name_offset; 17503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t desc_offset; 17603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Elf_Data *note_data = core_arg->note_data; 17703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t nregs = ebl_frame_nregs (core_arg->ebl); 17803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes assert (nregs > 0); 17903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes assert (offset < note_data->d_size); 18003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t getnote_err = gelf_getnote (note_data, offset, &nhdr, &name_offset, 18103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes &desc_offset); 18203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* __libdwfl_attach_state_for_core already verified the note is there. */ 18303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes assert (getnote_err != 0); 18403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* Do not check NAME for now, help broken Linux kernels. */ 18503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const char *name = note_data->d_buf + name_offset; 18603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const char *desc = note_data->d_buf + desc_offset; 18703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes GElf_Word regs_offset; 18803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t nregloc; 18903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const Ebl_Register_Location *reglocs; 19003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t nitems; 19103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const Ebl_Core_Item *items; 19203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes int core_note_err = ebl_core_note (core_arg->ebl, &nhdr, name, ®s_offset, 19303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes &nregloc, ®locs, &nitems, &items); 19403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* __libdwfl_attach_state_for_core already verified the note is there. */ 19503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes assert (core_note_err != 0); 19603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes assert (nhdr.n_type == NT_PRSTATUS); 19703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const Ebl_Core_Item *item; 19803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes for (item = items; item < items + nitems; item++) 19903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (strcmp (item->name, "pid") == 0) 20003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes break; 20103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes assert (item < items + nitems); 20203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes pid_t tid; 20303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 20403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset); 20503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 20603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes ? be32toh (val32) : le32toh (val32)); 20703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes tid = (int32_t) val32; 20803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes eu_static_assert (sizeof val32 <= sizeof tid); 20903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 21003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* core_next_thread already found this TID there. */ 21103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes assert (tid == INTUSE(dwfl_thread_tid) (thread)); 21203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes for (item = items; item < items + nitems; item++) 21303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (item->pc_register) 21403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes break; 21503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (item < items + nitems) 21603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 21703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Dwarf_Word pc; 21803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes switch (gelf_getclass (core) == ELFCLASS32 ? 32 : 64) 21903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 22003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes case 32:; 22103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset); 22203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 22303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes ? be32toh (val32) : le32toh (val32)); 22403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* Do a host width conversion. */ 22503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes pc = val32; 22603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes break; 22703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes case 64:; 22803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes uint64_t val64 = read_8ubyte_unaligned_noncvt (desc + item->offset); 22903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 23003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes ? be64toh (val64) : le64toh (val64)); 23103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes pc = val64; 23203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes break; 23303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes default: 23403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes abort (); 23503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 23603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes INTUSE(dwfl_thread_state_register_pc) (thread, pc); 23703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 23803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes desc += regs_offset; 23903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes for (size_t regloci = 0; regloci < nregloc; regloci++) 24003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 24103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const Ebl_Register_Location *regloc = reglocs + regloci; 24203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes // Iterate even regs out of NREGS range so that we can find pc_register. 24303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (regloc->bits != 32 && regloc->bits != 64) 24403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes continue; 24503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const char *reg_desc = desc + regloc->offset; 24603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes for (unsigned regno = regloc->regno; 24703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes regno < regloc->regno + (regloc->count ?: 1U); 24803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes regno++) 24903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 25003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* PPC provides DWARF register 65 irrelevant for 25103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes CFI which clashes with register 108 (LR) we need. 25203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes LR (108) is provided earlier (in NT_PRSTATUS) than the # 65. 25303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes FIXME: It depends now on their order in core notes. 25403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes FIXME: It uses private function. */ 25503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (regno < nregs 25603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes && __libdwfl_frame_reg_get (thread->unwound, regno, NULL)) 25703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes continue; 25803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Dwarf_Word val; 25903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes switch (regloc->bits) 26003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 26103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes case 32:; 26203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes uint32_t val32 = read_4ubyte_unaligned_noncvt (reg_desc); 26303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes reg_desc += sizeof val32; 26403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 26503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes ? be32toh (val32) : le32toh (val32)); 26603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* Do a host width conversion. */ 26703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes val = val32; 26803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes break; 26903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes case 64:; 27003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes uint64_t val64 = read_8ubyte_unaligned_noncvt (reg_desc); 27103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes reg_desc += sizeof val64; 27203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 27303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes ? be64toh (val64) : le64toh (val64)); 27403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes assert (sizeof (*thread->unwound->regs) == sizeof val64); 27503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes val = val64; 27603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes break; 27703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes default: 27803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes abort (); 27903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 28003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* Registers not valid for CFI are just ignored. */ 28103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (regno < nregs) 28203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes INTUSE(dwfl_thread_state_registers) (thread, regno, 1, &val); 28303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (regloc->pc_register) 28403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes INTUSE(dwfl_thread_state_register_pc) (thread, val); 28503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes reg_desc += regloc->pad; 28603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 28703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 28803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes return true; 28903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes} 29003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 29103333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic void 29203333823c75a1c1887e923828113a1b0fd12020cElliott Hughescore_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg) 29303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{ 29403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes struct core_arg *core_arg = dwfl_arg; 29503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes ebl_closebackend (core_arg->ebl); 29603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes free (core_arg); 29703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes} 29803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 29903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic const Dwfl_Thread_Callbacks core_thread_callbacks = 30003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{ 30103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes core_next_thread, 30203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes NULL, /* get_thread */ 30303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes core_memory_read, 30403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes core_set_initial_registers, 30503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes core_detach, 30603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes NULL, /* core_thread_detach */ 30703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}; 30803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 30903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesint 31003333823c75a1c1887e923828113a1b0fd12020cElliott Hughesdwfl_core_file_attach (Dwfl *dwfl, Elf *core) 31103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{ 31203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Dwfl_Error err = DWFL_E_NOERROR; 31303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Ebl *ebl = ebl_openbackend (core); 31403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (ebl == NULL) 31503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 31603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes err = DWFL_E_LIBEBL; 31703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes fail_err: 31803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (dwfl->process == NULL && dwfl->attacherr == DWFL_E_NOERROR) 31903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes dwfl->attacherr = __libdwfl_canon_error (err); 32003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes __libdwfl_seterrno (err); 32103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes return -1; 32203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 32303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t nregs = ebl_frame_nregs (ebl); 32403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (nregs == 0) 32503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 32603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes err = DWFL_E_NO_UNWIND; 32703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes fail: 32803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes ebl_closebackend (ebl); 32903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes goto fail_err; 33003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 33103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (core, &ehdr_mem); 33203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (ehdr == NULL) 33303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 33403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes err = DWFL_E_LIBELF; 33503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes goto fail; 33603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 33703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (ehdr->e_type != ET_CORE) 33803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 33903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes err = DWFL_E_NO_CORE_FILE; 34003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes goto fail; 34103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 34203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t phnum; 34303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (elf_getphdrnum (core, &phnum) < 0) 34403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 34503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes err = DWFL_E_LIBELF; 34603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes goto fail; 34703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 34803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes pid_t pid = -1; 34903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Elf_Data *note_data = NULL; 35003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes for (size_t cnt = 0; cnt < phnum; ++cnt) 35103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 35203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem); 35303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (phdr != NULL && phdr->p_type == PT_NOTE) 35403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 35503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes note_data = elf_getdata_rawchunk (core, phdr->p_offset, 35603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes phdr->p_filesz, ELF_T_NHDR); 35703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes break; 35803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 35903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 36003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (note_data == NULL) 36103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 36203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes err = DWFL_E_LIBELF; 36303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes goto fail; 36403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 36503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t offset = 0; 36603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes GElf_Nhdr nhdr; 36703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t name_offset; 36803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t desc_offset; 36903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes while (offset < note_data->d_size 37003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes && (offset = gelf_getnote (note_data, offset, 37103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes &nhdr, &name_offset, &desc_offset)) > 0) 37203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 37303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* Do not check NAME for now, help broken Linux kernels. */ 37403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const char *name = note_data->d_buf + name_offset; 37503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const char *desc = note_data->d_buf + desc_offset; 37603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes GElf_Word regs_offset; 37703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t nregloc; 37803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const Ebl_Register_Location *reglocs; 37903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes size_t nitems; 38003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const Ebl_Core_Item *items; 38103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (! ebl_core_note (ebl, &nhdr, name, 38203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes ®s_offset, &nregloc, ®locs, &nitems, &items)) 38303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 38403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* This note may be just not recognized, skip it. */ 38503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes continue; 38603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 38703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (nhdr.n_type != NT_PRPSINFO) 38803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes continue; 38903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const Ebl_Core_Item *item; 39003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes for (item = items; item < items + nitems; item++) 39103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (strcmp (item->name, "pid") == 0) 39203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes break; 39303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (item == items + nitems) 39403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes continue; 39503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset); 39603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 39703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes ? be32toh (val32) : le32toh (val32)); 39803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes pid = (int32_t) val32; 39903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes eu_static_assert (sizeof val32 <= sizeof pid); 40003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes break; 40103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 40203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (pid == -1) 40303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 40403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes /* No valid NT_PRPSINFO recognized in this CORE. */ 40503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes err = DWFL_E_BADELF; 40603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes goto fail; 40703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 40803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes struct core_arg *core_arg = malloc (sizeof *core_arg); 40903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (core_arg == NULL) 41003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 41103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes err = DWFL_E_NOMEM; 41203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes goto fail; 41303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 41403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes core_arg->core = core; 41503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes core_arg->note_data = note_data; 41603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes core_arg->thread_note_offset = 0; 41703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes core_arg->ebl = ebl; 41803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes if (! INTUSE(dwfl_attach_state) (dwfl, core, pid, &core_thread_callbacks, 41903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes core_arg)) 42003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes { 42103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes free (core_arg); 42203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes ebl_closebackend (ebl); 42303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes return -1; 42403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes } 42503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes return pid; 42603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes} 42703333823c75a1c1887e923828113a1b0fd12020cElliott HughesINTDEF (dwfl_core_file_attach) 428