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			   &regs_offset, &nregloc, &reglocs, &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, &regs_offset,
19303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes				     &nregloc, &reglocs, &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			   &regs_offset, &nregloc, &reglocs, &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