1 /* Test program for CFI handling. 2 Copyright (C) 2009-2010, 2013, 2015 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 <inttypes.h> 21 #include ELFUTILS_HEADER(dwfl) 22 #include <dwarf.h> 23 #include <argp.h> 24 #include <stdio.h> 25 #include <stdio_ext.h> 26 #include <locale.h> 27 #include <stdlib.h> 28 #include <string.h> 29 30 #include "../libdw/known-dwarf.h" 31 32 static const char * 33 op_name (unsigned int code) 34 { 35 static const char *const known[] = 36 { 37 #define DWARF_ONE_KNOWN_DW_OP(NAME, CODE) [CODE] = #NAME, 38 DWARF_ALL_KNOWN_DW_OP 39 #undef DWARF_ONE_KNOWN_DW_OP 40 }; 41 42 if (likely (code < sizeof (known) / sizeof (known[0]))) 43 return known[code]; 44 45 return NULL; 46 } 47 48 static void 49 print_detail (int result, const Dwarf_Op *ops, size_t nops, Dwarf_Addr bias) 50 { 51 if (result < 0) 52 printf ("indeterminate (%s)\n", dwarf_errmsg (-1)); 53 else if (nops == 0) 54 printf ("%s\n", ops == NULL ? "same_value" : "undefined"); 55 else 56 { 57 printf ("%s expression:", result == 0 ? "location" : "value"); 58 for (size_t i = 0; i < nops; ++i) 59 { 60 printf (" %s", op_name(ops[i].atom)); 61 if (ops[i].number2 == 0) 62 { 63 if (ops[i].atom == DW_OP_addr) 64 printf ("(%#" PRIx64 ")", ops[i].number + bias); 65 else if (ops[i].number != 0) 66 printf ("(%" PRId64 ")", ops[i].number); 67 } 68 else 69 printf ("(%" PRId64 ",%" PRId64 ")", 70 ops[i].number, ops[i].number2); 71 } 72 puts (""); 73 } 74 } 75 76 struct stuff 77 { 78 Dwarf_Frame *frame; 79 Dwarf_Addr bias; 80 }; 81 82 static int 83 print_register (void *arg, 84 int regno, 85 const char *setname, 86 const char *prefix, 87 const char *regname, 88 int bits __attribute__ ((unused)), 89 int type __attribute__ ((unused))) 90 { 91 struct stuff *stuff = arg; 92 93 printf ("\t%s reg%u (%s%s): ", setname, regno, prefix, regname); 94 95 Dwarf_Op ops_mem[2]; 96 Dwarf_Op *ops; 97 size_t nops; 98 int result = dwarf_frame_register (stuff->frame, regno, ops_mem, &ops, &nops); 99 print_detail (result, ops, nops, stuff->bias); 100 101 return DWARF_CB_OK; 102 } 103 104 static int 105 handle_cfi (Dwfl *dwfl, const char *which, Dwarf_CFI *cfi, 106 GElf_Addr pc, struct stuff *stuff) 107 { 108 if (cfi == NULL) 109 { 110 printf ("handle_cfi no CFI (%s): %s\n", which, dwarf_errmsg (-1)); 111 return -1; 112 } 113 114 int result = dwarf_cfi_addrframe (cfi, pc - stuff->bias, &stuff->frame); 115 if (result != 0) 116 { 117 printf ("dwarf_cfi_addrframe (%s): %s\n", which, dwarf_errmsg (-1)); 118 return 1; 119 } 120 121 Dwarf_Addr start = pc; 122 Dwarf_Addr end = pc; 123 bool signalp; 124 int ra_regno = dwarf_frame_info (stuff->frame, &start, &end, &signalp); 125 if (ra_regno >= 0) 126 { 127 start += stuff->bias; 128 end += stuff->bias; 129 } 130 131 printf ("%s has %#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "):\n", 132 which, pc, start, end); 133 134 if (ra_regno < 0) 135 printf ("\treturn address register unavailable (%s)\n", 136 dwarf_errmsg (0)); 137 else 138 printf ("\treturn address in reg%u%s\n", 139 ra_regno, signalp ? " (signal frame)" : ""); 140 141 // Point cfa_ops to dummy to match print_detail expectations. 142 // (nops == 0 && cfa_ops != NULL => "undefined") 143 Dwarf_Op dummy; 144 Dwarf_Op *cfa_ops = &dummy; 145 size_t cfa_nops; 146 result = dwarf_frame_cfa (stuff->frame, &cfa_ops, &cfa_nops); 147 148 printf ("\tCFA "); 149 print_detail (result, cfa_ops, cfa_nops, stuff->bias); 150 151 (void) dwfl_module_register_names (dwfl_addrmodule (dwfl, pc), 152 &print_register, stuff); 153 154 return 0; 155 } 156 157 static int 158 handle_address (GElf_Addr pc, Dwfl *dwfl) 159 { 160 Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc); 161 162 struct stuff stuff; 163 stuff.frame = NULL; 164 stuff.bias = 0; 165 int res = handle_cfi (dwfl, ".eh_frame", 166 dwfl_module_eh_cfi (mod, &stuff.bias), pc, &stuff); 167 free (stuff.frame); 168 169 stuff.frame = NULL; 170 stuff.bias = 0; 171 res &= handle_cfi (dwfl, ".debug_frame", 172 dwfl_module_dwarf_cfi (mod, &stuff.bias), pc, &stuff); 173 free (stuff.frame); 174 175 return res; 176 } 177 178 int 179 main (int argc, char *argv[]) 180 { 181 int remaining; 182 183 /* Set locale. */ 184 (void) setlocale (LC_ALL, ""); 185 186 Dwfl *dwfl = NULL; 187 (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining, &dwfl); 188 assert (dwfl != NULL); 189 190 int result = 0; 191 192 /* Now handle the addresses. In case none are given on the command 193 line, read from stdin. */ 194 if (remaining == argc) 195 { 196 /* We use no threads here which can interfere with handling a stream. */ 197 (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER); 198 199 char *buf = NULL; 200 size_t len = 0; 201 while (!feof_unlocked (stdin)) 202 { 203 if (getline (&buf, &len, stdin) < 0) 204 break; 205 206 char *endp; 207 uintmax_t addr = strtoumax (buf, &endp, 0); 208 if (endp != buf) 209 result |= handle_address (addr, dwfl); 210 else 211 result = 1; 212 } 213 214 free (buf); 215 } 216 else 217 { 218 do 219 { 220 char *endp; 221 uintmax_t addr = strtoumax (argv[remaining], &endp, 0); 222 if (endp != argv[remaining]) 223 result |= handle_address (addr, dwfl); 224 else 225 result = 1; 226 } 227 while (++remaining < argc); 228 } 229 230 dwfl_end (dwfl); 231 232 return result; 233 } 234