ns-3 Direct Code Execution
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
elf-ldd.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2012 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Frederic Urbani <frederic.urbani@inria.fr>
19  *
20  */
21 #include "elf-ldd.h"
22 #include "ns3/log.h"
23 #include "ns3/assert.h"
24 #include <unistd.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <dirent.h>
33 #include <sys/mman.h>
34 #include <elf.h>
35 #include <link.h>
36 #include <set>
37 #include <map>
38 #include <vector>
39 #include <utility>
40 #include <string>
41 #include <iostream>
42 
43 namespace ns3 {
44 using namespace std;
45 
46 NS_LOG_COMPONENT_DEFINE ("ElfLdd");
47 
49 {
50 public:
51  SharedLibrary (string sName, string fullName);
52  void AddLibrary (string l);
53  void AddPath (string p);
54  void SetSoName (string s);
55  void SetArch32 ();
56  void SetArch64 ();
57  string GetName (bool full) const;
58  bool GetArch32 () const;
59  bool GetArch64 () const;
60  set <pair<string,string> > GetLibs () const;
61  vector <string> GetPath () const;
62  string GetSoname () const;
63  bool SearchLibs ();
64  bool CalcDepth (int max, map <string, SharedLibrary*> &mapScanned);
65  int GetDepth () const;
66 
67 private:
68  // ELF file name
69  const string m_fullName;
70  // Short Name
71  const string m_sName;
72  // Set of library found in elf file short
73  set <pair<string,string> > m_libs;
74  // vector of paths found in elf file (in DT_PATH and DT_RUNPATH) each entry is checked before (exists on this computer).
75  vector <string> m_path;
76  // DT_SONAME seen
77  string m_soname;
78  bool m_arch32;
79  bool m_arch64;
80  int m_depth;
81 };
82 
83 SharedLibrary::SharedLibrary (string s,string f) : m_fullName (f),
84  m_sName (s),
85  m_arch32 (0),
86  m_arch64 (0),
87  m_depth (-1)
88 {
89 }
90 
91 void
93 {
94  m_libs.insert (make_pair (l, ""));
95 }
96 
97 void
99 {
100  char *start = (char*) p.c_str ();
101  char *crsr = start;
102 
103  while (*crsr)
104  {
105  char *f = crsr;
106  char prec = 0;
107 
108  while (*crsr && (*crsr != ':'))
109  {
110  prec = *crsr;
111  crsr++;
112  }
113  char *l = crsr;
114 
115  if (l > f)
116  {
117  string res = string (f, l - f);
118  if ((prec != 0) && (prec != '/'))
119  {
120  res += '/';
121  }
122  if (res.length () > 0)
123  {
124  DIR *d = opendir (res.c_str ());
125 
126  if (d)
127  {
128  m_path.push_back (res);
129  closedir (d);
130  }
131  }
132  }
133  if (*crsr)
134  {
135  crsr++;
136  }
137  }
138 }
139 
140 void
142 {
143  m_soname = s;
144 }
145 set <pair<string,string> >
147 {
148  return m_libs;
149 }
150 vector <string>
152 {
153  return m_path;
154 }
155 string
157 {
158  return m_soname;
159 }
160 void
162 {
163  m_arch32 = 1;
164 }
165 void
167 {
168  m_arch64 = 1;
169 }
170 bool
172 {
173  return m_arch32;
174 }
176 {
177  return m_arch64;
178 }
179 string
180 SharedLibrary::GetName (bool full) const
181 {
182  if (full)
183  {
184  return m_fullName;
185  }
186  else
187  {
188  return m_sName;
189  }
190 }
191 bool
193 {
194  uint32_t count = 0;
195  set<pair<string,string> > n;
196 
197  for (set<pair<string,string> >::const_iterator i = m_libs.begin (); i != m_libs.end (); ++i)
198  {
199  bool f = 0;
200  pair <string,string> p = *i;
201 
202  for (vector<string>::const_iterator j = m_path.begin (); j != m_path.end (); ++j)
203  {
204  string fullPath = *j + p.first;
205  struct stat st;
206 
207  if (!stat (fullPath.c_str (), &st))
208  {
209  p.second = fullPath;
210  n.insert (p);
211  count++;
212  f = 1;
213  break;
214  }
215  }
216  if (!f)
217  {
218  NS_LOG_DEBUG (p.first << " NOT FOUND");
219  }
220  }
221  if (m_libs.size () == count)
222  {
223  m_libs = n;
224  return 1;
225  }
226  return 0;
227 }
228 bool
229 SharedLibrary::CalcDepth (int max, map <string, SharedLibrary*> &mapScanned)
230 {
231  if (m_depth >= 0)
232  {
233  return 1;
234  }
235  if (max < 0)
236  {
237  return 0;
238  }
239  if (m_libs.size () == 0)
240  {
241  m_depth = 0;
242  return 1;
243  }
244  int calc = 0;
245  for (set<pair<string,string> >::const_iterator i = m_libs.begin (); i != m_libs.end (); ++i)
246  {
247  if (!mapScanned[(*i).second]->CalcDepth (max - 1, mapScanned))
248  {
249  return 0;
250  }
251  if (mapScanned[(*i).second]->GetDepth () > calc - 1)
252  {
253  calc = mapScanned[(*i).second]->GetDepth () + 1;
254  }
255  }
256  m_depth = calc;
257  return 1;
258 }
259 int
261 {
262  return m_depth;
263 }
264 // Convert a virtual address to an offset within the file
265 ElfW (Addr) vaddr_2_foffset (const ElfW (Ehdr) * he, const ElfW (Phdr) * pr, const ElfW (Addr) vma)
266 {
267  for (int p = 0; p < he->e_phnum; p++)
268  {
269  if (pr[p].p_type == PT_LOAD)
270  {
271  if ((vma >= pr[p].p_vaddr))
272  {
273  return vma - pr[p].p_vaddr + pr[p].p_offset;
274  }
275  }
276  }
277 
278  return vma;
279 }
280 SharedLibrary*
281 ElfLdd::ExtractLibraries (std::string sName, std::string fullPath)
282 {
283  NS_LOG_FUNCTION (sName << fullPath);
284  int fd = open (fullPath.c_str (), O_RDONLY);
285  if (fd == -1)
286  {
287  NS_LOG_ERROR (fullPath << ": unable to open file errno: " << errno);
288  return 0;
289  }
290  struct stat st;
291  int retval = fstat (fd, &st);
292  if (retval)
293  {
294  NS_LOG_ERROR (fullPath << ": unable to fstat file errno: " << errno);
295  return 0;
296  }
297  uint64_t size = st.st_size;
298  uint8_t *buffer = (uint8_t *) mmap (0, size, PROT_READ, MAP_PRIVATE, fd, 0);
299  if (((void*)-1) == buffer)
300  {
301  NS_LOG_ERROR (fullPath << ": unable to mmap file errno: " << errno);
302  return 0;
303  }
304  close (fd);
305  SharedLibrary *res = new SharedLibrary (sName, fullPath);
306  const ElfW (Ehdr) * header = (ElfW (Ehdr) *)buffer;
307  if (header->e_ident [EI_CLASS] == ELFCLASS64)
308  {
309  res->SetArch64 ();
310  }
311  if (header->e_ident [EI_CLASS] == ELFCLASS32)
312  {
313  res->SetArch32 ();
314  }
315  const ElfW (Phdr) * programTable = (ElfW (Phdr) *)(buffer + header->e_phoff);
316  const ElfW (Shdr) * sectionTable = (ElfW (Shdr) *)(buffer + header->e_shoff);
317  for (int s = 0; s < header->e_shnum ; s++)
318  {
319  if (SHT_DYNAMIC == sectionTable [s].sh_type)
320  {
321  int n = 0;
322  ElfW (Dyn) * dynamics = (ElfW (Dyn) *)(buffer + sectionTable [s].sh_offset);
323  bool turn = 1;
324  ElfW (Addr) dt_strtab = 0;
325  do
326  {
327  if (dynamics [n].d_tag == DT_STRTAB)
328  {
329  turn = 0;
330  dt_strtab = vaddr_2_foffset (header, programTable, dynamics [n].d_un.d_ptr);
331  }
332  if (dynamics [n].d_tag == DT_NULL)
333  {
334  turn = 0;
335  }
336  n++;
337  }
338  while (turn);
339  n = 0;
340  turn = 1;
341  do
342  {
343  switch (dynamics [n].d_tag)
344  {
345  case DT_NULL:
346  {
347  turn = 0;
348  }
349  break;
350 
351  case DT_NEEDED:
352  {
353  res->AddLibrary (string ((char*)(buffer + dt_strtab + dynamics [n].d_un.d_ptr)));
354  }
355  break;
356 
357  case DT_RPATH:
358  case DT_RUNPATH:
359  {
360  res->AddPath (string ((char*)(buffer + dt_strtab + dynamics [n].d_un.d_ptr)));
361  }
362  break;
363 
364  case DT_SONAME:
365  {
366  res->SetSoName (string ((char*)(buffer + dt_strtab + dynamics [n].d_un.d_ptr)));
367  }
368  break;
369  }
370  n++;
371  }
372  while (turn);
373  }
374  }
375  retval = ::munmap (buffer, size);
376 
377  return res;
378 }
379 
380 void
381 ElfLdd::Loop (std::string s, std::string f)
382 {
383  set<pair<string,string> > todo;
384  set<string> done;
385  map <string, SharedLibrary*> mapScanned;
386  todo.insert (make_pair (s,f));
387  vector<SharedLibrary*> toFree;
388 
389  while (todo.size () > 0)
390  {
391  const pair<string,string> name = *(todo.begin ());
392  todo.erase (name);
393  SharedLibrary* l = ExtractLibraries (name.first, name.second);
394  if (l)
395  {
396  toFree.push_back (l);
397  if (getenv ("LD_LIBRARY_PATH"))
398  {
399  l->AddPath (getenv ("LD_LIBRARY_PATH"));
400  }
401  if (l->GetArch32 ())
402  {
403  l->AddPath ("/lib/:/usr/lib/:/lib/i386-linux-gnu/:/usr/lib/i386-linux-gnu/");
404  }
405  if (l->GetArch64 ())
406  {
407  l->AddPath ("/lib64/:/usr/lib64/:/lib/x86_64-linux-gnu/:/usr/lib/x86_64-linux-gnu/:/lib/:/usr/lib/");
408  }
409  if (l->SearchLibs ())
410  {
411  done.insert (name.second);
412  mapScanned [name.second] = l;
413  set <pair<string,string> > full = l->GetLibs ();
414 
415  for (set <pair<string,string> >::const_iterator ii = full.begin ();
416  ii != full.end (); ++ii)
417  {
418  string lalib = (*ii).second;
419 
420  if ((todo.find (*ii) == todo.end ())
421  &&
422  (done.end () == done.find (lalib)))
423  {
424  todo.insert (*ii);
425  }
426  }
427  }
428  }
429  }
430 
431  if (0 == mapScanned[f])
432  {
433  NS_LOG_DEBUG ("No libraries found for " << f);
434  return;
435  }
436 
437  if (!mapScanned[f]->CalcDepth (mapScanned.size (), mapScanned))
438  {
439  NS_LOG_ERROR ("There is a loop in dependencies of " << f);
440  return;
441  }
442  map <int, vector <SharedLibrary*> > tri;
443  int maxi = 0;
444  for (map <string, SharedLibrary*>::const_iterator i = mapScanned.begin ();
445  i != mapScanned.end (); i++)
446  {
447  int p = i->second->GetDepth ();
448 
449  if (p > maxi)
450  {
451  maxi = p;
452  }
453  if (tri.find (p) == tri.end ())
454  {
455  vector <SharedLibrary*> vide;
456  tri [p] = vide;
457  }
458  tri [p].push_back (i->second);
459  }
460  for (int j = 0 ; j <= maxi ; j++)
461  {
462  vector <SharedLibrary*> vectore = tri [j];
463  for (vector<SharedLibrary*>::const_iterator s = vectore.begin (); s != vectore.end (); s++)
464  {
466  d.required = (*s)->GetName (0);
467  d.found = (*s)->GetName (1);
468  m_deps.push_back (d);
469  }
470  }
471  for (vector<SharedLibrary*>::const_iterator s = toFree.begin (); s != toFree.end (); s++)
472  {
473  delete (*s);
474  }
475 }
476 
477 ElfLdd::ElfLdd (string s, string f)
478 {
479  Loop (s, f);
480 }
481 
482 std::vector<struct ElfDependencies::Dependency>
484 {
485  return m_deps;
486 }
487 
489 ElfLdd::Begin (void) const
490 {
491  return m_deps.begin ();
492 }
494 ElfLdd::End (void) const
495 {
496  return m_deps.end ();
497 }
498 
499 } // namespace ns3
500 
501