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