Imported Upstream version 0.160
[platform/upstream/elfutils.git] / tests / addrcfi.c
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 }