18ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil/* Test custom provided Dwfl_Thread_Callbacks vector.
28ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   Copyright (C) 2013 Red Hat, Inc.
38ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   This file is part of elfutils.
48ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
58ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   This file is free software; you can redistribute it and/or modify
68ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   it under the terms of the GNU General Public License as published by
78ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   the Free Software Foundation; either version 3 of the License, or
88ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   (at your option) any later version.
98ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
108ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   elfutils is distributed in the hope that it will be useful, but
118ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   WITHOUT ANY WARRANTY; without even the implied warranty of
128ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
138ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   GNU General Public License for more details.
148ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
158ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   You should have received a copy of the GNU General Public License
168ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
178ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
188ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil/* Test custom provided Dwfl_Thread_Callbacks vector.  Test mimics what
198ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   a ptrace based vector would do.  */
208ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
218ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <config.h>
228ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <assert.h>
238ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <inttypes.h>
248ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <stdio.h>
258ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <stdio_ext.h>
268ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <locale.h>
278ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <dirent.h>
288ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <stdlib.h>
298ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <errno.h>
308ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <error.h>
318ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <unistd.h>
328ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <dwarf.h>
3365251494ae6eae66bfdf9134189fd11b1ee8e9b5Pino Toscano#if defined(__x86_64__) && defined(__linux__)
348ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <sys/resource.h>
358ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <sys/ptrace.h>
368ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <signal.h>
378ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <sys/types.h>
388ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <sys/wait.h>
398ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <sys/user.h>
408ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <fcntl.h>
418ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include <string.h>
428ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#include ELFUTILS_HEADER(dwfl)
4365251494ae6eae66bfdf9134189fd11b1ee8e9b5Pino Toscano#endif
448ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
4502cefdaa6429e620d6457fdb3ad9934f194c5a93Kurt Roeckx#if !defined(__x86_64__) || !defined(__linux__)
468ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
478ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilint
48813aae0e94c2e694e1cad25d4e268dfe60397196Mark Wielaardmain (int argc __attribute__ ((unused)), char **argv)
498ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil{
50813aae0e94c2e694e1cad25d4e268dfe60397196Mark Wielaard  fprintf (stderr, "%s: Unwinding not supported for this architecture\n",
51813aae0e94c2e694e1cad25d4e268dfe60397196Mark Wielaard          argv[0]);
528ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  return 77;
538ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil}
548ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
5502cefdaa6429e620d6457fdb3ad9934f194c5a93Kurt Roeckx#else /* __x86_64__ && __linux__ */
568ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
578ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil/* The only arch specific code is set_initial_registers.  */
588ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
598ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilstatic int
608ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilfind_elf (Dwfl_Module *mod __attribute__ ((unused)),
618ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  void **userdata __attribute__ ((unused)),
628ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  const char *modname __attribute__ ((unused)),
638ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  Dwarf_Addr base __attribute__ ((unused)),
648ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  char **file_name __attribute__ ((unused)),
658ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  Elf **elfp __attribute__ ((unused)))
668ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil{
678ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  /* Not used as modules are reported explicitly.  */
688ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (0);
698ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil}
708ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
718ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilstatic bool
728ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilmemory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result,
738ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	     void *dwfl_arg __attribute__ ((unused)))
748ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil{
758ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  pid_t child = dwfl_pid (dwfl);
768ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
778ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  errno = 0;
788ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  long l = ptrace (PTRACE_PEEKDATA, child, (void *) (uintptr_t) addr, NULL);
79c801acf1cb6ee95044d11ad8ed8ebf879db0444cMax Filippov  assert (errno == 0);
808ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  *result = l;
818ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
828ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  /* We could also return false for failed ptrace.  */
838ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  return true;
848ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil}
858ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
868ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil/* Return filename and VMA address *BASEP where its mapping starts which
878ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   contains ADDR.  */
888ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
898ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilstatic char *
908ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilmaps_lookup (pid_t pid, Dwarf_Addr addr, GElf_Addr *basep)
918ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil{
928ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  char *fname;
938ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  int i = asprintf (&fname, "/proc/%ld/maps", (long) pid);
94c801acf1cb6ee95044d11ad8ed8ebf879db0444cMax Filippov  assert (errno == 0);
958ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (i > 0);
968ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  FILE *f = fopen (fname, "r");
97c801acf1cb6ee95044d11ad8ed8ebf879db0444cMax Filippov  assert (errno == 0);
988ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (f);
998ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  free (fname);
1008ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  for (;;)
1018ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    {
1028ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      // 37e3c22000-37e3c23000 rw-p 00022000 00:11 49532 /lib64/ld-2.14.90.so */
1038ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      unsigned long start, end, offset;
1048ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      i = fscanf (f, "%lx-%lx %*s %lx %*x:%*x %*x", &start, &end, &offset);
105c801acf1cb6ee95044d11ad8ed8ebf879db0444cMax Filippov      assert (errno == 0);
1068ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      assert (i == 3);
1078ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      char *filename = strdup ("");
1088ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      assert (filename);
1098ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      size_t filename_len = 0;
1108ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      for (;;)
1118ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	{
1128ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  int c = fgetc (f);
1138ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  assert (c != EOF);
1148ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  if (c == '\n')
1158ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	    break;
1168ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  if (c == ' ' && *filename == '\0')
1178ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	    continue;
1188ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  filename = realloc (filename, filename_len + 2);
1198ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  assert (filename);
1208ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  filename[filename_len++] = c;
1218ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  filename[filename_len] = '\0';
1228ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	}
1238ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      if (start <= addr && addr < end)
1248ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	{
1258ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  i = fclose (f);
126c801acf1cb6ee95044d11ad8ed8ebf879db0444cMax Filippov	  assert (errno == 0);
1278ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  assert (i == 0);
1288ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
1298ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  *basep = start - offset;
1308ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  return filename;
1318ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	}
1328ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      free (filename);
1338ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    }
1348ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil}
1358ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
1368ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil/* Add module containing ADDR to the DWFL address space.
1378ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
1388ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   dwfl_report_elf call here violates Dwfl manipulation as one should call
1398ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   dwfl_report only between dwfl_report_begin_add and dwfl_report_end.
1408ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   Current elfutils implementation does not mind as dwfl_report_begin_add is
1418ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil   empty.  */
1428ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
1438ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilstatic Dwfl_Module *
1448ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilreport_module (Dwfl *dwfl, pid_t child, Dwarf_Addr addr)
1458ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil{
1468ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  GElf_Addr base;
1478ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  char *long_name = maps_lookup (child, addr, &base);
1488ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  Dwfl_Module *mod = dwfl_report_elf (dwfl, long_name, long_name, -1,
1498ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil				      base, false /* add_p_vaddr */);
1508ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (mod);
1518ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  free (long_name);
1528ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (dwfl_addrmodule (dwfl, addr) == mod);
1538ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  return mod;
1548ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil}
1558ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
1568ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilstatic pid_t
1578ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilnext_thread (Dwfl *dwfl, void *dwfl_arg __attribute__ ((unused)),
1588ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	     void **thread_argp)
1598ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil{
1608ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  if (*thread_argp != NULL)
1618ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    return 0;
1628ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  /* Put arbitrary non-NULL value into *THREAD_ARGP as a marker so that this
1638ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil     function returns non-zero PID only once.  */
1648ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  *thread_argp = thread_argp;
1658ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  return dwfl_pid (dwfl);
1668ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil}
1678ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
1688ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilstatic bool
1698ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilset_initial_registers (Dwfl_Thread *thread,
1708ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil		       void *thread_arg __attribute__ ((unused)))
1718ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil{
1728ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  pid_t child = dwfl_pid (dwfl_thread_dwfl (thread));
1738ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
1748ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  struct user_regs_struct user_regs;
1758ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  long l = ptrace (PTRACE_GETREGS, child, NULL, &user_regs);
176c801acf1cb6ee95044d11ad8ed8ebf879db0444cMax Filippov  assert (errno == 0);
1778ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (l == 0);
1788ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
1798ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  Dwarf_Word dwarf_regs[17];
1808ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[0] = user_regs.rax;
1818ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[1] = user_regs.rdx;
1828ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[2] = user_regs.rcx;
1838ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[3] = user_regs.rbx;
1848ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[4] = user_regs.rsi;
1858ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[5] = user_regs.rdi;
1868ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[6] = user_regs.rbp;
1878ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[7] = user_regs.rsp;
1888ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[8] = user_regs.r8;
1898ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[9] = user_regs.r9;
1908ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[10] = user_regs.r10;
1918ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[11] = user_regs.r11;
1928ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[12] = user_regs.r12;
1938ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[13] = user_regs.r13;
1948ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[14] = user_regs.r14;
1958ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[15] = user_regs.r15;
1968ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwarf_regs[16] = user_regs.rip;
1978ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  bool ok = dwfl_thread_state_registers (thread, 0, 17, dwarf_regs);
1988ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (ok);
1998ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
2008ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  /* x86_64 has PC contained in its CFI subset of DWARF register set so
2018ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil     elfutils will figure out the real PC value from REGS.
2028ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil     So no need to explicitly call dwfl_thread_state_register_pc.  */
2038ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
2048ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  return true;
2058ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil}
2068ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
2078ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilstatic const Dwfl_Thread_Callbacks callbacks =
2088ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil{
2098ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  next_thread,
210e962ec3bcbe8eccdcded36aaafee7bec41fa1bc4Mark Wielaard  NULL, /* get_thread */
2118ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  memory_read,
2128ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  set_initial_registers,
2138ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  NULL, /* detach */
2148ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  NULL, /* thread_detach */
2158ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil};
2168ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
2178ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilstatic int
2188ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilframe_callback (Dwfl_Frame *state, void *arg)
2198ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil{
2208ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  unsigned *framenop = arg;
2218ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  Dwarf_Addr pc;
2228ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  bool isactivation;
2238ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  if (! dwfl_frame_pc (state, &pc, &isactivation))
2248ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    {
2258ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      error (1, 0, "%s", dwfl_errmsg (-1));
2268ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      return 1;
2278ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    }
2288ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
2298ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
2308ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  /* Get PC->SYMNAME.  */
2318ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  Dwfl *dwfl = dwfl_thread_dwfl (dwfl_frame_thread (state));
2328ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
2338ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  if (mod == NULL)
2348ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    mod = report_module (dwfl, dwfl_pid (dwfl), pc_adjusted);
2358ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  const char *symname = NULL;
2368ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  symname = dwfl_module_addrname (mod, pc_adjusted);
2378ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
2388ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  printf ("#%2u %#" PRIx64 "%4s\t%s\n", (*framenop)++, (uint64_t) pc,
2398ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil	  ! isactivation ? "- 1" : "", symname);
2408ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  return DWARF_CB_OK;
2418ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil}
2428ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
2438ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilstatic int
2448ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilthread_callback (Dwfl_Thread *thread, void *thread_arg __attribute__ ((unused)))
2458ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil{
2468ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  unsigned frameno = 0;
2478ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  switch (dwfl_thread_getframes (thread, frame_callback, &frameno))
2488ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    {
2498ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    case 0:
2508ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      break;
2518ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    case -1:
2528ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      error (1, 0, "dwfl_thread_getframes: %s", dwfl_errmsg (-1));
2538ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    default:
2548ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      abort ();
2558ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    }
2568ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  return DWARF_CB_OK;
2578ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil}
2588ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
2598ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilint
2608ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvilmain (int argc __attribute__ ((unused)), char **argv __attribute__ ((unused)))
2618ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil{
2628ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  /* We use no threads here which can interfere with handling a stream.  */
2638ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  __fsetlocking (stdin, FSETLOCKING_BYCALLER);
2648ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  __fsetlocking (stdout, FSETLOCKING_BYCALLER);
2658ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  __fsetlocking (stderr, FSETLOCKING_BYCALLER);
2668ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
2678ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  /* Set locale.  */
2688ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  (void) setlocale (LC_ALL, "");
2698ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
2708ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  elf_version (EV_CURRENT);
2718ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
2728ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  pid_t child = fork ();
2738ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  switch (child)
2748ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  {
2758ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    case -1:
276c801acf1cb6ee95044d11ad8ed8ebf879db0444cMax Filippov      assert (errno == 0);
2778ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      assert (0);
2788ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    case 0:;
2798ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      long l = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
280c801acf1cb6ee95044d11ad8ed8ebf879db0444cMax Filippov      assert (errno == 0);
2818ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      assert (l == 0);
2828ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      raise (SIGUSR1);
28370c3a53baa06b6cdee6e92bd673c1cf977066bc1Mark Wielaard      return 0;
2848ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    default:
2858ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      break;
2868ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  }
2878ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
2888ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  int status;
2898ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  pid_t pid = waitpid (child, &status, 0);
290c801acf1cb6ee95044d11ad8ed8ebf879db0444cMax Filippov  assert (errno == 0);
2918ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (pid == child);
2928ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (WIFSTOPPED (status));
2938ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (WSTOPSIG (status) == SIGUSR1);
2948ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
2958ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  static char *debuginfo_path;
2968ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  static const Dwfl_Callbacks offline_callbacks =
2978ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    {
2988ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      .find_debuginfo = dwfl_standard_find_debuginfo,
2998ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      .debuginfo_path = &debuginfo_path,
3008ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      .section_address = dwfl_offline_section_address,
3018ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil      .find_elf = find_elf,
3028ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil    };
3038ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  Dwfl *dwfl = dwfl_begin (&offline_callbacks);
3048ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (dwfl);
3058ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
3068ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  struct user_regs_struct user_regs;
3078ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  long l = ptrace (PTRACE_GETREGS, child, NULL, &user_regs);
308c801acf1cb6ee95044d11ad8ed8ebf879db0444cMax Filippov  assert (errno == 0);
3098ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (l == 0);
3108ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  report_module (dwfl, child, user_regs.rip);
3118ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
3128ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  bool ok = dwfl_attach_state (dwfl, EM_NONE, child, &callbacks, NULL);
3138ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (ok);
3148ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
3158ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  /* Multiple threads are not handled here.  */
3168ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  int err = dwfl_getthreads (dwfl, thread_callback, NULL);
3178ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (! err);
3188ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
3198ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  dwfl_end (dwfl);
3208ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  kill (child, SIGKILL);
3218ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  pid = waitpid (child, &status, 0);
322c801acf1cb6ee95044d11ad8ed8ebf879db0444cMax Filippov  assert (errno == 0);
3238ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (pid == child);
3248ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (WIFSIGNALED (status));
3258ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  assert (WTERMSIG (status) == SIGKILL);
3268ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
3278ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil  return EXIT_SUCCESS;
3288ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil}
3298ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil
3308ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0Jan Kratochvil#endif /* x86_64 */
331