1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2020 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 /// @file
9 ///
10 /// This program takes parameters to open an elf file, lookup a symbol
11 /// in its symbol tables and report what it sees.
12 
13 #include <elf.h>
14 #include <cstring>
15 #include <iostream>
16 #include <sstream>
17 #include "abg-config.h"
18 #include "abg-dwarf-reader.h"
19 #include "abg-ir.h"
20 #include "abg-tools-utils.h"
21 
22 using std::cout;
23 using std::cerr;
24 using std::string;
25 using std::ostream;
26 using std::ostringstream;
27 using std::vector;
28 
29 using abigail::ir::environment;
30 using abigail::ir::environment_sptr;
31 using abigail::dwarf_reader::lookup_symbol_from_elf;
32 using abigail::elf_symbol;
33 using abigail::elf_symbol_sptr;
34 
35 struct options
36 {
37   bool	show_help;
38   bool	display_version;
39   char* elf_path;
40   char* symbol_name;
41   bool	demangle;
42   bool absolute_path;
43 
optionsoptions44   options()
45     : show_help(false),
46       display_version(false),
47       elf_path(0),
48       symbol_name(0),
49       demangle(false),
50       absolute_path(true)
51   {}
52 };
53 
54 static void
display_usage(const string & prog_name,ostream & out)55 display_usage(const string& prog_name, ostream &out)
56 {
57   out << "usage: " << prog_name << " [options] <elf file> <symbol-name>\n"
58       << "where [options] can be:\n"
59       << "  --help  display this help string\n"
60       << "  --version|-v  display program version information and exit\n"
61       << "  --demangle  demangle the symbols from the symbol table\n"
62       << "  --no-absolute-path  do not show absolute paths in messages\n";
63 }
64 
65 static void
parse_command_line(int argc,char * argv[],options & opts)66 parse_command_line(int argc, char* argv[], options& opts)
67 {
68   if (argc < 2)
69     {
70       opts.show_help = true;
71       return;
72     }
73 
74   for (int i = 1; i < argc; ++i)
75     {
76       if (argv[i][0] != '-')
77 	{
78 	  if (!opts.elf_path)
79 	    opts.elf_path = argv[i];
80 	  else if (!opts.symbol_name)
81 	    opts.symbol_name = argv[i] ;
82 	  else
83 	    {
84 	      opts.show_help = true;
85 	      return;
86 	    }
87 	}
88       else if (!strcmp(argv[i], "--help")
89 	       || !strcmp(argv[i], "-h"))
90 	{
91 	  opts.show_help = true;
92 	  return;
93 	}
94       else if (!strcmp(argv[i], "--version")
95 	       || !strcmp(argv[i], "-v"))
96 	{
97 	  opts.display_version = true;
98 	  return;
99 	}
100       else if (!strcmp(argv[i], "--demangle"))
101 	opts.demangle = true;
102       else if (!strcmp(argv[i], "--no-absolute-path"))
103 	opts.absolute_path = false;
104       else
105 	opts.show_help = true;
106     }
107 }
108 
109 int
main(int argc,char * argv[])110 main(int argc, char* argv[])
111 {
112   options opts;
113   parse_command_line(argc, argv, opts);
114 
115   if (opts.show_help)
116     {
117       display_usage(argv[0], cout);
118       return 1;
119     }
120 
121   if (opts.display_version)
122     {
123       abigail::tools_utils::emit_prefix(argv[0], cout)
124 	<< abigail::tools_utils::get_library_version_string();
125       return 0;
126     }
127 
128   assert(opts.elf_path != 0
129 	 && opts.symbol_name != 0);
130 
131   string p = opts.elf_path, n = opts.symbol_name;
132   environment_sptr env(new environment);
133   vector<elf_symbol_sptr> syms;
134   if (!lookup_symbol_from_elf(env.get(), p, n, opts.demangle, syms))
135     {
136       cout << "could not find symbol '"
137 	   << opts.symbol_name
138 	   << "' in file '";
139       if (opts.absolute_path)
140 	cout << opts.elf_path << "'\n";
141       else
142 	cout << basename(opts.elf_path);
143       return 0;
144     }
145 
146   elf_symbol_sptr sym = syms[0];
147   cout << "found symbol '" << n << "'";
148   if (n != sym->get_name())
149     cout << " (" << sym->get_name() << ")";
150   cout << ", an instance of "
151        << (elf_symbol::type) sym->get_type()
152        << " of " << sym->get_binding();
153   if (syms.size() > 1 || !sym->get_version().is_empty())
154     {
155       cout << ", of version";
156       if (syms.size () > 1)
157 	cout << "s";
158       cout << " ";
159       for (vector<elf_symbol_sptr>::const_iterator i = syms.begin();
160 	   i != syms.end();
161 	   ++i)
162 	{
163 	  if (i != syms.begin())
164 	    cout << ", ";
165 	  cout << "'" << (*i)->get_version().str() << "'";
166 	}
167     }
168   cout << '\n';
169 
170   return 0;
171 }
172