1 /* Test program for unwinding of complicated DWARF expressions. 2 Copyright (C) 2013 Red Hat, Inc. 3 This file is part of elfutils. 4 5 This file is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 elfutils is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18 #include <config.h> 19 #include <assert.h> 20 #include <signal.h> 21 #include <inttypes.h> 22 #include <stdio_ext.h> 23 #include <locale.h> 24 #include <errno.h> 25 #include <sys/ptrace.h> 26 #include ELFUTILS_HEADER(dwfl) 27 28 #ifndef __linux__ 29 30 int 31 main (int argc __attribute__ ((unused)), char **argv) 32 { 33 fprintf (stderr, "%s: Unwinding not supported for this architecture\n", 34 argv[0]); 35 return 77; 36 } 37 38 #else /* __linux__ */ 39 40 static void cleanup_13_abort (void); 41 #define main cleanup_13_main 42 #include "cleanup-13.c" 43 #undef main 44 45 static void 46 report_pid (Dwfl *dwfl, pid_t pid) 47 { 48 int result = dwfl_linux_proc_report (dwfl, pid); 49 if (result < 0) 50 error (2, 0, "dwfl_linux_proc_report: %s", dwfl_errmsg (-1)); 51 else if (result > 0) 52 error (2, result, "dwfl_linux_proc_report"); 53 54 if (dwfl_report_end (dwfl, NULL, NULL) != 0) 55 error (2, 0, "dwfl_report_end: %s", dwfl_errmsg (-1)); 56 57 result = dwfl_linux_proc_attach (dwfl, pid, true); 58 if (result < 0) 59 error (2, 0, "dwfl_linux_proc_attach: %s", dwfl_errmsg (-1)); 60 else if (result > 0) 61 error (2, result, "dwfl_linux_proc_attach"); 62 } 63 64 static Dwfl * 65 pid_to_dwfl (pid_t pid) 66 { 67 static char *debuginfo_path; 68 static const Dwfl_Callbacks proc_callbacks = 69 { 70 .find_debuginfo = dwfl_standard_find_debuginfo, 71 .debuginfo_path = &debuginfo_path, 72 73 .find_elf = dwfl_linux_proc_find_elf, 74 }; 75 Dwfl *dwfl = dwfl_begin (&proc_callbacks); 76 if (dwfl == NULL) 77 error (2, 0, "dwfl_begin: %s", dwfl_errmsg (-1)); 78 report_pid (dwfl, pid); 79 return dwfl; 80 } 81 82 static int 83 frame_callback (Dwfl_Frame *state, void *frame_arg) 84 { 85 Dwarf_Addr pc; 86 bool isactivation; 87 if (! dwfl_frame_pc (state, &pc, &isactivation)) 88 { 89 error (0, 0, "%s", dwfl_errmsg (-1)); 90 return DWARF_CB_ABORT; 91 } 92 Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1); 93 94 /* Get PC->SYMNAME. */ 95 Dwfl_Thread *thread = dwfl_frame_thread (state); 96 Dwfl *dwfl = dwfl_thread_dwfl (thread); 97 Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted); 98 const char *symname = NULL; 99 if (mod) 100 symname = dwfl_module_addrname (mod, pc_adjusted); 101 102 printf ("%#" PRIx64 "\t%s\n", (uint64_t) pc, symname); 103 104 if (symname && (strcmp (symname, "main") == 0 105 || strcmp (symname, ".main") == 0)) 106 { 107 kill (dwfl_pid (dwfl), SIGKILL); 108 exit (0); 109 } 110 111 return DWARF_CB_OK; 112 } 113 114 static int 115 thread_callback (Dwfl_Thread *thread, void *thread_arg) 116 { 117 dwfl_thread_getframes (thread, frame_callback, NULL); 118 error (1, 0, "dwfl_thread_getframes: %s", dwfl_errmsg (-1)); 119 } 120 121 int 122 main (int argc __attribute__ ((unused)), char **argv) 123 { 124 /* We use no threads here which can interfere with handling a stream. */ 125 __fsetlocking (stdin, FSETLOCKING_BYCALLER); 126 __fsetlocking (stdout, FSETLOCKING_BYCALLER); 127 __fsetlocking (stderr, FSETLOCKING_BYCALLER); 128 129 /* Set locale. */ 130 (void) setlocale (LC_ALL, ""); 131 132 elf_version (EV_CURRENT); 133 134 pid_t pid = fork (); 135 switch (pid) 136 { 137 case -1: 138 abort (); 139 case 0:; 140 long l = ptrace (PTRACE_TRACEME, 0, NULL, NULL); 141 assert_perror (errno); 142 assert (l == 0); 143 cleanup_13_main (); 144 abort (); 145 default: 146 break; 147 } 148 149 errno = 0; 150 int status; 151 pid_t got = waitpid (pid, &status, 0); 152 assert_perror (errno); 153 assert (got == pid); 154 assert (WIFSTOPPED (status)); 155 assert (WSTOPSIG (status) == SIGABRT); 156 157 Dwfl *dwfl = pid_to_dwfl (pid); 158 dwfl_getthreads (dwfl, thread_callback, NULL); 159 160 /* There is an exit (0) call if we find the "main" frame, */ 161 error (1, 0, "dwfl_getthreads: %s", dwfl_errmsg (-1)); 162 } 163 164 #endif /* ! __linux__ */ 165 166