1/* Test program for unwinding of complicated DWARF expressions. 2 Copyright (C) 2013, 2015, 2018 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 <inttypes.h> 20#include <stdio_ext.h> 21#include <locale.h> 22#include <errno.h> 23#include <unistd.h> 24#include <sys/types.h> 25#include ELFUTILS_HEADER(dwfl) 26#include "system.h" 27 28#ifndef __linux__ 29 30int 31main (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#include <sys/ptrace.h> 40#include <sys/wait.h> 41#include <signal.h> 42 43#define main cleanup_13_main 44#include "cleanup-13.c" 45#undef main 46 47static void 48report_pid (Dwfl *dwfl, pid_t pid) 49{ 50 int result = dwfl_linux_proc_report (dwfl, pid); 51 if (result < 0) 52 error (2, 0, "dwfl_linux_proc_report: %s", dwfl_errmsg (-1)); 53 else if (result > 0) 54 error (2, result, "dwfl_linux_proc_report"); 55 56 if (dwfl_report_end (dwfl, NULL, NULL) != 0) 57 error (2, 0, "dwfl_report_end: %s", dwfl_errmsg (-1)); 58 59 result = dwfl_linux_proc_attach (dwfl, pid, true); 60 if (result < 0) 61 error (2, 0, "dwfl_linux_proc_attach: %s", dwfl_errmsg (-1)); 62 else if (result > 0) 63 error (2, result, "dwfl_linux_proc_attach"); 64} 65 66static Dwfl * 67pid_to_dwfl (pid_t pid) 68{ 69 static char *debuginfo_path; 70 static const Dwfl_Callbacks proc_callbacks = 71 { 72 .find_debuginfo = dwfl_standard_find_debuginfo, 73 .debuginfo_path = &debuginfo_path, 74 75 .find_elf = dwfl_linux_proc_find_elf, 76 }; 77 Dwfl *dwfl = dwfl_begin (&proc_callbacks); 78 if (dwfl == NULL) 79 error (2, 0, "dwfl_begin: %s", dwfl_errmsg (-1)); 80 report_pid (dwfl, pid); 81 return dwfl; 82} 83 84static int 85frame_callback (Dwfl_Frame *state, void *frame_arg) 86{ 87 Dwarf_Addr pc; 88 bool isactivation; 89 if (! dwfl_frame_pc (state, &pc, &isactivation)) 90 { 91 error (0, 0, "%s", dwfl_errmsg (-1)); 92 return DWARF_CB_ABORT; 93 } 94 Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1); 95 96 /* Get PC->SYMNAME. */ 97 Dwfl_Thread *thread = dwfl_frame_thread (state); 98 Dwfl *dwfl = dwfl_thread_dwfl (thread); 99 Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted); 100 const char *symname = NULL; 101 if (mod) 102 symname = dwfl_module_addrname (mod, pc_adjusted); 103 104 printf ("%#" PRIx64 "\t%s\n", (uint64_t) pc, symname ?: "<null>"); 105 106 if (symname && (strcmp (symname, "main") == 0 107 || strcmp (symname, ".main") == 0)) 108 { 109 kill (dwfl_pid (dwfl), SIGKILL); 110 exit (0); 111 } 112 113 return DWARF_CB_OK; 114} 115 116static int 117thread_callback (Dwfl_Thread *thread, void *thread_arg) 118{ 119 if (dwfl_thread_getframes (thread, frame_callback, NULL) == -1) 120 error (1, 0, "dwfl_thread_getframes: %s", dwfl_errmsg (-1)); 121 122 /* frame_callback shall exit (0) on success. */ 123 printf ("dwfl_thread_getframes returned, main not found\n"); 124 return DWARF_CB_ABORT; 125} 126 127int 128__attribute__((section(".main"))) /* Defeat -freorder-blocks-and-partition */ 129main (int argc __attribute__ ((unused)), char **argv) 130{ 131 /* We use no threads here which can interfere with handling a stream. */ 132 __fsetlocking (stdin, FSETLOCKING_BYCALLER); 133 __fsetlocking (stdout, FSETLOCKING_BYCALLER); 134 __fsetlocking (stderr, FSETLOCKING_BYCALLER); 135 136 /* Set locale. */ 137 (void) setlocale (LC_ALL, ""); 138 139 elf_version (EV_CURRENT); 140 141 pid_t pid = fork (); 142 switch (pid) 143 { 144 case -1: 145 perror ("fork failed"); 146 exit (-1); 147 case 0:; 148 long l = ptrace (PTRACE_TRACEME, 0, NULL, NULL); 149 if (l != 0) 150 { 151 perror ("PTRACE_TRACEME failed"); 152 exit (-1); 153 } 154 cleanup_13_main (); 155 printf ("cleanup_13_main returned, impossible...\n"); 156 exit (-1); 157 default: 158 break; 159 } 160 161 errno = 0; 162 int status; 163 pid_t got = waitpid (pid, &status, 0); 164 if (got != pid) 165 error (1, errno, "waitpid returned %d", got); 166 if (!WIFSTOPPED (status)) 167 error (1, 0, "unexpected wait status %u", status); 168 if (WSTOPSIG (status) != SIGABRT) 169 error (1, 0, "unexpected signal %u", WSTOPSIG (status)); 170 171 Dwfl *dwfl = pid_to_dwfl (pid); 172 if (dwfl_getthreads (dwfl, thread_callback, NULL) == -1) 173 error (1, 0, "dwfl_getthreads: %s", dwfl_errmsg (-1)); 174 175 /* There is an exit (0) call if we find the "main" frame, */ 176 printf ("dwfl_getthreads returned, main not found\n"); 177 exit (-1); 178} 179 180#endif /* ! __linux__ */ 181 182