Brian Silverman | 8649792 | 2018-02-10 19:28:39 -0500 | [diff] [blame] | 1 | /* Test program for libdwfl basic module tracking, relocation. |
| 2 | Copyright (C) 2005, 2007 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 <sys/types.h> |
| 22 | #include <stdio.h> |
| 23 | #include <stdio_ext.h> |
| 24 | #include <stdlib.h> |
| 25 | #include <string.h> |
| 26 | #include <error.h> |
| 27 | #include <locale.h> |
| 28 | #include <argp.h> |
| 29 | #include ELFUTILS_HEADER(dwfl) |
| 30 | #include <dwarf.h> |
| 31 | |
| 32 | static bool show_inlines; |
| 33 | |
| 34 | struct info |
| 35 | { |
| 36 | Dwarf_Die *cudie; |
| 37 | Dwarf_Addr dwbias; |
| 38 | }; |
| 39 | |
| 40 | static int |
| 41 | print_instance (Dwarf_Die *instance, void *arg) |
| 42 | { |
| 43 | const struct info *info = arg; |
| 44 | |
| 45 | printf (" inlined"); |
| 46 | |
| 47 | Dwarf_Files *files; |
| 48 | if (dwarf_getsrcfiles (info->cudie, &files, NULL) == 0) |
| 49 | { |
| 50 | Dwarf_Attribute attr_mem; |
| 51 | Dwarf_Word val; |
| 52 | if (dwarf_formudata (dwarf_attr (instance, DW_AT_call_file, |
| 53 | &attr_mem), &val) == 0) |
| 54 | { |
| 55 | const char *file = dwarf_filesrc (files, val, NULL, NULL); |
| 56 | int lineno = 0, colno = 0; |
| 57 | if (dwarf_formudata (dwarf_attr (instance, DW_AT_call_line, |
| 58 | &attr_mem), &val) == 0) |
| 59 | lineno = val; |
| 60 | if (dwarf_formudata (dwarf_attr (instance, DW_AT_call_column, |
| 61 | &attr_mem), &val) == 0) |
| 62 | colno = val; |
| 63 | if (lineno == 0) |
| 64 | { |
| 65 | if (file != NULL) |
| 66 | printf (" from %s", file); |
| 67 | } |
| 68 | else if (colno == 0) |
| 69 | printf (" at %s:%u", file, lineno); |
| 70 | else |
| 71 | printf (" at %s:%u:%u", file, lineno, colno); |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | Dwarf_Addr lo = -1, hi = -1, entry = -1; |
| 76 | if (dwarf_lowpc (instance, &lo) == 0) |
| 77 | lo += info->dwbias; |
| 78 | else |
| 79 | printf (" (lowpc => %s)", dwarf_errmsg (-1)); |
| 80 | if (dwarf_highpc (instance, &hi) == 0) |
| 81 | hi += info->dwbias; |
| 82 | else |
| 83 | printf (" (highpc => %s)", dwarf_errmsg (-1)); |
| 84 | |
| 85 | Dwarf_Attribute attr_mem; |
| 86 | Dwarf_Attribute *attr = dwarf_attr (instance, DW_AT_entry_pc, &attr_mem); |
| 87 | if (attr != NULL) |
| 88 | { |
| 89 | if (dwarf_formaddr (attr, &entry) == 0) |
| 90 | entry += info->dwbias; |
| 91 | else |
| 92 | printf (" (entrypc => %s)", dwarf_errmsg (-1)); |
| 93 | } |
| 94 | |
| 95 | if (lo != (Dwarf_Addr) -1 || hi != (Dwarf_Addr) -1) |
| 96 | printf (" %#" PRIx64 "..%#" PRIx64, lo, hi); |
| 97 | if (entry != (Dwarf_Addr) -1) |
| 98 | printf (" => %#" PRIx64 "\n", entry); |
| 99 | else |
| 100 | puts (""); |
| 101 | |
| 102 | return DWARF_CB_OK; |
| 103 | } |
| 104 | |
| 105 | static void |
| 106 | print_inline (Dwarf_Die *func, void *arg) |
| 107 | { |
| 108 | if (dwarf_func_inline_instances (func, &print_instance, arg) != 0) |
| 109 | printf (" error finding instances: %s\n", dwarf_errmsg (-1)); |
| 110 | } |
| 111 | |
| 112 | static int |
| 113 | print_func (Dwarf_Die *func, void *arg) |
| 114 | { |
| 115 | const struct info *info = arg; |
| 116 | |
| 117 | const char *file = dwarf_decl_file (func); |
| 118 | int line = -1; |
| 119 | dwarf_decl_line (func, &line); |
| 120 | const char *fct = dwarf_diename (func); |
| 121 | |
| 122 | printf (" %s:%d: %s:", file, line, fct); |
| 123 | |
| 124 | if (dwarf_func_inline (func)) |
| 125 | { |
| 126 | puts (" inline function"); |
| 127 | if (show_inlines) |
| 128 | print_inline (func, arg); |
| 129 | } |
| 130 | else |
| 131 | { |
| 132 | Dwarf_Addr lo = -1, hi = -1, entry = -1; |
| 133 | if (dwarf_lowpc (func, &lo) == 0) |
| 134 | lo += info->dwbias; |
| 135 | else |
| 136 | printf (" (lowpc => %s)", dwarf_errmsg (-1)); |
| 137 | if (dwarf_highpc (func, &hi) == 0) |
| 138 | hi += info->dwbias; |
| 139 | else |
| 140 | printf (" (highpc => %s)", dwarf_errmsg (-1)); |
| 141 | if (dwarf_entrypc (func, &entry) == 0) |
| 142 | entry += info->dwbias; |
| 143 | else |
| 144 | printf (" (entrypc => %s)", dwarf_errmsg (-1)); |
| 145 | |
| 146 | if (lo != (Dwarf_Addr) -1 || hi != (Dwarf_Addr) -1 |
| 147 | || entry != (Dwarf_Addr) -1) |
| 148 | printf (" %#" PRIx64 "..%#" PRIx64 " => %#" PRIx64 "\n", |
| 149 | lo, hi, entry); |
| 150 | else |
| 151 | puts (""); |
| 152 | } |
| 153 | |
| 154 | return DWARF_CB_OK; |
| 155 | } |
| 156 | |
| 157 | static int |
| 158 | list_module (Dwfl_Module *mod __attribute__ ((unused)), |
| 159 | void **userdata __attribute__ ((unused)), |
| 160 | const char *name, Dwarf_Addr base, |
| 161 | void *arg __attribute__ ((unused))) |
| 162 | { |
| 163 | Dwarf_Addr start; |
| 164 | Dwarf_Addr end; |
| 165 | const char *file; |
| 166 | const char *debug; |
| 167 | if (dwfl_module_info (mod, NULL, &start, &end, |
| 168 | NULL, NULL, &file, &debug) != name |
| 169 | || start != base) |
| 170 | abort (); |
| 171 | printf ("module: %30s %08" PRIx64 "..%08" PRIx64 " %s %s\n", |
| 172 | name, start, end, file, debug); |
| 173 | return DWARF_CB_OK; |
| 174 | } |
| 175 | |
| 176 | static int |
| 177 | print_module (Dwfl_Module *mod __attribute__ ((unused)), |
| 178 | void **userdata __attribute__ ((unused)), |
| 179 | const char *name, Dwarf_Addr base, |
| 180 | Dwarf *dw, Dwarf_Addr bias, |
| 181 | void *arg) |
| 182 | { |
| 183 | printf ("module: %30s %08" PRIx64 " %s %" PRIx64 " (%s)\n", |
| 184 | name, base, dw == NULL ? "no" : "DWARF", bias, dwfl_errmsg (-1)); |
| 185 | |
| 186 | if (dw != NULL && *(const bool *) arg) |
| 187 | { |
| 188 | Dwarf_Off off = 0; |
| 189 | size_t cuhl; |
| 190 | Dwarf_Off noff; |
| 191 | |
| 192 | while (dwarf_nextcu (dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0) |
| 193 | { |
| 194 | Dwarf_Die die_mem; |
| 195 | struct info info = { dwarf_offdie (dw, off + cuhl, &die_mem), bias }; |
| 196 | (void) dwarf_getfuncs (info.cudie, print_func, &info, 0); |
| 197 | |
| 198 | off = noff; |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | return DWARF_CB_OK; |
| 203 | } |
| 204 | |
| 205 | static bool show_functions; |
| 206 | |
| 207 | /* gettext helper macro. */ |
| 208 | #undef N_ |
| 209 | #define N_(Str) Str |
| 210 | |
| 211 | static const struct argp_option options[] = |
| 212 | { |
| 213 | { "functions", 'f', NULL, 0, N_("Additionally show function names"), 0 }, |
| 214 | { "inlines", 'i', NULL, 0, N_("Show instances of inlined functions"), 0 }, |
| 215 | { NULL, 0, NULL, 0, NULL, 0 } |
| 216 | }; |
| 217 | |
| 218 | static error_t |
| 219 | parse_opt (int key, char *arg __attribute__ ((unused)), |
| 220 | struct argp_state *state __attribute__ ((unused))) |
| 221 | { |
| 222 | switch (key) |
| 223 | { |
| 224 | case ARGP_KEY_INIT: |
| 225 | state->child_inputs[0] = state->input; |
| 226 | break; |
| 227 | |
| 228 | case 'f': |
| 229 | show_functions = true; |
| 230 | break; |
| 231 | |
| 232 | case 'i': |
| 233 | show_inlines = show_functions = true; |
| 234 | break; |
| 235 | |
| 236 | default: |
| 237 | return ARGP_ERR_UNKNOWN; |
| 238 | } |
| 239 | return 0; |
| 240 | } |
| 241 | |
| 242 | int |
| 243 | main (int argc, char **argv) |
| 244 | { |
| 245 | /* We use no threads here which can interfere with handling a stream. */ |
| 246 | (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); |
| 247 | |
| 248 | /* Set locale. */ |
| 249 | (void) setlocale (LC_ALL, ""); |
| 250 | |
| 251 | Dwfl *dwfl = NULL; |
| 252 | const struct argp_child argp_children[] = |
| 253 | { |
| 254 | { .argp = dwfl_standard_argp () }, |
| 255 | { .argp = NULL } |
| 256 | }; |
| 257 | const struct argp argp = |
| 258 | { |
| 259 | options, parse_opt, NULL, NULL, argp_children, NULL, NULL |
| 260 | }; |
| 261 | (void) argp_parse (&argp, argc, argv, 0, NULL, &dwfl); |
| 262 | assert (dwfl != NULL); |
| 263 | |
| 264 | ptrdiff_t p = 0; |
| 265 | do |
| 266 | p = dwfl_getmodules (dwfl, &list_module, NULL, p); |
| 267 | while (p > 0); |
| 268 | if (p < 0) |
| 269 | error (2, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1)); |
| 270 | |
| 271 | do |
| 272 | p = dwfl_getdwarf (dwfl, &print_module, &show_functions, p); |
| 273 | while (p > 0); |
| 274 | if (p < 0) |
| 275 | error (2, 0, "dwfl_getdwarf: %s", dwfl_errmsg (-1)); |
| 276 | |
| 277 | p = 0; |
| 278 | do |
| 279 | p = dwfl_getmodules (dwfl, &list_module, NULL, p); |
| 280 | while (p > 0); |
| 281 | if (p < 0) |
| 282 | error (2, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1)); |
| 283 | |
| 284 | dwfl_end (dwfl); |
| 285 | |
| 286 | return 0; |
| 287 | } |