Imported Upstream version 0.153
[platform/upstream/elfutils.git] / tests / addrcfi.c
1 /* Test program for CFI handling.
2    Copyright (C) 2009-2010 Red Hat, Inc.
3    This file is part of Red Hat elfutils.
4
5    Red Hat elfutils is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by the
7    Free Software Foundation; version 2 of the License.
8
9    Red Hat elfutils is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public License along
15    with Red Hat elfutils; if not, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
17
18    Red Hat elfutils is an included package of the Open Invention Network.
19    An included package of the Open Invention Network is a package for which
20    Open Invention Network licensees cross-license their patents.  No patent
21    license is granted, either expressly or impliedly, by designation as an
22    included package.  Should you wish to participate in the Open Invention
23    Network licensing program, please visit www.openinventionnetwork.com
24    <http://www.openinventionnetwork.com>.  */
25
26 #include <config.h>
27 #include <assert.h>
28 #include <inttypes.h>
29 #include ELFUTILS_HEADER(dwfl)
30 #include <dwarf.h>
31 #include <argp.h>
32 #include <stdio.h>
33 #include <stdio_ext.h>
34 #include <locale.h>
35 #include <stdlib.h>
36 #include <error.h>
37 #include <string.h>
38
39
40 static void
41 print_detail (int result, const Dwarf_Op *ops, size_t nops, Dwarf_Addr bias)
42 {
43   if (result < 0)
44     printf ("indeterminate (%s)\n", dwarf_errmsg (-1));
45   else if (nops == 0)
46     printf ("%s\n", result == 0 ? "same_value" : "undefined");
47   else
48     {
49       printf ("%s expression:", result == 0 ? "location" : "value");
50       for (size_t i = 0; i < nops; ++i)
51         {
52           printf (" %#x", ops[i].atom);
53           if (ops[i].number2 == 0)
54             {
55               if (ops[i].atom == DW_OP_addr)
56                 printf ("(%#" PRIx64 ")", ops[i].number + bias);
57               else if (ops[i].number != 0)
58                 printf ("(%" PRId64 ")", ops[i].number);
59             }
60           else
61             printf ("(%" PRId64 ",%" PRId64 ")",
62                     ops[i].number, ops[i].number2);
63         }
64       puts ("");
65     }
66 }
67
68 struct stuff
69 {
70   Dwarf_Frame *frame;
71   Dwarf_Addr bias;
72 };
73
74 static int
75 print_register (void *arg,
76                 int regno,
77                 const char *setname,
78                 const char *prefix,
79                 const char *regname,
80                 int bits __attribute__ ((unused)),
81                 int type __attribute__ ((unused)))
82 {
83   struct stuff *stuff = arg;
84
85   printf ("\t%s reg%u (%s%s): ", setname, regno, prefix, regname);
86
87   Dwarf_Op ops_mem[2];
88   Dwarf_Op *ops;
89   size_t nops;
90   int result = dwarf_frame_register (stuff->frame, regno, ops_mem, &ops, &nops);
91   print_detail (result, ops, nops, stuff->bias);
92
93   return DWARF_CB_OK;
94 }
95
96 static int
97 handle_cfi (Dwfl *dwfl, const char *which, Dwarf_CFI *cfi,
98             GElf_Addr pc, struct stuff *stuff)
99 {
100   int result = dwarf_cfi_addrframe (cfi, pc - stuff->bias, &stuff->frame);
101   if (result != 0)
102     {
103       error (0, 0, "dwarf_cfi_addrframe (%s): %s", which, dwarf_errmsg (-1));
104       return 1;
105     }
106
107   Dwarf_Addr start = pc;
108   Dwarf_Addr end = pc;
109   bool signalp;
110   int ra_regno = dwarf_frame_info (stuff->frame, &start, &end, &signalp);
111   if (ra_regno >= 0)
112     {
113       start += stuff->bias;
114       end += stuff->bias;
115     }
116
117   printf ("%s has %#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "):\n",
118           which, pc, start, end);
119
120   if (ra_regno < 0)
121     printf ("\treturn address register unavailable (%s)\n",
122             dwarf_errmsg (0));
123   else
124     printf ("\treturn address in reg%u%s\n",
125             ra_regno, signalp ? " (signal frame)" : "");
126
127   Dwarf_Op *cfa_ops;
128   size_t cfa_nops;
129   result = dwarf_frame_cfa (stuff->frame, &cfa_ops, &cfa_nops);
130
131   printf ("\tCFA ");
132   print_detail (result, cfa_ops, cfa_nops, stuff->bias);
133
134   (void) dwfl_module_register_names (dwfl_addrmodule (dwfl, pc),
135                                      &print_register, stuff);
136
137   return 0;
138 }
139
140 static int
141 handle_address (GElf_Addr pc, Dwfl *dwfl)
142 {
143   Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc);
144
145   struct stuff stuff;
146   return (handle_cfi (dwfl, ".eh_frame",
147                       dwfl_module_eh_cfi (mod, &stuff.bias), pc, &stuff)
148           & handle_cfi (dwfl, ".debug_frame",
149                         dwfl_module_dwarf_cfi (mod, &stuff.bias), pc, &stuff));
150 }
151
152 int
153 main (int argc, char *argv[])
154 {
155   int remaining;
156
157   /* Set locale.  */
158   (void) setlocale (LC_ALL, "");
159
160   Dwfl *dwfl = NULL;
161   (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining, &dwfl);
162   assert (dwfl != NULL);
163
164   int result = 0;
165
166   /* Now handle the addresses.  In case none are given on the command
167      line, read from stdin.  */
168   if (remaining == argc)
169     {
170       /* We use no threads here which can interfere with handling a stream.  */
171       (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
172
173       char *buf = NULL;
174       size_t len = 0;
175       while (!feof_unlocked (stdin))
176         {
177           if (getline (&buf, &len, stdin) < 0)
178             break;
179
180           char *endp;
181           uintmax_t addr = strtoumax (buf, &endp, 0);
182           if (endp != buf)
183             result |= handle_address (addr, dwfl);
184           else
185             result = 1;
186         }
187
188       free (buf);
189     }
190   else
191     {
192       do
193         {
194           char *endp;
195           uintmax_t addr = strtoumax (argv[remaining], &endp, 0);
196           if (endp != argv[remaining])
197             result |= handle_address (addr, dwfl);
198           else
199             result = 1;
200         }
201       while (++remaining < argc);
202     }
203
204   dwfl_end (dwfl);
205
206   return result;
207 }