1 //
2 // Copyright (C) 2013 The Android Open Source Project
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions
7 // are met:
8 //  * Redistributions of source code must retain the above copyright
9 //    notice, this list of conditions and the following disclaimer.
10 //  * Redistributions in binary form must reproduce the above copyright
11 //    notice, this list of conditions and the following disclaimer in
12 //    the documentation and/or other materials provided with the
13 //    distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 // SUCH DAMAGE.
27 //
28 
29 // A small portable program used to dump the dynamic dependencies of a
30 // shared library. Requirements:
31 //   - Must support both 32-bit and 64-bit ELF binaries.
32 //   - Must support both little and big endian binaries.
33 //   - Must be compiled as a Unicode program on Windows.
34 //   - Follows Chromium coding-style guide.
35 //   - Single source file to make it easier to build anywhere.
36 
37 //
38 // Work-around Windows Unicode support.
39 //
40 
41 // Enable Windows Unicode support by default. Override this by
42 // setting WINDOWS_UNICODE at build time.
43 #if !defined(WINDOWS_UNICODE) && defined(_WIN32)
44 #define WINDOWS_UNICODE 1
45 #endif
46 
47 #ifdef _WIN32
48 #undef UNICODE
49 #undef _UNICODE
50 #ifdef WINDOWS_UNICODE
51 #define UNICODE 1
52 #define _UNICODE 1
53 #endif
54 #include <windows.h>
55 #include <tchar.h>
56 #else
57 #include <stdlib.h>
58 #include <stdio.h>
59 #include <string.h>
60 #endif
61 
62 #include <string>
63 
64 // Define String as a typedef for either std::string or std::wstring
65 // depending on the platform.
66 #if WINDOWS_UNICODE
67 typedef std::wstring String;
68 #else
69 typedef std::string String;
70 #endif
71 
72 // Use the following functions instead of their standard library equivalent.
73 #if !WINDOWS_UNICODE
74 #define TCHAR char
75 #define _T(x) x
76 #define _tgetenv   getenv
77 #define _tcslen    strlen
78 #define _tcschr    strchr
79 #define _tcscmp    strcmp
80 #define _tcsncmp   strncmp
81 #define _tfopen    fopen
82 #define _tprintf   printf
83 #define _vftprintf vfprintf
84 #define _ftprintf  fprintf
85 #define _tstat     stat
86 #define _vtprintf  vprintf
87 #define _stat      stat
88 #endif
89 
90 // Use TO_STRING(xxx) to convert a C-string into the equivalent String.
91 #if WINDOWS_UNICODE == 1
__s2ws(const std::string & s)92 static inline std::wstring __s2ws(const std::string& s) {
93     int s_len = static_cast<int>(s.length() + 1);
94     int len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), s_len, 0, 0);
95     std::wstring result(len, L'\0');
96     MultiByteToWideChar(CP_ACP, 0, s.c_str(), s_len, &result[0], len);
97     return result;
98 }
99 #define TO_STRING(x) __s2ws(x)
100 #else
101 #define TO_STRING(x)  (x)
102 #endif
103 
104 // Use TO_CONST_TCHAR(xxx) to convert a const char* to a const char/wchar*
105 #if WINDOWS_UNICODE == 1
106 #define TO_CONST_TCHAR(x) TO_STRING(x).c_str()
107 #else
108 #define TO_CONST_TCHAR(x)  (x)
109 #endif
110 
111 
112 //
113 // Start the real program now
114 //
115 
116 #include <errno.h>
117 #ifdef __linux__
118 #include <glob.h>
119 #endif
120 #include <limits.h>
121 #include <stdarg.h>
122 #include <stddef.h>
123 #include <stdint.h>
124 #include <stdlib.h>
125 #include <stdio.h>
126 #include <string.h>
127 #include <sys/stat.h>
128 
129 #include <algorithm>
130 #include <list>
131 #include <map>
132 #include <string>
133 #include <vector>
134 
135 namespace {
136 
137 // Utility functions.
138 
139 enum {
140   MESSAGE_FLAG_PANIC = (1 << 0),
141   MESSAGE_FLAG_ERRNO = (1 << 1),
142 };
143 
vmessage(int flags,const TCHAR * fmt,va_list args)144 void vmessage(int flags, const TCHAR* fmt, va_list args) {
145   int old_errno = errno;
146   if (flags & MESSAGE_FLAG_PANIC)
147     fprintf(stderr, "ERROR: ");
148 
149   _vftprintf(stderr, fmt, args);
150   if (flags & MESSAGE_FLAG_ERRNO) {
151     fprintf(stderr, ": %s", strerror(old_errno));
152   }
153   fprintf(stderr, "\n");
154 
155   if (flags & MESSAGE_FLAG_PANIC)
156     exit(1);
157 
158   errno = old_errno;
159 }
160 
panic(const TCHAR * fmt,...)161 void panic(const TCHAR* fmt, ...) {
162   va_list args;
163   va_start(args, fmt);
164   vmessage(MESSAGE_FLAG_PANIC, fmt, args);
165   va_end(args);
166 }
167 
168 int g_verbose = 0;
169 
log_n(int n,const TCHAR * fmt,...)170 void log_n(int n, const TCHAR* fmt, ...) {
171   if (g_verbose >= n) {
172     va_list args;
173     va_start(args, fmt);
174     _vtprintf(fmt, args);
175     va_end(args);
176   }
177 }
178 
179 #define LOG_N(level,...) \
180   ({ if (g_verbose >= (level)) log_n((level), __VA_ARGS__); })
181 
182 #define LOG(...)  LOG_N(1,__VA_ARGS__)
183 #define LOG2(...) LOG_N(2,__VA_ARGS__)
184 
185 #ifndef DEBUG
186 #define DEBUG 0
187 #endif
188 
189 #if DEBUG
190 #define DLOG(...) _tprintf(__VA_ARGS__)
191 #else
192 #define DLOG(...) ((void)0)
193 #endif
194 
195 // Path utilites
196 
197 // Return the position of the last directory separator in a path,
198 // or std::string::npos if none is found.
path_last_dirsep(const String & filepath)199 size_t path_last_dirsep(const String& filepath) {
200 #ifdef _WIN32
201   size_t sep_slash = filepath.rfind(_T('/'));
202   size_t sep_backslash = filepath.rfind(_T('\\'));
203   size_t sep;
204   if (sep_slash == std::string::npos)
205     sep = sep_backslash;
206   else if (sep_backslash == std::string::npos)
207     sep = sep_slash;
208   else
209     sep = std::max(sep_slash, sep_backslash);
210 #else
211   size_t sep = filepath.rfind(_T('/'));
212 #endif
213   return sep;
214 }
215 
216 // Return the directory name of a given path.
path_dirname(const String & filepath)217 String path_dirname(const String& filepath) {
218   size_t sep = path_last_dirsep(filepath);
219   if (sep == std::string::npos)
220     return String(_T("."));
221   else if (sep == 0)
222     return String(_T("/"));
223   else
224     return filepath.substr(0, sep);
225 }
226 
227 // Return the basename of a given path.
path_basename(const String & filepath)228 String path_basename(const String& filepath) {
229   size_t sep = path_last_dirsep(filepath);
230   if (sep == std::string::npos)
231     return filepath;
232   else
233     return filepath.substr(sep + 1);
234 }
235 
236 
237 // Reading utilities.
238 
get_u16_le(const uint8_t * bytes)239 uint16_t get_u16_le(const uint8_t* bytes) {
240   return static_cast<uint16_t>(bytes[0] | (bytes[1] << 8));
241 }
242 
get_u32_le(const uint8_t * bytes)243 uint32_t get_u32_le(const uint8_t* bytes) {
244   return static_cast<uint32_t>(
245       bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24));
246 }
247 
get_u64_le(const uint8_t * bytes)248 uint64_t get_u64_le(const uint8_t* bytes) {
249   uint64_t lo = static_cast<uint64_t>(get_u32_le(bytes));
250   uint64_t hi = static_cast<uint64_t>(get_u32_le(bytes + 4));
251   return lo | (hi << 32);
252 }
253 
get_u16_be(const uint8_t * bytes)254 uint16_t get_u16_be(const uint8_t* bytes) {
255   return static_cast<uint16_t>((bytes[0] << 8) | bytes[1]);
256 }
257 
get_u32_be(const uint8_t * bytes)258 uint32_t get_u32_be(const uint8_t* bytes) {
259   return static_cast<uint32_t>(
260       (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);
261 }
262 
get_u64_be(const uint8_t * bytes)263 uint64_t get_u64_be(const uint8_t* bytes) {
264   uint64_t hi = static_cast<uint64_t>(get_u32_be(bytes));
265   uint64_t lo = static_cast<uint64_t>(get_u32_be(bytes + 4));
266   return lo | (hi << 32);
267 }
268 
269 // FileReader utility classes
270 
271 class Reader {
272 public:
Reader()273   Reader() {}
274 
275   virtual const uint8_t* GetBytesAt(off_t pos, size_t size) = 0;
276   virtual uint16_t GetU16At(off_t pos) = 0;
277   virtual uint32_t GetU32At(off_t pos) = 0;
278   virtual uint64_t GetU64At(off_t pos) = 0;
279 
~Reader()280   virtual ~Reader() {}
281 };
282 
283 class FileReader : public Reader {
284 public:
FileReader(FILE * file)285   FileReader(FILE* file) : file_(file) {}
286 
GetBytesAt(off_t pos,size_t size)287   virtual const uint8_t* GetBytesAt(off_t pos, size_t size) {
288     if (size < kMaxBytes &&
289         fseek(file_, pos, SEEK_SET) == 0 &&
290         fread(buffer_, size, 1, file_) == 1) {
291       return buffer_;
292     } else
293       return NULL;
294   }
295 
296 private:
297   static const size_t kMaxBytes = 32;
298   FILE* file_;
299   uint8_t buffer_[kMaxBytes];
300 };
301 
302 class FileLittleEndianReader : public FileReader {
303 public:
FileLittleEndianReader(FILE * file)304   FileLittleEndianReader(FILE* file) : FileReader(file) {}
305 
GetU16At(off_t pos)306   virtual uint16_t GetU16At(off_t pos) {
307     const uint8_t* buf = GetBytesAt(pos, 2);
308     return (buf != NULL) ? get_u16_le(buf) : 0;
309   }
310 
GetU32At(off_t pos)311   virtual uint32_t GetU32At(off_t pos) {
312     const uint8_t* buf = GetBytesAt(pos, 4);
313     return (buf != NULL) ? get_u32_le(buf) : 0;
314   }
315 
GetU64At(off_t pos)316   virtual uint64_t GetU64At(off_t pos) {
317     const uint8_t* buf = GetBytesAt(pos, 8);
318     return (buf != NULL) ? get_u64_le(buf) : 0ULL;
319   }
320 };
321 
322 class FileBigEndianReader : public FileReader {
323 public:
FileBigEndianReader(FILE * file)324   FileBigEndianReader(FILE* file) : FileReader(file) {}
325 
GetU16At(off_t pos)326   virtual uint16_t GetU16At(off_t pos) {
327     const uint8_t* buf = GetBytesAt(pos, 2);
328     return (buf != NULL) ? get_u16_be(buf) : 0;
329   }
330 
GetU32At(off_t pos)331   virtual uint32_t GetU32At(off_t pos) {
332     const uint8_t* buf = GetBytesAt(pos, 4);
333     return (buf != NULL) ? get_u32_be(buf) : 0;
334   }
335 
GetU64At(off_t pos)336   virtual uint64_t GetU64At(off_t pos) {
337     const uint8_t* buf = GetBytesAt(pos, 8);
338     return (buf != NULL) ? get_u64_be(buf) : 0ULL;
339   }
340 };
341 
342 // ELF utility functions.
343 
344 // The first 16 common bytes.
345 #define EI_NIDENT 16
346 
347 #define EI_CLASS   4
348 #define ELFCLASS32 1
349 #define ELFCLASS64 2
350 
351 #define EI_DATA     5
352 #define ELFDATA2LSB 1
353 #define ELFDATA2MSB 2
354 
elf_ident_is_elf(const uint8_t * ident)355 bool elf_ident_is_elf(const uint8_t* ident) {
356   return ident[0] == 0x7f &&
357          ident[1] == 'E' &&
358          ident[2] == 'L' &&
359          ident[3] == 'F';
360 }
361 
elf_ident_is_big_endian(const uint8_t * ident)362 bool elf_ident_is_big_endian(const uint8_t* ident) {
363   return ident[EI_DATA] == ELFDATA2MSB;
364 }
365 
elf_ident_is_64bits(const uint8_t * ident)366 bool elf_ident_is_64bits(const uint8_t* ident) {
367   return ident[EI_CLASS] == ELFCLASS64;
368 }
369 
370 #define SHT_STRTAB  3
371 #define SHT_DYNAMIC 6
372 
373 // 32-bit ELF definitions.
374 
375 class Elf32 {
376 public:
377   typedef uint16_t Half;
378   typedef uint32_t Word;
379   typedef uint32_t Off;
380   typedef uint32_t Addr;
381   typedef int32_t Sword;
382 
383   struct Header {
384     uint8_t e_ident[EI_NIDENT];
385     Half    e_type;
386     Half    e_machine;
387     Word    e_version;
388     Addr    e_entry;
389     Off     e_phoff;
390     Off     e_shoff;
391     Word    e_flags;
392     Half    e_shsize;
393     Half    e_phentsize;
394     Half    e_phnum;
395     Half    e_shentsize;
396     Half    e_shnum;
397     Half    e_shstrndx;
398   };
399 
400   struct Shdr {
401     Word sh_name;
402     Word sh_type;
403     Word sh_flags;
404     Addr sh_addr;
405     Off  sh_offset;
406     Word sh_size;
407     Word sh_link;
408     Word sh_info;
409     Word sh_addralign;
410     Word sh_entsize;
411   };
412 };
413 
414 class Elf64 {
415 public:
416   typedef uint16_t Half;
417   typedef uint64_t Off;
418   typedef uint64_t Addr;
419   typedef int32_t  Sword;
420   typedef uint32_t Word;
421   typedef uint64_t Xword;
422   typedef int64_t Sxword;
423 
424   struct Header {
425     uint8_t e_ident[EI_NIDENT];
426     Half    e_type;
427     Half    e_machine;
428     Word    e_version;
429     Addr    e_entry;
430     Off     e_phoff;
431     Off     e_shoff;
432     Word    e_flags;
433     Half    e_shsize;
434     Half    e_phentsize;
435     Half    e_phnum;
436     Half    e_shentsize;
437     Half    e_shnum;
438     Half    e_shstrndx;
439   };
440 
441   struct Shdr {
442     Word  sh_name;
443     Word  sh_type;
444     Xword sh_flags;
445     Addr  sh_addr;
446     Off   sh_offset;
447     Xword sh_size;
448     Word  sh_link;
449     Word  sh_info;
450     Xword sh_addralign;
451     Xword sh_entsize;
452   };
453 };
454 
455 template <class ELF>
456 class ElfParser {
457 public:
ElfParser(Reader & reader)458   ElfParser(Reader& reader) : reader_(reader) {}
459 
460   typedef typename ELF::Word Word;
461   typedef typename ELF::Sword Sword;
462   typedef typename ELF::Addr Addr;
463   typedef typename ELF::Off Off;
464   typedef typename ELF::Half Half;
465   typedef typename ELF::Header ElfHeader;
466   typedef typename ELF::Shdr Shdr;
467 
468   // Read an ELF::Word at a given position.
GetWordAt(off_t pos)469   Word GetWordAt(off_t pos) {
470     return reader_.GetU32At(pos);
471   }
472 
473   // Read an ELF::Half at a given position.
GetHalfAt(off_t pos)474   Half GetHalfAt(off_t pos) {
475     return reader_.GetU16At(pos);
476   }
477 
478   // Read an ELF::Sword at a given position.
GetSwordAt(off_t pos)479   Sword GetSwordAt(off_t pos) {
480     return static_cast<Sword>(GetWordAt(pos));
481   }
482 
483   // Read an ELF::Addr at a given position.
484   Addr GetAddrAt(off_t pos);
485 
486   // Read an ELF::Off at a given position.
GetOffAt(off_t pos)487   Off GetOffAt(off_t pos) {
488     return static_cast<Off>(GetAddrAt(pos));
489   }
490 
491   // Helper class to iterate over the section table.
492   class SectionIterator {
493   public:
SectionIterator(ElfParser & parser)494     explicit SectionIterator(ElfParser& parser)
495       : parser_(parser) {
496       table_offset_ = parser_.GetOffAt(offsetof(ElfHeader, e_shoff));
497       table_count_ = parser_.GetHalfAt(offsetof(ElfHeader, e_shnum));
498       table_entry_size_ = parser_.GetHalfAt(offsetof(ElfHeader, e_shentsize));
499       if (table_entry_size_ < static_cast<Half>(sizeof(Shdr))) {
500         // malformed binary. Ignore all sections.
501         table_count_ = 0;
502       }
503     }
504 
NextOffset()505     Off NextOffset() {
506       if (table_count_ == 0)
507         return 0;
508       Off result = table_offset_;
509       table_offset_ += table_entry_size_;
510       table_count_ -= 1;
511       return result;
512     }
513 
Skip(int count)514     void Skip(int count) {
515       while (count > 0 && table_count_ > 0) {
516         table_offset_ += table_entry_size_;
517         table_count_--;
518         count--;
519       }
520     }
521 
522   private:
523     ElfParser& parser_;
524     Off table_offset_;
525     Half table_count_;
526     Half table_entry_size_;
527   };
528 
529   // Return the offset of the first section of a given type, or 0 if not
530   // found. |*size| will be set to the section size in bytes in case of
531   // success.
GetSectionOffsetByType(int table_type,Off * size)532   Off GetSectionOffsetByType(int table_type, Off* size) {
533     SectionIterator iter(*this);
534     for (;;) {
535       Off table_offset = iter.NextOffset();
536       if (table_offset == 0)
537         break;
538       Word sh_type = GetWordAt(table_offset + offsetof(Shdr, sh_type));
539       if (sh_type == static_cast<Word>(table_type)) {
540         *size = GetOffAt(table_offset + offsetof(Shdr, sh_size));
541         return GetOffAt(table_offset + offsetof(Shdr, sh_offset));
542       }
543     }
544     return 0;
545   }
546 
547   // Return the index of the string table for the dynamic section
548   // in this ELF binary. Or 0 if not found.
GetDynamicStringTableIndex()549   int GetDynamicStringTableIndex() {
550     SectionIterator iter(*this);
551     for (;;) {
552       Off table_offset = iter.NextOffset();
553       if (table_offset == 0)
554         break;
555       Word sh_type = GetWordAt(table_offset + offsetof(Shdr, sh_type));
556       if (sh_type == SHT_DYNAMIC)
557         return GetWordAt(table_offset + offsetof(Shdr, sh_link));
558     }
559     return 0;
560   }
561 
562   // Return the offset of a section identified by its index, or 0 in case
563   // of error (bad index).
GetSectionOffsetByIndex(int sec_index,Off * size)564   Off GetSectionOffsetByIndex(int sec_index, Off* size) {
565     SectionIterator iter(*this);
566     iter.Skip(sec_index);
567     Off table_offset = iter.NextOffset();
568     if (table_offset != 0) {
569       *size = GetOffAt(table_offset + offsetof(Shdr, sh_size));
570       return GetOffAt(table_offset + offsetof(Shdr, sh_offset));
571     }
572     return 0;
573   }
574 
575   // Return a string identified by its index and its string table
576   // Address. Returns an empty string in case of error.
GetStringByIndex(Off str_index,int str_table_index)577   String GetStringByIndex(Off str_index, int str_table_index) {
578     String result;
579 
580     if (str_table_index != 0) {
581       Off str_table_size = 0;
582       Off str_table = GetSectionOffsetByIndex(str_table_index,
583                                               &str_table_size);
584       if (str_table != 0 && str_index < str_table_size) {
585         str_table += str_index;
586         str_table_size -= str_index;
587         while (str_table_size > 0) {
588           const uint8_t* p = reader_.GetBytesAt(str_table, 1);
589           if (p == NULL || *p == '\0')
590             break;
591           result.append(1, static_cast<const char>(*p));
592           str_table += 1;
593           str_table_size -= 1;
594         }
595       }
596     }
597     return result;
598   }
599 
600 private:
601   Reader& reader_;
602 };
603 
604 template <>
GetAddrAt(off_t pos)605 Elf32::Addr ElfParser<Elf32>::GetAddrAt(off_t pos) {
606   return reader_.GetU32At(pos);
607 }
608 
609 template <>
GetAddrAt(off_t pos)610 Elf64::Addr ElfParser<Elf64>::GetAddrAt(off_t pos) {
611   return reader_.GetU64At(pos);
612 }
613 
614 // Helper class to iterate over items of a given type in the dynamic
615 // section. A type of 0 (SHT_NULL) means iterate over all items.
616 //
617 // Examples:
618 //    // Iterate over all entries in the table, find the SHT_NEEDED ones.
619 //    DynamicIterator<Elf32> iter(parser);
620 //    while (iter.GetNext()) {
621 //      if (iter.GetTag() == SHT_NEEDED) {
622 //         Elf32::Off value = iter.GetValue();
623 //         ...
624 //      }
625 //    }
626 template <class ELF>
627 class DynamicIterator {
628 public:
DynamicIterator(ElfParser<ELF> & parser)629   explicit DynamicIterator(ElfParser<ELF>& parser)
630     : parser_(parser),
631       dyn_size_(0),
632       dyn_offset_(0),
633       started_(false) {
634     dyn_offset_ = parser_.GetSectionOffsetByType(SHT_DYNAMIC, &dyn_size_);
635     started_ = (dyn_size_ < kEntrySize);
636   }
637 
GetNext()638   bool GetNext() {
639     if (!started_)
640       started_ = true;
641     else {
642       if (dyn_size_ < kEntrySize)
643         return false;
644       dyn_offset_ += kEntrySize;
645       dyn_size_ -= kEntrySize;
646     }
647     return true;
648   }
649 
GetTag()650   typename ELF::Off GetTag() {
651     return parser_.GetOffAt(dyn_offset_);
652   }
653 
GetValue()654   typename ELF::Off GetValue() {
655     return parser_.GetOffAt(dyn_offset_ + kTagSize);
656   }
657 
658 private:
659   typedef typename ELF::Off Off;
660   static const Off kTagSize = static_cast<Off>(sizeof(Off));
661   static const Off kValueSize = kTagSize;
662   static const Off kEntrySize = kTagSize + kValueSize;
663 
664   ElfParser<ELF>& parser_;
665   Off dyn_size_;
666   Off dyn_offset_;
667   bool started_;
668 };
669 
670 #define DT_NEEDED 1
671 #define DT_SONAME 14
672 
673 template <class ELF>
GetLibNameT(Reader & reader)674 String GetLibNameT(Reader& reader) {
675   ElfParser<ELF> parser(reader);
676   int str_table_index = parser.GetDynamicStringTableIndex();
677   DynamicIterator<ELF> iter(parser);
678   while (iter.GetNext()) {
679     if (iter.GetTag() == DT_SONAME) {
680       typename ELF::Off str_index = iter.GetValue();
681       return parser.GetStringByIndex(str_index, str_table_index);
682     }
683   }
684   return String();
685 }
686 
687 template <class ELF>
GetNeededLibsT(Reader & reader,std::vector<String> * result)688 int GetNeededLibsT(Reader& reader, std::vector<String>* result) {
689   ElfParser<ELF> parser(reader);
690   int str_table_index = parser.GetDynamicStringTableIndex();
691   DynamicIterator<ELF> iter(parser);
692   int count = 0;
693   while (iter.GetNext()) {
694     if (iter.GetTag() == DT_NEEDED) {
695       typename ELF::Off str_index = iter.GetValue();
696       String lib_name = parser.GetStringByIndex(str_index, str_table_index);
697       if (!lib_name.empty()) {
698         result->push_back(lib_name);
699         count++;
700       }
701     }
702   }
703   return count;
704 }
705 
706 class ElfFile {
707 public:
ElfFile()708   ElfFile()
709     : file_(NULL), big_endian_(false), is_64bits_(false), reader_(NULL) {}
710 
~ElfFile()711   virtual ~ElfFile() {
712     delete reader_;
713     Close();
714   }
715 
Open(const TCHAR * path,String * error)716   bool Open(const TCHAR* path, String* error) {
717     Close();
718     file_ = _tfopen(path, _T("rb"));
719     if (file_ == NULL) {
720       error->assign(TO_STRING(strerror(errno)));
721       return false;
722     }
723     uint8_t ident[EI_NIDENT];
724     if (fread(ident, sizeof(ident), 1, file_) != 1) {
725       error->assign(TO_STRING(strerror(errno)));
726       Close();
727       return false;
728     }
729     if (!elf_ident_is_elf(ident)) {
730       *error = _T("Not an ELF binary file");
731       Close();
732       return false;
733     }
734     big_endian_ = elf_ident_is_big_endian(ident);
735     is_64bits_ = elf_ident_is_64bits(ident);
736 
737     if (big_endian_) {
738       reader_ = new FileBigEndianReader(file_);
739     } else {
740       reader_ = new FileLittleEndianReader(file_);
741     }
742     return true;
743   }
744 
IsOk()745   bool IsOk() { return file_ != NULL; }
746 
IsBigEndian()747   bool IsBigEndian() { return big_endian_; }
748 
GetReader()749   const Reader& GetReader() { return *reader_; };
750 
751   // Returns the embedded library name, extracted from the dynamic table.
GetLibName()752   String GetLibName() {
753     if (is_64bits_)
754       return GetLibNameT<Elf64>(*reader_);
755     else
756       return GetLibNameT<Elf32>(*reader_);
757   }
758 
759   // Gets the list of needed libraries and appends them to |result|.
760   // Returns the number of library names appended.
GetNeededLibs(std::vector<String> * result)761   int GetNeededLibs(std::vector<String>* result) {
762     if (is_64bits_)
763       return GetNeededLibsT<Elf64>(*reader_, result);
764     else
765       return GetNeededLibsT<Elf32>(*reader_, result);
766   }
767 
768 protected:
Close()769   void Close() {
770     if (file_ != NULL) {
771       fclose(file_);
772       file_ = NULL;
773     }
774   }
775 
776   FILE* file_;
777   bool big_endian_;
778   bool is_64bits_;
779   Reader* reader_;
780 };
781 
782 #ifdef __linux__
IsLdSoConfSeparator(char ch)783 static bool IsLdSoConfSeparator(char ch) {
784   // The ldconfig manpage indicates that /etc/ld.so.conf contains a list
785   // of colon, space, tab newline or comma separated directories.
786   return (ch == ' ' || ch == '\t' || ch == '\r' ||
787           ch == '\n' || ch == ',' || ch == ':');
788 }
789 
790 // Parse the content of /etc/ld.so.conf, it contains according to the
791 // documentation a 'comma, space, newline, tab separated list of
792 // directories'. In practice, it can also include comments, and an
793 // include directive and glob patterns, as in:
794 //  'include /etc/ld.so.conf.d/*.conf'
AddHostLdSoConfPaths(const char * ld_so_conf_path,std::vector<String> * lib_search_path)795 void AddHostLdSoConfPaths(const char* ld_so_conf_path,
796                           std::vector<String>* lib_search_path) {
797   FILE* file = fopen(ld_so_conf_path, "rb");
798   if (!file)
799     return;
800 
801   char line[1024];
802   while (fgets(line, sizeof(line), file) != NULL) {
803     const char* begin = line;
804     const char* end = line + strlen(line);
805     while (end > begin && end[-1] == '\n')
806       end--;
807 
808     bool prev_is_include = false;
809     while (begin < end) {
810       // Skip over separators
811       while (begin < end && IsLdSoConfSeparator(*begin))
812         begin++;
813 
814       if (begin == end || begin[0] == '#') {
815         // Skip empty lines and comments.
816         break;
817       }
818       // Find end of current item
819       const char* next_pos = begin;
820       while (next_pos < end &&
821           !IsLdSoConfSeparator(*next_pos) &&
822           *next_pos != '#')
823         next_pos++;
824 
825       size_t len = static_cast<size_t>(next_pos - begin);
826       if (prev_is_include) {
827         // If previous token was an 'include', treat this as a glob
828         // pattern and try to process all matching files.
829         prev_is_include = false;
830         if (len == 0) {
831           // Ignore stand-alone 'include' in a single line.
832           break;
833         }
834         String pattern(begin, len);
835         DLOG("%s: processing include '%s'\n",
836              __FUNCTION__,
837              pattern.c_str());
838 
839         glob_t the_glob;
840         memset(&the_glob, 0, sizeof(the_glob));
841         int ret = ::glob(pattern.c_str(), 0, NULL, &the_glob);
842         if (ret == 0) {
843           // Iterate / include all matching files.
844           String filepath;
845           for (size_t n = 0; n < the_glob.gl_pathc; ++n) {
846             filepath.assign(the_glob.gl_pathv[n]);
847             DLOG("%s: Including %s\n", __FUNCTION__, filepath.c_str());
848             AddHostLdSoConfPaths(filepath.c_str(), lib_search_path);
849           }
850         }
851         globfree(&the_glob);
852       } else {
853         // The previous token was not an 'include'. But is the current one?
854         static const char kInclude[] = "include";
855         const size_t kIncludeLen = sizeof(kInclude) - 1;
856         if (len == kIncludeLen && !memcmp(begin, kInclude, len)) {
857           prev_is_include = true;
858         } else if (len > 0) {
859           // No, it must be a directory name.
860           String dirpath(begin, len);
861           struct stat st;
862           if (::stat(dirpath.c_str(), &st) != 0) {
863             LOG("Could not stat(): %s: %s\n", dirpath.c_str(), strerror(errno));
864           } else if (!S_ISDIR(st.st_mode)) {
865             LOG("Not a directory: %s\n", dirpath.c_str());
866           } else {
867             DLOG("%s: Adding %s\n", __FUNCTION__, dirpath.c_str());
868             lib_search_path->push_back(dirpath);
869           }
870         }
871       }
872       // switch to next item in line.
873       begin = next_pos;
874     }
875   }
876   fclose(file);
877 }
878 #endif  // __linux__
879 
880 // Add host shared library search path to |lib_search_path|
AddHostLibraryPaths(std::vector<String> * lib_search_path)881 void AddHostLibraryPaths(std::vector<String>* lib_search_path) {
882   // Only add libraries form LD_LIBRARY_PATH on ELF-based systems.
883 #if defined(__ELF__)
884   // If LD_LIBRARY_PATH is defined, process it
885   const TCHAR* env = _tgetenv(_T("LD_LIBRARY_PATH"));
886   if (env != NULL) {
887     const TCHAR* pos = env;
888     while (*pos) {
889       size_t path_len;
890       const TCHAR* next_pos = _tcschr(pos, ':');
891       if (next_pos == NULL) {
892         path_len = _tcslen(pos);
893         next_pos = pos + path_len;
894       } else {
895         path_len = next_pos - pos;
896         next_pos += 1;
897       }
898 
899       if (path_len == 0) {
900         // Per POSIX convention, an empty path item means "current path".
901         // Not that this is generally a very bad idea, security-wise.
902         lib_search_path->push_back(_T("."));
903       } else {
904         lib_search_path->push_back(String(pos, path_len));
905       }
906 
907       pos = next_pos;
908     }
909   }
910 #ifdef __linux__
911   AddHostLdSoConfPaths("/etc/ld.so.conf", lib_search_path);
912 #endif
913   // TODO(digit): What about BSD systems?
914 #endif
915 }
916 
917 // Returns true if |libname| is the name of an Android system library.
IsAndroidSystemLib(const String & libname)918 bool IsAndroidSystemLib(const String& libname) {
919   static const TCHAR* const kAndroidSystemLibs[] = {
920     _T("libc.so"),
921     _T("libdl.so"),
922     _T("liblog.so"),
923     _T("libm.so"),
924     _T("libstdc++.so"),
925     _T("libz.so"),
926     _T("libandroid.so"),
927     _T("libjnigraphics.so"),
928     _T("libEGL.so"),
929     _T("libGLESv1_CM.so"),
930     _T("libGLESv2.so"),
931     _T("libOpenSLES.so"),
932     _T("libOpenMAXAL.so"),
933     NULL
934   };
935   for (size_t n = 0; kAndroidSystemLibs[n] != NULL; ++n) {
936     if (!libname.compare(kAndroidSystemLibs[n]))
937       return true;
938   }
939   return false;
940 }
941 
942 // Returns true if |libname| is the name of an NDK-compatible shared
943 // library. This means its must begin with "lib" and end with "so"
944 // (without any version numbers).
IsAndroidNdkCompatibleLib(const String & libname)945 bool IsAndroidNdkCompatibleLib(const String& libname) {
946   return libname.size() > 6 &&
947          !libname.compare(0, 3, _T("lib")) &&
948          !libname.compare(libname.size() - 3, 3, _T(".so"));
949 }
950 
951 // Try to find a library named |libname| in |search_paths|
952 // Returns true on success, and sets |result| to the full library path,
953 // false otherwise.
FindLibraryPath(const String & libname,const std::vector<String> & search_paths,String * result)954 bool FindLibraryPath(const String& libname,
955                      const std::vector<String>& search_paths,
956                      String* result) {
957   // Check in the search paths.
958   LOG2(_T("  looking for library: %s\n"), libname.c_str());
959   for (size_t n = 0; n < search_paths.size(); ++n) {
960     String file_path = search_paths[n];
961     if (file_path.empty())
962       continue;
963     if (file_path[file_path.size() - 1] != _T('/') &&
964         file_path[file_path.size() - 1] != _T('\\')) {
965       file_path.append(_T("/"));
966     }
967     file_path.append(libname);
968 
969     LOG2(_T("    in %s: "), file_path.c_str());
970     struct _stat st;
971     if (_tstat(file_path.c_str(), &st) < 0) {
972       LOG2(_T("%s\n"), TO_CONST_TCHAR(strerror(errno)));
973       continue;
974     }
975     if (!S_ISREG(st.st_mode)) {
976       LOG2(_T("Not a regular file!\n"));
977       continue;
978     }
979     // Found the library file.
980     LOG2(_T("OK\n"));
981     result->assign(file_path);
982     return true;
983   }
984 
985   return false;
986 }
987 
988 // Recursive support
989 
990 struct LibNode {
991   // An enumeration listing possible node types, which are:
992   enum Type {
993     NODE_NONE,   // No type yet.
994     NODE_PATH,   // Valid ELF library, |value| is file path.
995     NODE_ERROR,  // Invalid library name, |value| is error string.
996     NODE_SYSTEM, // Android system library, |value| is library name.
997   };
998 
999   Type type;
1000   String value;
1001   std::vector<String> needed_libs;
1002 
LibNode__anon9f1770860111::LibNode1003   LibNode() : type(NODE_NONE), value(), needed_libs() {}
1004 
LibNode__anon9f1770860111::LibNode1005   explicit LibNode(const String& path)
1006     : type(NODE_PATH), value(path), needed_libs() {}
1007 
Set__anon9f1770860111::LibNode1008   void Set(Type type_p, const String& value_p) {
1009     type = type_p;
1010     value = value_p;
1011   }
1012 };
1013 
1014 typedef std::map<String, LibNode> DependencyGraph;
1015 typedef std::list<String> WorkQueue;
1016 
1017 // Used internally by BuildDependencyGraph().
UpdateDependencies(const String & libname,const String & libpath,DependencyGraph & deps,WorkQueue & queue)1018 void UpdateDependencies(
1019     const String& libname,
1020     const String& libpath,
1021     DependencyGraph& deps,
1022     WorkQueue& queue) {
1023   DLOG(_T("UPDATE libname=%s path=%s\n"), libname.c_str(), libpath.c_str());
1024   // Sanity check: find if the library is already in the graph.
1025   if (!libname.empty() && deps.find(libname) != deps.end()) {
1026     // Should not happen.
1027     panic(_T("INTERNAL: Library already in graph: %s"), libname.c_str());
1028   }
1029 
1030   LibNode node;
1031   ElfFile libfile;
1032   String error;
1033   String soname = libname;
1034   if (!libfile.Open(libpath.c_str(), &error)) {
1035     node.Set(LibNode::NODE_ERROR, error);
1036   } else {
1037     String soname = libfile.GetLibName();
1038     if (soname.empty())
1039       soname = libname;
1040     else if (soname != libname) {
1041       _ftprintf(stderr,
1042                 _T("WARNING: Library has invalid soname ('%s'): %s\n"),
1043                 soname.c_str(),
1044                 libpath.c_str());
1045     }
1046     // Discovered a new library, get its dependent libraries.
1047     node.Set(LibNode::NODE_PATH, libpath);
1048     libfile.GetNeededLibs(&node.needed_libs);
1049 
1050     LOG(_T("%s depends on:"), soname.c_str());
1051 
1052     // Add them to the work queue.
1053     for (size_t n = 0; n < node.needed_libs.size(); ++n) {
1054       LOG(_T(" %s"), node.needed_libs[n].c_str());
1055       queue.push_back(node.needed_libs[n]);
1056     }
1057     LOG(_T("\n"));
1058   }
1059   deps[soname] = node;
1060 }
1061 
1062 // Build the full dependency graph.
1063 // |root_libpath| is the path of the root library.
1064 // |lib_search_path| is the list of library search paths.
1065 // Returns a new dependency graph object.
BuildDependencyGraph(const String & root_libpath,const std::vector<String> & lib_search_path)1066 DependencyGraph BuildDependencyGraph(
1067     const String& root_libpath,
1068     const std::vector<String>& lib_search_path) {
1069   DependencyGraph deps;
1070   std::list<String> queue;
1071 
1072   // As a first step, build the full dependency graph, starting with the
1073   // root library. This records errors in the graph too.
1074   UpdateDependencies(path_basename(root_libpath),
1075                      root_libpath,
1076                      deps, queue);
1077 
1078   while (!queue.empty()) {
1079     // Pop first item from queue.
1080     String libname = queue.front();
1081     queue.pop_front();
1082 
1083     // Is the library already in the graph?
1084     DependencyGraph::iterator iter = deps.find(libname);
1085     if (iter != deps.end()) {
1086       // Library already found, skip it.
1087       continue;
1088     }
1089 
1090     // Find the library in the current search path.
1091     String libpath;
1092     if (FindLibraryPath(libname, lib_search_path, &libpath)) {
1093       UpdateDependencies(libname, libpath, deps, queue);
1094       continue;
1095     }
1096 
1097     if (IsAndroidSystemLib(libname)) {
1098       LOG(_T("Android system library: %s\n"), libname.c_str());
1099       LibNode node;
1100       node.Set(LibNode::NODE_SYSTEM, libname);
1101       deps[libname] = node;
1102       continue;
1103     }
1104 
1105     _ftprintf(stderr,
1106               _T("WARNING: Could not find library: %s\n"),
1107               libname.c_str());
1108     LibNode node;
1109     node.Set(LibNode::NODE_ERROR, _T("Could not find library"));
1110     deps[libname] = node;
1111   }
1112 
1113   return deps;
1114 }
1115 
1116 // Print the dependency graph in a human-readable format to stdout.
DumpDependencyGraph(const DependencyGraph & deps)1117 void DumpDependencyGraph(const DependencyGraph& deps) {
1118   _tprintf(_T("Dependency graph:\n"));
1119   DependencyGraph::const_iterator iter = deps.begin();
1120   for ( ; iter != deps.end(); ++iter ) {
1121     const String& libname = iter->first;
1122     const LibNode& node = iter->second;
1123     String node_type;
1124     switch (node.type) {
1125       case LibNode::NODE_NONE:  // should not happen.
1126         node_type = _T("NONE??");
1127         break;
1128       case LibNode::NODE_PATH:
1129         node_type = _T("PATH");
1130         break;
1131       case LibNode::NODE_ERROR:
1132         node_type = _T("ERROR");
1133         break;
1134       case LibNode::NODE_SYSTEM:
1135         node_type = _T("SYSTEM");
1136     }
1137     _tprintf(
1138         _T("[%s] %s %s\n"),
1139         libname.c_str(),
1140         node_type.c_str(),
1141         node.value.c_str());
1142 
1143     if (node.type == LibNode::NODE_PATH) {
1144       for (size_t n = 0; n < node.needed_libs.size(); ++n) {
1145         _tprintf(_T("    %s\n"), node.needed_libs[n].c_str());
1146       }
1147     }
1148   }
1149 }
1150 
1151 // Return the sorted list of libraries from a dependency graph.
1152 // They are topologically ordered, i.e. a library appears always
1153 // before any other library it depends on.
GetTopologicalSortedLibraries(DependencyGraph & deps,std::vector<String> * result)1154 void GetTopologicalSortedLibraries(
1155     DependencyGraph& deps,
1156     std::vector<String>* result) {
1157   result->clear();
1158   // First: Compute the number of visitors per library in the graph.
1159   typedef std::map<String, int> VisitorMap;
1160   VisitorMap visitors;
1161   for (DependencyGraph::const_iterator iter = deps.begin();
1162       iter != deps.end();
1163       ++iter) {
1164     if (visitors.find(iter->first) == visitors.end()) {
1165       visitors[iter->first] = 0;
1166     }
1167 
1168     const std::vector<String>& needed_libs = iter->second.needed_libs;
1169     for (size_t n = 0; n < needed_libs.size(); ++n) {
1170       const String& libname = needed_libs[n];
1171       VisitorMap::iterator lib_iter = visitors.find(libname);
1172       if (lib_iter != visitors.end())
1173         lib_iter->second += 1;
1174       else
1175         visitors[libname] = 1;
1176     }
1177   }
1178 
1179 #if DEBUG
1180   {
1181     VisitorMap::const_iterator iter_end = visitors.end();
1182     VisitorMap::const_iterator iter = visitors.begin();
1183     for ( ; iter != iter_end; ++iter ) {
1184       _tprintf(_T("-- %s %d\n"), iter->first.c_str(), iter->second);
1185     }
1186   }
1187 #endif
1188 
1189   while (!visitors.empty()) {
1190     // Find the library with the smallest number of visitors.
1191     // The value should be 0, unless there are circular dependencies.
1192     VisitorMap::const_iterator iter_end = visitors.end();
1193     VisitorMap::const_iterator iter;
1194     int min_visitors = INT_MAX;
1195     String min_libname;
1196     for (iter = visitors.begin(); iter != iter_end; ++iter) {
1197       // Note: Uses <= instead of < to ensure better diagnostics in
1198       // case of circular dependencies. This shall return the latest
1199       // node in the cycle, i.e. the first one where a 'back' edge
1200       // exists.
1201       if (iter->second <= min_visitors) {
1202         min_libname = iter->first;
1203         min_visitors = iter->second;
1204       }
1205     }
1206 
1207     if (min_visitors == INT_MAX) {
1208       // Should not happen.
1209       panic(_T("INTERNAL: Could not find minimum visited node!"));
1210     }
1211 
1212     // min_visitors should be 0, unless there are circular dependencies.
1213     if (min_visitors != 0) {
1214       // Warn about circular dependencies
1215       _ftprintf(stderr,
1216                 _T("WARNING: Circular dependency found from: %s\n"),
1217                 min_libname.c_str());
1218     }
1219 
1220     // Remove minimum node from the graph, and decrement the visitor
1221     // count of all its needed libraries. This also breaks dependency
1222     // cycles.
1223     result->push_back(min_libname);
1224     const LibNode& node = deps[min_libname];
1225     const std::vector<String> needed_libs = node.needed_libs;
1226     visitors.erase(min_libname);
1227 
1228     for (size_t n = 0; n < needed_libs.size(); ++n)
1229       visitors[needed_libs[n]]--;
1230   }
1231 }
1232 
1233 // Main function
1234 
1235 #define PROGNAME "ndk-depends"
1236 
print_usage(int exit_code)1237 void print_usage(int exit_code) {
1238   printf(
1239     "Usage: %s [options] <elf-file>\n\n"
1240 
1241     "This program is used to print the dependencies of a given ELF\n"
1242     "binary (shared library or executable). It supports any architecture,\n"
1243     "endianess and bitness.\n\n"
1244 
1245     "By default, all dependencies are printed in topological order,\n"
1246     "which means that each item always appear before other items\n"
1247     "it depends on. Except in case of circular dependencies, which will\n"
1248     "print a warning to stderr.\n\n"
1249 
1250     "The tool will try to find other libraries in the same directory\n"
1251     "as the input ELF file. It is possible however to provide\n"
1252     "additional search paths with the -L<path>, which adds an explicit path\n"
1253     "or --host-libs which adds host-specific library paths, on ELF-based systems\n"
1254     "only.\n\n"
1255 
1256     "Use --print-paths to print the path of each ELF binary.\n\n"
1257 
1258     "Use --print-direct to only print the direct dependencies\n"
1259     "of the input ELF binary. All other options except --verbose will be ignored.\n\n"
1260 
1261     "Use --print-java to print a Java source fragment that loads the\n"
1262     "libraries with System.loadLibrary() in the correct order. This can\n"
1263     "be useful when copied into your application's Java source code.\n\n"
1264 
1265     "Use --print-dot to print the dependency graph as a .dot file that can be\n"
1266     "parsed by the GraphViz tool. For example, to generate a PNG image of the\n"
1267     "graph, use something like:\n\n"
1268 
1269     "  ndk-depends /path/to/libfoo.so --print-dot | dot -Tpng -o /tmp/graph.png\n\n"
1270 
1271     "The --verbose option prints debugging information, which can be useful\n"
1272     "to diagnose problems with malformed ELF binaries.\n\n"
1273 
1274     "Valid options:\n"
1275     "  --help|-h|-?    Print this message.\n"
1276     "  --verbose       Increase verbosity.\n"
1277     "  --print-direct  Only print direct dependencies.\n"
1278     "  -L<path>        Append <path> to the library search path.\n"
1279     "  --host-libs     Append host library search path.\n"
1280     "  --print-paths   Print full paths of all libraries.\n"
1281     "  --print-java    Print Java library load sequence.\n"
1282     "  --print-dot     Print the dependency graph as a Graphviz .dot file.\n"
1283     "\n", PROGNAME);
1284 
1285   exit(exit_code);
1286 }
1287 
1288 }  // namespace
1289 
1290 
1291 #ifdef _WIN32
main(void)1292 int main(void) {
1293   int argc = 0;
1294   TCHAR** argv = CommandLineToArgvW(GetCommandLine(), &argc);
1295 #else
1296 int main(int argc, const char** argv) {
1297 #endif
1298 
1299   enum PrintFormat {
1300     PRINT_DEFAULT = 0,
1301     PRINT_DIRECT,
1302     PRINT_PATHS,
1303     PRINT_JAVA,
1304     PRINT_DOT_FILE,
1305   };
1306 
1307   bool do_help = false;
1308   PrintFormat print_format = PRINT_DEFAULT;
1309   std::vector<String> lib_search_path;
1310   std::vector<String> params;
1311 
1312   // Process options.
1313   while (argc > 1) {
1314     if (argv[1][0] == _T('-')) {
1315       const TCHAR* arg = argv[1];
1316       if (!_tcscmp(arg, _T("--help")) ||
1317           !_tcscmp(arg, _T("-h")) ||
1318           !_tcscmp(arg, _T("-?")))
1319         do_help = true;
1320       else if (!_tcscmp(arg, _T("--print-direct"))) {
1321         print_format = PRINT_DIRECT;
1322       } else if (!_tcscmp(arg, _T("-L"))) {
1323         if (argc < 3)
1324           panic(_T("Option -L requires an argument."));
1325         lib_search_path.push_back(String(argv[2]));
1326         argc--;
1327         argv++;
1328       } else if (!_tcsncmp(arg, _T("-L"), 2)) {
1329         lib_search_path.push_back(String(arg+2));
1330       } else if (!_tcscmp(arg, _T("--host-libs"))) {
1331         AddHostLibraryPaths(&lib_search_path);
1332       } else if (!_tcscmp(arg, _T("--print-java"))) {
1333         print_format = PRINT_JAVA;
1334       } else if (!_tcscmp(arg, _T("--print-paths"))) {
1335         print_format = PRINT_PATHS;
1336       } else if (!_tcscmp(arg, _T("--print-dot"))) {
1337         print_format = PRINT_DOT_FILE;
1338       } else if (!_tcscmp(arg, _T("--verbose"))) {
1339         g_verbose++;
1340       } else {
1341         panic(_T("Unsupported option '%s', see --help."), arg);
1342       }
1343     } else {
1344       params.push_back(String(argv[1]));
1345     }
1346     argc--;
1347     argv++;
1348   }
1349 
1350   if (do_help)
1351     print_usage(0);
1352 
1353   if (params.empty())
1354     panic(_T("Please provide the path of an ELF shared library or executable."
1355              "\nSee --help for usage details."));
1356 
1357   // Insert ELF file directory at the head of the search path.
1358   lib_search_path.insert(lib_search_path.begin(), path_dirname(params[0]));
1359 
1360   if (g_verbose >= 1) {
1361     _tprintf(_T("Current library search path:\n"));
1362     for (size_t n = 0; n < lib_search_path.size(); ++n)
1363       _tprintf(_T("  %s\n"), lib_search_path[n].c_str());
1364     _tprintf(_T("\n"));
1365   }
1366 
1367   // Open main input file.
1368   const TCHAR* libfile_path = params[0].c_str();
1369 
1370   ElfFile libfile;
1371   String error;
1372   if (!libfile.Open(libfile_path, &error)) {
1373     panic(_T("Could not open file '%s': %s"), libfile_path, error.c_str());
1374   }
1375 
1376   if (print_format == PRINT_DIRECT) {
1377     // Simple dump, one line per dependency. No frills, no recursion.
1378     std::vector<String> needed_libs;
1379     libfile.GetNeededLibs(&needed_libs);
1380 
1381     for (size_t i = 0; i < needed_libs.size(); ++i)
1382       _tprintf(_T("%s\n"), needed_libs[i].c_str());
1383 
1384     return 0;
1385   }
1386 
1387   // Topological sort of all dependencies.
1388   LOG(_T("Building dependency graph...\n"));
1389   DependencyGraph deps = BuildDependencyGraph(
1390       libfile_path, lib_search_path);
1391 
1392   if (g_verbose >= 2)
1393     DumpDependencyGraph(deps);
1394 
1395   LOG(_T("Building sorted list of binaries:\n"));
1396   std::vector<String> needed_libs;
1397   GetTopologicalSortedLibraries(deps, &needed_libs);
1398 
1399   if (print_format == PRINT_JAVA) {
1400     // Print Java libraries in reverse order.
1401     std::reverse(needed_libs.begin(), needed_libs.end());
1402     for (size_t i = 0; i < needed_libs.size(); ++i) {
1403       const String& lib = needed_libs[i];
1404       if (IsAndroidSystemLib(lib)) {
1405         // Skip system libraries.
1406         continue;
1407       }
1408       if (!IsAndroidNdkCompatibleLib(lib)) {
1409         _ftprintf(
1410             stderr,
1411             _T("WARNING: Non-compatible library name ignored: %s\n"),
1412             lib.c_str());
1413         continue;
1414       }
1415       _tprintf(_T("System.loadLibrary(%s);\n"),
1416                 lib.substr(3, lib.size() - 6).c_str());
1417     }
1418     return 0;
1419   }
1420 
1421   if (print_format == PRINT_DOT_FILE) {
1422     // Using the topological order helps generates a more human-friendly
1423     // directed graph.
1424     _tprintf(_T("digraph {\n"));
1425     for (size_t i = 0; i < needed_libs.size(); ++i) {
1426       const String& libname = needed_libs[i];
1427       const std::vector<String>& libdeps = deps[libname].needed_libs;
1428       for (size_t n = 0; n < libdeps.size(); ++n) {
1429         // Note: Use quoting to deal with special characters like -
1430         // which are not normally part of DOT 'id' tokens.
1431         _tprintf(_T("  \"%s\" -> \"%s\"\n"), libname.c_str(), libdeps[n].c_str());
1432       }
1433     }
1434     _tprintf(_T("}\n"));
1435     return 0;
1436   }
1437 
1438   if (print_format == PRINT_PATHS) {
1439     // Print libraries with path.
1440     for (size_t i = 0; i < needed_libs.size(); ++i) {
1441       const String& lib = needed_libs[i];
1442       LibNode& node = deps[lib];
1443       const TCHAR* format;
1444       switch (node.type) {
1445         case LibNode::NODE_PATH:
1446           format = _T("%s -> %s\n");
1447           break;
1448         case LibNode::NODE_SYSTEM:
1449           format = _T("%s -> $ /system/lib/%s\n");
1450           break;
1451         default:
1452           format = _T("%s -> !! %s\n");
1453       }
1454       _tprintf(format, lib.c_str(), deps[lib].value.c_str());
1455     }
1456     return 0;
1457   }
1458 
1459   // Print simple library names.
1460   for (size_t i = 0; i < needed_libs.size(); ++i) {
1461     const String& lib = needed_libs[i];
1462     _tprintf(_T("%s\n"), lib.c_str());
1463   }
1464   return 0;
1465 }
1466