Home | History | Annotate | Download | only in ndk-depends
      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
     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 
    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 
    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 
    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.
    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.
    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.
    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 
    239 uint16_t get_u16_le(const uint8_t* bytes) {
    240   return static_cast<uint16_t>(bytes[0] | (bytes[1] << 8));
    241 }
    242 
    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 
    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 
    254 uint16_t get_u16_be(const uint8_t* bytes) {
    255   return static_cast<uint16_t>((bytes[0] << 8) | bytes[1]);
    256 }
    257 
    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 
    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:
    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 
    280   virtual ~Reader() {}
    281 };
    282 
    283 class FileReader : public Reader {
    284 public:
    285   FileReader(FILE* file) : file_(file) {}
    286 
    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:
    304   FileLittleEndianReader(FILE* file) : FileReader(file) {}
    305 
    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 
    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 
    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:
    324   FileBigEndianReader(FILE* file) : FileReader(file) {}
    325 
    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 
    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 
    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 
    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 
    362 bool elf_ident_is_big_endian(const uint8_t* ident) {
    363   return ident[EI_DATA] == ELFDATA2MSB;
    364 }
    365 
    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:
    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.
    469   Word GetWordAt(off_t pos) {
    470     return reader_.GetU32At(pos);
    471   }
    472 
    473   // Read an ELF::Half at a given position.
    474   Half GetHalfAt(off_t pos) {
    475     return reader_.GetU16At(pos);
    476   }
    477 
    478   // Read an ELF::Sword at a given position.
    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.
    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:
    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 
    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 
    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.
    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.
    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).
    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.
    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 <>
    605 Elf32::Addr ElfParser<Elf32>::GetAddrAt(off_t pos) {
    606   return reader_.GetU32At(pos);
    607 }
    608 
    609 template <>
    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:
    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 
    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 
    650   typename ELF::Off GetTag() {
    651     return parser_.GetOffAt(dyn_offset_);
    652   }
    653 
    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>
    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>
    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:
    708   ElfFile()
    709     : file_(NULL), big_endian_(false), is_64bits_(false), reader_(NULL) {}
    710 
    711   virtual ~ElfFile() {
    712     delete reader_;
    713     Close();
    714   }
    715 
    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 
    745   bool IsOk() { return file_ != NULL; }
    746 
    747   bool IsBigEndian() { return big_endian_; }
    748 
    749   const Reader& GetReader() { return *reader_; };
    750 
    751   // Returns the embedded library name, extracted from the dynamic table.
    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.
    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:
    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__
    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'
    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|
    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.
    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).
    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.
    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 
   1003   LibNode() : type(NODE_NONE), value(), needed_libs() {}
   1004 
   1005   explicit LibNode(const String& path)
   1006     : type(NODE_PATH), value(path), needed_libs() {}
   1007 
   1008   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().
   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.
   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.
   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.
   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 
   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
   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