1 /* Test custom provided Dwfl_Thread_Callbacks vector. 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 /* Test custom provided Dwfl_Thread_Callbacks vector. Test mimics what 19 a ptrace based vector would do. */ 20 21 #include <config.h> 22 #include <assert.h> 23 #include <inttypes.h> 24 #include <stdio.h> 25 #include <stdio_ext.h> 26 #include <locale.h> 27 #include <dirent.h> 28 #include <stdlib.h> 29 #include <errno.h> 30 #include <error.h> 31 #include <unistd.h> 32 #include <dwarf.h> 33 #if defined(__x86_64__) && defined(__linux__) 34 #include <sys/resource.h> 35 #include <sys/ptrace.h> 36 #include <signal.h> 37 #include <sys/types.h> 38 #include <sys/wait.h> 39 #include <sys/user.h> 40 #include <fcntl.h> 41 #include <string.h> 42 #include ELFUTILS_HEADER(dwfl) 43 #endif 44 45 #if !defined(__x86_64__) || !defined(__linux__) 46 47 int 48 main (int argc __attribute__ ((unused)), char **argv) 49 { 50 fprintf (stderr, "%s: Unwinding not supported for this architecture\n", 51 argv[0]); 52 return 77; 53 } 54 55 #else /* __x86_64__ && __linux__ */ 56 57 /* The only arch specific code is set_initial_registers. */ 58 59 static int 60 find_elf (Dwfl_Module *mod __attribute__ ((unused)), 61 void **userdata __attribute__ ((unused)), 62 const char *modname __attribute__ ((unused)), 63 Dwarf_Addr base __attribute__ ((unused)), 64 char **file_name __attribute__ ((unused)), 65 Elf **elfp __attribute__ ((unused))) 66 { 67 /* Not used as modules are reported explicitly. */ 68 assert (0); 69 } 70 71 static bool 72 memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, 73 void *dwfl_arg __attribute__ ((unused))) 74 { 75 pid_t child = dwfl_pid (dwfl); 76 77 errno = 0; 78 long l = ptrace (PTRACE_PEEKDATA, child, (void *) (uintptr_t) addr, NULL); 79 assert (errno == 0); 80 *result = l; 81 82 /* We could also return false for failed ptrace. */ 83 return true; 84 } 85 86 /* Return filename and VMA address *BASEP where its mapping starts which 87 contains ADDR. */ 88 89 static char * 90 maps_lookup (pid_t pid, Dwarf_Addr addr, GElf_Addr *basep) 91 { 92 char *fname; 93 int i = asprintf (&fname, "/proc/%ld/maps", (long) pid); 94 assert (errno == 0); 95 assert (i > 0); 96 FILE *f = fopen (fname, "r"); 97 assert (errno == 0); 98 assert (f); 99 free (fname); 100 for (;;) 101 { 102 // 37e3c22000-37e3c23000 rw-p 00022000 00:11 49532 /lib64/ld-2.14.90.so */ 103 unsigned long start, end, offset; 104 i = fscanf (f, "%lx-%lx %*s %lx %*x:%*x %*x", &start, &end, &offset); 105 assert (errno == 0); 106 assert (i == 3); 107 char *filename = strdup (""); 108 assert (filename); 109 size_t filename_len = 0; 110 for (;;) 111 { 112 int c = fgetc (f); 113 assert (c != EOF); 114 if (c == '\n') 115 break; 116 if (c == ' ' && *filename == '\0') 117 continue; 118 filename = realloc (filename, filename_len + 2); 119 assert (filename); 120 filename[filename_len++] = c; 121 filename[filename_len] = '\0'; 122 } 123 if (start <= addr && addr < end) 124 { 125 i = fclose (f); 126 assert (errno == 0); 127 assert (i == 0); 128 129 *basep = start - offset; 130 return filename; 131 } 132 free (filename); 133 } 134 } 135 136 /* Add module containing ADDR to the DWFL address space. 137 138 dwfl_report_elf call here violates Dwfl manipulation as one should call 139 dwfl_report only between dwfl_report_begin_add and dwfl_report_end. 140 Current elfutils implementation does not mind as dwfl_report_begin_add is 141 empty. */ 142 143 static Dwfl_Module * 144 report_module (Dwfl *dwfl, pid_t child, Dwarf_Addr addr) 145 { 146 GElf_Addr base; 147 char *long_name = maps_lookup (child, addr, &base); 148 Dwfl_Module *mod = dwfl_report_elf (dwfl, long_name, long_name, -1, 149 base, false /* add_p_vaddr */); 150 assert (mod); 151 free (long_name); 152 assert (dwfl_addrmodule (dwfl, addr) == mod); 153 return mod; 154 } 155 156 static pid_t 157 next_thread (Dwfl *dwfl, void *dwfl_arg __attribute__ ((unused)), 158 void **thread_argp) 159 { 160 if (*thread_argp != NULL) 161 return 0; 162 /* Put arbitrary non-NULL value into *THREAD_ARGP as a marker so that this 163 function returns non-zero PID only once. */ 164 *thread_argp = thread_argp; 165 return dwfl_pid (dwfl); 166 } 167 168 static bool 169 set_initial_registers (Dwfl_Thread *thread, 170 void *thread_arg __attribute__ ((unused))) 171 { 172 pid_t child = dwfl_pid (dwfl_thread_dwfl (thread)); 173 174 struct user_regs_struct user_regs; 175 long l = ptrace (PTRACE_GETREGS, child, NULL, &user_regs); 176 assert (errno == 0); 177 assert (l == 0); 178 179 Dwarf_Word dwarf_regs[17]; 180 dwarf_regs[0] = user_regs.rax; 181 dwarf_regs[1] = user_regs.rdx; 182 dwarf_regs[2] = user_regs.rcx; 183 dwarf_regs[3] = user_regs.rbx; 184 dwarf_regs[4] = user_regs.rsi; 185 dwarf_regs[5] = user_regs.rdi; 186 dwarf_regs[6] = user_regs.rbp; 187 dwarf_regs[7] = user_regs.rsp; 188 dwarf_regs[8] = user_regs.r8; 189 dwarf_regs[9] = user_regs.r9; 190 dwarf_regs[10] = user_regs.r10; 191 dwarf_regs[11] = user_regs.r11; 192 dwarf_regs[12] = user_regs.r12; 193 dwarf_regs[13] = user_regs.r13; 194 dwarf_regs[14] = user_regs.r14; 195 dwarf_regs[15] = user_regs.r15; 196 dwarf_regs[16] = user_regs.rip; 197 bool ok = dwfl_thread_state_registers (thread, 0, 17, dwarf_regs); 198 assert (ok); 199 200 /* x86_64 has PC contained in its CFI subset of DWARF register set so 201 elfutils will figure out the real PC value from REGS. 202 So no need to explicitly call dwfl_thread_state_register_pc. */ 203 204 return true; 205 } 206 207 static const Dwfl_Thread_Callbacks callbacks = 208 { 209 next_thread, 210 NULL, /* get_thread */ 211 memory_read, 212 set_initial_registers, 213 NULL, /* detach */ 214 NULL, /* thread_detach */ 215 }; 216 217 static int 218 frame_callback (Dwfl_Frame *state, void *arg) 219 { 220 unsigned *framenop = arg; 221 Dwarf_Addr pc; 222 bool isactivation; 223 if (! dwfl_frame_pc (state, &pc, &isactivation)) 224 { 225 error (1, 0, "%s", dwfl_errmsg (-1)); 226 return 1; 227 } 228 Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1); 229 230 /* Get PC->SYMNAME. */ 231 Dwfl *dwfl = dwfl_thread_dwfl (dwfl_frame_thread (state)); 232 Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted); 233 if (mod == NULL) 234 mod = report_module (dwfl, dwfl_pid (dwfl), pc_adjusted); 235 const char *symname = NULL; 236 symname = dwfl_module_addrname (mod, pc_adjusted); 237 238 printf ("#%2u %#" PRIx64 "%4s\t%s\n", (*framenop)++, (uint64_t) pc, 239 ! isactivation ? "- 1" : "", symname); 240 return DWARF_CB_OK; 241 } 242 243 static int 244 thread_callback (Dwfl_Thread *thread, void *thread_arg __attribute__ ((unused))) 245 { 246 unsigned frameno = 0; 247 switch (dwfl_thread_getframes (thread, frame_callback, &frameno)) 248 { 249 case 0: 250 break; 251 case -1: 252 error (1, 0, "dwfl_thread_getframes: %s", dwfl_errmsg (-1)); 253 default: 254 abort (); 255 } 256 return DWARF_CB_OK; 257 } 258 259 int 260 main (int argc __attribute__ ((unused)), char **argv __attribute__ ((unused))) 261 { 262 /* We use no threads here which can interfere with handling a stream. */ 263 __fsetlocking (stdin, FSETLOCKING_BYCALLER); 264 __fsetlocking (stdout, FSETLOCKING_BYCALLER); 265 __fsetlocking (stderr, FSETLOCKING_BYCALLER); 266 267 /* Set locale. */ 268 (void) setlocale (LC_ALL, ""); 269 270 elf_version (EV_CURRENT); 271 272 pid_t child = fork (); 273 switch (child) 274 { 275 case -1: 276 assert (errno == 0); 277 assert (0); 278 case 0:; 279 long l = ptrace (PTRACE_TRACEME, 0, NULL, NULL); 280 assert (errno == 0); 281 assert (l == 0); 282 raise (SIGUSR1); 283 return 0; 284 default: 285 break; 286 } 287 288 int status; 289 pid_t pid = waitpid (child, &status, 0); 290 assert (errno == 0); 291 assert (pid == child); 292 assert (WIFSTOPPED (status)); 293 assert (WSTOPSIG (status) == SIGUSR1); 294 295 static char *debuginfo_path; 296 static const Dwfl_Callbacks offline_callbacks = 297 { 298 .find_debuginfo = dwfl_standard_find_debuginfo, 299 .debuginfo_path = &debuginfo_path, 300 .section_address = dwfl_offline_section_address, 301 .find_elf = find_elf, 302 }; 303 Dwfl *dwfl = dwfl_begin (&offline_callbacks); 304 assert (dwfl); 305 306 struct user_regs_struct user_regs; 307 long l = ptrace (PTRACE_GETREGS, child, NULL, &user_regs); 308 assert (errno == 0); 309 assert (l == 0); 310 report_module (dwfl, child, user_regs.rip); 311 312 bool ok = dwfl_attach_state (dwfl, EM_NONE, child, &callbacks, NULL); 313 assert (ok); 314 315 /* Multiple threads are not handled here. */ 316 int err = dwfl_getthreads (dwfl, thread_callback, NULL); 317 assert (! err); 318 319 dwfl_end (dwfl); 320 kill (child, SIGKILL); 321 pid = waitpid (child, &status, 0); 322 assert (errno == 0); 323 assert (pid == child); 324 assert (WIFSIGNALED (status)); 325 assert (WTERMSIG (status) == SIGKILL); 326 327 return EXIT_SUCCESS; 328 } 329 330 #endif /* x86_64 */ 331