HPCToolkit
LinuxKernelSymbols.cpp
Go to the documentation of this file.
1 // -*-Mode: C++;-*-
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 //******************************************************************************
48 // system includes
49 //******************************************************************************
50 
51 #include <string.h>
52 #include <sys/stat.h>
53 
54 #include <iostream>
55 
56 //******************************************************************************
57 // local includes
58 //******************************************************************************
59 
60 #include <include/linux_info.h>
61 #include "LinuxKernelSymbols.hpp"
62 
63 #include "../support-lean/compress.h"
64 
65 
66 //******************************************************************************
67 // local operations
68 //******************************************************************************
69 
70 static std::string
71 getKernelFilename(const std::set<std::string> &directorySet, std::string virtual_name)
72 {
73  std::string path;
74 
75  // remove the fake symbol < and >
76  std::string fname = virtual_name.substr( 1, virtual_name.size()-2 );
77 
78  // check if any of the directory in the set has vmlinux.xxxx file
79  std::set<std::string>::iterator it;
80  for(it = directorySet.begin(); it != directorySet.end(); ++it) {
81  std::string dir = *it;
82  path = dir + "/" + KERNEL_SYMBOLS_DIRECTORY + "/" + fname;
83 
84  struct stat buffer;
85 
86  if (stat(path.c_str(), &buffer) == 0) {
87  return path;
88  }
89  }
90  return path;
91 }
92 
93 //******************************************************************************
94 // interface operations
95 //******************************************************************************
96 
98 (
99  void
101 {
102 }
103 
104 
105 bool
106 LinuxKernelSymbols::parse(const std::set<std::string> &directorySet, const char *pathname)
107 {
108  std::string virtual_path(pathname);
109  std::string real_path = getKernelFilename(directorySet, virtual_path);
110 
111  if (real_path.empty()) {
112  std::cerr << "Warning: cannot find kernel symbols file " << pathname <<
113  " ds: "<< directorySet.size() << std::endl;
114  perror("LinuxKernelSymbols");
115  return false;
116  }
117 
118  FILE *fp_in = fopen(real_path.c_str(), "r");
119  if (fp_in == NULL) {
120  // there is nothing critical if we cannot open pseudo load module.
121  // we just cannot find the address.
122  return false;
123  }
124 
125  FILE *fp_deflate = tmpfile();
126  if (fp_deflate == NULL) {
127  std::cerr << "Error: cannot create temporary file" << std::endl;
128  return false;
129  }
130 
131  FILE *fp_out = fp_deflate;
132 
133  enum compress_e decomp_status = compress_inflate(fp_in, fp_deflate);
134 
135  // if the decompression is not needed (zlib doesn't exist) we just
136  // read the original copied kallsyms
137  if (decomp_status == COMPRESS_NONE) {
138  fp_out = fp_in;
139  fclose(fp_deflate);
140  }
141 
142  SimpleSymbolBinding binding;
143  FILE *fp = fp_out;
144 
145  if (fp) {
146  rewind(fp);
147  size_t len = 4096;
148  char *line = (char *) malloc(len);
149 
150  for(;;) {
151  if (getline(&line, &len, fp) == EOF)
152  break; // read a line from the file
153 
154  // parse the line into 3 or 4 parts
155  char type;
156  void *addr;
157  char name[4096];
158  char module[4096];
159  module[0] = 0; // initialize module to null in case it is missing
160  int result = sscanf(line, "%p %c %s %s\n", &addr, &type, name, module);
161 
162  if (result < 3) break;
163 
164  switch(type) {
165  case 't':
166  case 'T':
167  // if module is non-empty, append it to name
168  if (strlen(module) > 0) {
169  strcat(name, " ");
170  strcat(name, module);
171  }
172 
173  binding = ((type == 't') ?
176 
177  // add name to the set of function symbols
178  add((uint64_t) addr, SimpleSymbolKind_Function, binding, name);
179  break;
180  default:
181  break;
182  }
183  }
184  fclose(fp);
185  if (fp != fp_in)
186  fclose(fp_in);
187  }
189 
190  return count() > 0;
191 }
192 
193 
194 bool
195 LinuxKernelSymbolsFactory::match(const char *pathname)
196 {
197  if (pathname == NULL)
198  return false;
199 
200  bool prefix_correct = pathname[0] == '<';
201  bool suffix_correct = pathname[strlen(pathname)-1] == '>';
202  bool name_correct = 0<=strncmp(pathname+1, LINUX_KERNEL_NAME_REAL, strlen(LINUX_KERNEL_NAME_REAL));
203 
204  return prefix_correct && suffix_correct && name_correct;
205 }
206 
207 
210 {
211  if (m_kernelSymbol) {
212  return m_kernelSymbol;
213  }
214  m_kernelSymbol = new LinuxKernelSymbols;
215  return m_kernelSymbol;
216 }
217 
218 void
220 {
221  // only accept the first ID, and throw the others
222  if (m_id_status == UNINITIALIZED) {
223  m_id = _id;
224  m_id_status = INITIALIZED;
225  }
226 }
227 
228 uint
230 {
231  return m_id;
232 }
233 
234 void
236 {
237  // only accept the first ID, and throw the others
238  if (m_fileId_status == UNINITIALIZED) {
239  m_fileId = _id;
240  m_fileId_status = INITIALIZED;
241  }
242 }
243 
244 uint
246 {
247  return m_fileId;
248 }
249 
250 
251 
252 const char*
254 {
255  return LINUX_KERNEL_NAME;
256 }
257 
258 
259 //******************************************************************************
260 // unit test
261 //******************************************************************************
262 // #define UNIT_TEST
263 
264 #ifdef UNIT_TEST
265 
266 int main(int argc, char **argv)
267 {
268  LinuxKernelSymbols syms;
270  syms.dump();
271 
272  uint64_t addr = 0;
273  if (argc == 2) {
274  sscanf(argv[1], "%lx", &addr);
275  std::string name;
276  SimpleSymbol *sym = syms.find(addr);
277  bool result = (sym != 0);
278  if (result) name = sym->name();
279  std::cout << "Lookup " << std::hex << "0x" << addr << std::dec
280  << " (" << result << ")" << " --> " << name << std::endl;
281  }
282 }
283 
284 #endif
static std::string getKernelFilename(const std::set< std::string > &directorySet, std::string virtual_name)
#define LINUX_KERNEL_NAME
Definition: linux_info.h:4
SimpleSymbolBinding
void coalesce(SimpleSymbolsCoalesceCallback coalesce)
uint64_t count()
SimpleSymbol * find(uint64_t vma)
void add(uint64_t addr, SimpleSymbolKind kind, SimpleSymbolBinding binding, const char *name)
unsigned int uint
Definition: uint.h:124
#define LINUX_KERNEL_NAME_REAL
Definition: linux_info.h:3
int main(int argc, char *argv[])
Definition: main.cpp:125
const std::string & name() const
bool parse(const std::set< std::string > &directorySet, const char *pathname)
#define LINUX_KERNEL_SYMBOL_FILE
Definition: linux_info.h:8
SimpleSymbolsCoalesceCallback chooseHighestBinding
void *MONITOR_EXT_WRAP_NAME() malloc(size_t bytes)
#define NULL
Definition: ElfHelper.cpp:85
enum compress_e compress_inflate(FILE *source, FILE *dest)
compress_e
Definition: compress.h:73
cct_addr_t * addr
Definition: cct.c:130
#define KERNEL_SYMBOLS_DIRECTORY
Definition: linux_info.h:14
bool match(const char *pathname)
const std::string & name()