1da0c48c4Sopenharmony_ci/* Test program for libdwfl basic module tracking, relocation.
2da0c48c4Sopenharmony_ci   Copyright (C) 2005, 2007 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci
5da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
6da0c48c4Sopenharmony_ci   it under the terms of the GNU General Public License as published by
7da0c48c4Sopenharmony_ci   the Free Software Foundation; either version 3 of the License, or
8da0c48c4Sopenharmony_ci   (at your option) any later version.
9da0c48c4Sopenharmony_ci
10da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
11da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
12da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13da0c48c4Sopenharmony_ci   GNU General Public License for more details.
14da0c48c4Sopenharmony_ci
15da0c48c4Sopenharmony_ci   You should have received a copy of the GNU General Public License
16da0c48c4Sopenharmony_ci   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17da0c48c4Sopenharmony_ci
18da0c48c4Sopenharmony_ci#include <config.h>
19da0c48c4Sopenharmony_ci#include <assert.h>
20da0c48c4Sopenharmony_ci#include <inttypes.h>
21da0c48c4Sopenharmony_ci#include <sys/types.h>
22da0c48c4Sopenharmony_ci#include <stdio.h>
23da0c48c4Sopenharmony_ci#include <stdio_ext.h>
24da0c48c4Sopenharmony_ci#include <stdlib.h>
25da0c48c4Sopenharmony_ci#include <string.h>
26da0c48c4Sopenharmony_ci#include <locale.h>
27da0c48c4Sopenharmony_ci#include <argp.h>
28da0c48c4Sopenharmony_ci#include ELFUTILS_HEADER(dwfl)
29da0c48c4Sopenharmony_ci#include <dwarf.h>
30da0c48c4Sopenharmony_ci#include "system.h"
31da0c48c4Sopenharmony_ci
32da0c48c4Sopenharmony_cistatic bool show_inlines;
33da0c48c4Sopenharmony_ci
34da0c48c4Sopenharmony_cistruct info
35da0c48c4Sopenharmony_ci{
36da0c48c4Sopenharmony_ci  Dwarf_Die *cudie;
37da0c48c4Sopenharmony_ci  Dwarf_Addr dwbias;
38da0c48c4Sopenharmony_ci};
39da0c48c4Sopenharmony_ci
40da0c48c4Sopenharmony_cistatic int
41da0c48c4Sopenharmony_ciprint_instance (Dwarf_Die *instance, void *arg)
42da0c48c4Sopenharmony_ci{
43da0c48c4Sopenharmony_ci  const struct info *info = arg;
44da0c48c4Sopenharmony_ci
45da0c48c4Sopenharmony_ci  printf ("    inlined");
46da0c48c4Sopenharmony_ci
47da0c48c4Sopenharmony_ci  Dwarf_Files *files;
48da0c48c4Sopenharmony_ci  if (dwarf_getsrcfiles (info->cudie, &files, NULL) == 0)
49da0c48c4Sopenharmony_ci    {
50da0c48c4Sopenharmony_ci      Dwarf_Attribute attr_mem;
51da0c48c4Sopenharmony_ci      Dwarf_Word val;
52da0c48c4Sopenharmony_ci      if (dwarf_formudata (dwarf_attr (instance, DW_AT_call_file,
53da0c48c4Sopenharmony_ci				       &attr_mem), &val) == 0)
54da0c48c4Sopenharmony_ci	{
55da0c48c4Sopenharmony_ci	  const char *file = dwarf_filesrc (files, val, NULL, NULL);
56da0c48c4Sopenharmony_ci	  int lineno = 0, colno = 0;
57da0c48c4Sopenharmony_ci	  if (dwarf_formudata (dwarf_attr (instance, DW_AT_call_line,
58da0c48c4Sopenharmony_ci					   &attr_mem), &val) == 0)
59da0c48c4Sopenharmony_ci	    lineno = val;
60da0c48c4Sopenharmony_ci	  if (dwarf_formudata (dwarf_attr (instance, DW_AT_call_column,
61da0c48c4Sopenharmony_ci					   &attr_mem), &val) == 0)
62da0c48c4Sopenharmony_ci	    colno = val;
63da0c48c4Sopenharmony_ci	  if (lineno == 0)
64da0c48c4Sopenharmony_ci	    {
65da0c48c4Sopenharmony_ci	      if (file != NULL)
66da0c48c4Sopenharmony_ci		printf (" from %s", file);
67da0c48c4Sopenharmony_ci	    }
68da0c48c4Sopenharmony_ci	  else if (colno == 0)
69da0c48c4Sopenharmony_ci	    printf (" at %s:%u", file, lineno);
70da0c48c4Sopenharmony_ci	  else
71da0c48c4Sopenharmony_ci	    printf (" at %s:%u:%u", file, lineno, colno);
72da0c48c4Sopenharmony_ci	}
73da0c48c4Sopenharmony_ci    }
74da0c48c4Sopenharmony_ci
75da0c48c4Sopenharmony_ci  Dwarf_Addr lo = -1, hi = -1, entry = -1;
76da0c48c4Sopenharmony_ci  if (dwarf_lowpc (instance, &lo) == 0)
77da0c48c4Sopenharmony_ci    lo += info->dwbias;
78da0c48c4Sopenharmony_ci  else
79da0c48c4Sopenharmony_ci    printf (" (lowpc => %s)", dwarf_errmsg (-1));
80da0c48c4Sopenharmony_ci  if (dwarf_highpc (instance, &hi) == 0)
81da0c48c4Sopenharmony_ci    hi += info->dwbias;
82da0c48c4Sopenharmony_ci  else
83da0c48c4Sopenharmony_ci    printf (" (highpc => %s)", dwarf_errmsg (-1));
84da0c48c4Sopenharmony_ci
85da0c48c4Sopenharmony_ci  Dwarf_Attribute attr_mem;
86da0c48c4Sopenharmony_ci  Dwarf_Attribute *attr = dwarf_attr (instance, DW_AT_entry_pc, &attr_mem);
87da0c48c4Sopenharmony_ci  if (attr != NULL)
88da0c48c4Sopenharmony_ci    {
89da0c48c4Sopenharmony_ci      if (dwarf_formaddr (attr, &entry) == 0)
90da0c48c4Sopenharmony_ci	entry += info->dwbias;
91da0c48c4Sopenharmony_ci      else
92da0c48c4Sopenharmony_ci	printf (" (entrypc => %s)", dwarf_errmsg (-1));
93da0c48c4Sopenharmony_ci    }
94da0c48c4Sopenharmony_ci
95da0c48c4Sopenharmony_ci  if (lo != (Dwarf_Addr) -1 || hi != (Dwarf_Addr) -1)
96da0c48c4Sopenharmony_ci    printf (" %#" PRIx64 "..%#" PRIx64, lo, hi);
97da0c48c4Sopenharmony_ci  if (entry != (Dwarf_Addr) -1)
98da0c48c4Sopenharmony_ci    printf (" => %#" PRIx64 "\n", entry);
99da0c48c4Sopenharmony_ci  else
100da0c48c4Sopenharmony_ci    puts ("");
101da0c48c4Sopenharmony_ci
102da0c48c4Sopenharmony_ci  return DWARF_CB_OK;
103da0c48c4Sopenharmony_ci}
104da0c48c4Sopenharmony_ci
105da0c48c4Sopenharmony_cistatic void
106da0c48c4Sopenharmony_ciprint_inline (Dwarf_Die *func, void *arg)
107da0c48c4Sopenharmony_ci{
108da0c48c4Sopenharmony_ci  if (dwarf_func_inline_instances (func, &print_instance, arg) != 0)
109da0c48c4Sopenharmony_ci    printf ("  error finding instances: %s\n", dwarf_errmsg (-1));
110da0c48c4Sopenharmony_ci}
111da0c48c4Sopenharmony_ci
112da0c48c4Sopenharmony_cistatic int
113da0c48c4Sopenharmony_ciprint_func (Dwarf_Die *func, void *arg)
114da0c48c4Sopenharmony_ci{
115da0c48c4Sopenharmony_ci  const struct info *info = arg;
116da0c48c4Sopenharmony_ci
117da0c48c4Sopenharmony_ci  const char *file = dwarf_decl_file (func);
118da0c48c4Sopenharmony_ci  int line = -1;
119da0c48c4Sopenharmony_ci  dwarf_decl_line (func, &line);
120da0c48c4Sopenharmony_ci  const char *fct = dwarf_diename (func);
121da0c48c4Sopenharmony_ci
122da0c48c4Sopenharmony_ci  printf ("  %s:%d: %s:", file, line, fct);
123da0c48c4Sopenharmony_ci
124da0c48c4Sopenharmony_ci  if (dwarf_func_inline (func))
125da0c48c4Sopenharmony_ci    {
126da0c48c4Sopenharmony_ci      puts (" inline function");
127da0c48c4Sopenharmony_ci      if (show_inlines)
128da0c48c4Sopenharmony_ci	print_inline (func, arg);
129da0c48c4Sopenharmony_ci    }
130da0c48c4Sopenharmony_ci  else
131da0c48c4Sopenharmony_ci    {
132da0c48c4Sopenharmony_ci      Dwarf_Addr lo = -1, hi = -1, entry = -1;
133da0c48c4Sopenharmony_ci      if (dwarf_lowpc (func, &lo) == 0)
134da0c48c4Sopenharmony_ci	lo += info->dwbias;
135da0c48c4Sopenharmony_ci      else
136da0c48c4Sopenharmony_ci	printf (" (lowpc => %s)", dwarf_errmsg (-1));
137da0c48c4Sopenharmony_ci      if (dwarf_highpc (func, &hi) == 0)
138da0c48c4Sopenharmony_ci	hi += info->dwbias;
139da0c48c4Sopenharmony_ci      else
140da0c48c4Sopenharmony_ci	printf (" (highpc => %s)", dwarf_errmsg (-1));
141da0c48c4Sopenharmony_ci      if (dwarf_entrypc (func, &entry) == 0)
142da0c48c4Sopenharmony_ci	entry += info->dwbias;
143da0c48c4Sopenharmony_ci      else
144da0c48c4Sopenharmony_ci	printf (" (entrypc => %s)", dwarf_errmsg (-1));
145da0c48c4Sopenharmony_ci
146da0c48c4Sopenharmony_ci      if (lo != (Dwarf_Addr) -1 || hi != (Dwarf_Addr) -1
147da0c48c4Sopenharmony_ci	  || entry != (Dwarf_Addr) -1)
148da0c48c4Sopenharmony_ci	printf (" %#" PRIx64 "..%#" PRIx64 " => %#" PRIx64 "\n",
149da0c48c4Sopenharmony_ci		lo, hi, entry);
150da0c48c4Sopenharmony_ci      else
151da0c48c4Sopenharmony_ci	puts ("");
152da0c48c4Sopenharmony_ci    }
153da0c48c4Sopenharmony_ci
154da0c48c4Sopenharmony_ci  return DWARF_CB_OK;
155da0c48c4Sopenharmony_ci}
156da0c48c4Sopenharmony_ci
157da0c48c4Sopenharmony_cistatic int
158da0c48c4Sopenharmony_cilist_module (Dwfl_Module *mod __attribute__ ((unused)),
159da0c48c4Sopenharmony_ci	     void **userdata __attribute__ ((unused)),
160da0c48c4Sopenharmony_ci	     const char *name, Dwarf_Addr base,
161da0c48c4Sopenharmony_ci	     void *arg __attribute__ ((unused)))
162da0c48c4Sopenharmony_ci{
163da0c48c4Sopenharmony_ci  Dwarf_Addr start;
164da0c48c4Sopenharmony_ci  Dwarf_Addr end;
165da0c48c4Sopenharmony_ci  const char *file;
166da0c48c4Sopenharmony_ci  const char *debug;
167da0c48c4Sopenharmony_ci  if (dwfl_module_info (mod, NULL, &start, &end,
168da0c48c4Sopenharmony_ci			NULL, NULL, &file, &debug) != name
169da0c48c4Sopenharmony_ci      || start != base)
170da0c48c4Sopenharmony_ci    abort ();
171da0c48c4Sopenharmony_ci  printf ("module: %30s %08" PRIx64 "..%08" PRIx64 " %s %s\n",
172da0c48c4Sopenharmony_ci	  name, start, end, file, debug);
173da0c48c4Sopenharmony_ci  return DWARF_CB_OK;
174da0c48c4Sopenharmony_ci}
175da0c48c4Sopenharmony_ci
176da0c48c4Sopenharmony_cistatic int
177da0c48c4Sopenharmony_ciprint_module (Dwfl_Module *mod __attribute__ ((unused)),
178da0c48c4Sopenharmony_ci	      void **userdata __attribute__ ((unused)),
179da0c48c4Sopenharmony_ci	      const char *name, Dwarf_Addr base,
180da0c48c4Sopenharmony_ci	      Dwarf *dw, Dwarf_Addr bias,
181da0c48c4Sopenharmony_ci	      void *arg)
182da0c48c4Sopenharmony_ci{
183da0c48c4Sopenharmony_ci  printf ("module: %30s %08" PRIx64 " %s %" PRIx64 " (%s)\n",
184da0c48c4Sopenharmony_ci	  name, base, dw == NULL ? "no" : "DWARF", bias, dwfl_errmsg (-1));
185da0c48c4Sopenharmony_ci
186da0c48c4Sopenharmony_ci  if (dw != NULL && *(const bool *) arg)
187da0c48c4Sopenharmony_ci    {
188da0c48c4Sopenharmony_ci      Dwarf_Off off = 0;
189da0c48c4Sopenharmony_ci      size_t cuhl;
190da0c48c4Sopenharmony_ci      Dwarf_Off noff;
191da0c48c4Sopenharmony_ci
192da0c48c4Sopenharmony_ci      while (dwarf_nextcu (dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0)
193da0c48c4Sopenharmony_ci	{
194da0c48c4Sopenharmony_ci	  Dwarf_Die die_mem;
195da0c48c4Sopenharmony_ci	  struct info info = { dwarf_offdie (dw, off + cuhl, &die_mem), bias };
196da0c48c4Sopenharmony_ci	  (void) dwarf_getfuncs (info.cudie, print_func, &info, 0);
197da0c48c4Sopenharmony_ci
198da0c48c4Sopenharmony_ci	  off = noff;
199da0c48c4Sopenharmony_ci	}
200da0c48c4Sopenharmony_ci    }
201da0c48c4Sopenharmony_ci
202da0c48c4Sopenharmony_ci  return DWARF_CB_OK;
203da0c48c4Sopenharmony_ci}
204da0c48c4Sopenharmony_ci
205da0c48c4Sopenharmony_cistatic bool show_functions;
206da0c48c4Sopenharmony_ci
207da0c48c4Sopenharmony_cistatic const struct argp_option options[] =
208da0c48c4Sopenharmony_ci  {
209da0c48c4Sopenharmony_ci    { "functions", 'f', NULL, 0, N_("Additionally show function names"), 0 },
210da0c48c4Sopenharmony_ci    { "inlines", 'i', NULL, 0, N_("Show instances of inlined functions"), 0 },
211da0c48c4Sopenharmony_ci    { NULL, 0, NULL, 0, NULL, 0 }
212da0c48c4Sopenharmony_ci  };
213da0c48c4Sopenharmony_ci
214da0c48c4Sopenharmony_cistatic error_t
215da0c48c4Sopenharmony_ciparse_opt (int key, char *arg __attribute__ ((unused)),
216da0c48c4Sopenharmony_ci	   struct argp_state *state __attribute__ ((unused)))
217da0c48c4Sopenharmony_ci{
218da0c48c4Sopenharmony_ci  switch (key)
219da0c48c4Sopenharmony_ci    {
220da0c48c4Sopenharmony_ci    case ARGP_KEY_INIT:
221da0c48c4Sopenharmony_ci      state->child_inputs[0] = state->input;
222da0c48c4Sopenharmony_ci      break;
223da0c48c4Sopenharmony_ci
224da0c48c4Sopenharmony_ci    case 'f':
225da0c48c4Sopenharmony_ci      show_functions = true;
226da0c48c4Sopenharmony_ci      break;
227da0c48c4Sopenharmony_ci
228da0c48c4Sopenharmony_ci    case 'i':
229da0c48c4Sopenharmony_ci      show_inlines = show_functions = true;
230da0c48c4Sopenharmony_ci      break;
231da0c48c4Sopenharmony_ci
232da0c48c4Sopenharmony_ci    default:
233da0c48c4Sopenharmony_ci      return ARGP_ERR_UNKNOWN;
234da0c48c4Sopenharmony_ci    }
235da0c48c4Sopenharmony_ci  return 0;
236da0c48c4Sopenharmony_ci}
237da0c48c4Sopenharmony_ci
238da0c48c4Sopenharmony_ciint
239da0c48c4Sopenharmony_cimain (int argc, char **argv)
240da0c48c4Sopenharmony_ci{
241da0c48c4Sopenharmony_ci  /* We use no threads here which can interfere with handling a stream.  */
242da0c48c4Sopenharmony_ci  (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
243da0c48c4Sopenharmony_ci
244da0c48c4Sopenharmony_ci  /* Set locale.  */
245da0c48c4Sopenharmony_ci  (void) setlocale (LC_ALL, "");
246da0c48c4Sopenharmony_ci
247da0c48c4Sopenharmony_ci  Dwfl *dwfl = NULL;
248da0c48c4Sopenharmony_ci  const struct argp_child argp_children[] =
249da0c48c4Sopenharmony_ci    {
250da0c48c4Sopenharmony_ci      { .argp = dwfl_standard_argp () },
251da0c48c4Sopenharmony_ci      { .argp = NULL }
252da0c48c4Sopenharmony_ci    };
253da0c48c4Sopenharmony_ci  const struct argp argp =
254da0c48c4Sopenharmony_ci    {
255da0c48c4Sopenharmony_ci      options, parse_opt, NULL, NULL, argp_children, NULL, NULL
256da0c48c4Sopenharmony_ci    };
257da0c48c4Sopenharmony_ci  (void) argp_parse (&argp, argc, argv, 0, NULL, &dwfl);
258da0c48c4Sopenharmony_ci  assert (dwfl != NULL);
259da0c48c4Sopenharmony_ci
260da0c48c4Sopenharmony_ci  ptrdiff_t p = 0;
261da0c48c4Sopenharmony_ci  do
262da0c48c4Sopenharmony_ci    p = dwfl_getmodules (dwfl, &list_module, NULL, p);
263da0c48c4Sopenharmony_ci  while (p > 0);
264da0c48c4Sopenharmony_ci  if (p < 0)
265da0c48c4Sopenharmony_ci    error (2, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
266da0c48c4Sopenharmony_ci
267da0c48c4Sopenharmony_ci  do
268da0c48c4Sopenharmony_ci    p = dwfl_getdwarf (dwfl, &print_module, &show_functions, p);
269da0c48c4Sopenharmony_ci  while (p > 0);
270da0c48c4Sopenharmony_ci  if (p < 0)
271da0c48c4Sopenharmony_ci    error (2, 0, "dwfl_getdwarf: %s", dwfl_errmsg (-1));
272da0c48c4Sopenharmony_ci
273da0c48c4Sopenharmony_ci  p = 0;
274da0c48c4Sopenharmony_ci  do
275da0c48c4Sopenharmony_ci    p = dwfl_getmodules (dwfl, &list_module, NULL, p);
276da0c48c4Sopenharmony_ci  while (p > 0);
277da0c48c4Sopenharmony_ci  if (p < 0)
278da0c48c4Sopenharmony_ci    error (2, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
279da0c48c4Sopenharmony_ci
280da0c48c4Sopenharmony_ci  dwfl_end (dwfl);
281da0c48c4Sopenharmony_ci
282da0c48c4Sopenharmony_ci  return 0;
283da0c48c4Sopenharmony_ci}
284