12454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//
22454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Copyright (C) 2013 The Android Open Source Project
32454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// All rights reserved.
42454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//
52454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Redistribution and use in source and binary forms, with or without
62454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// modification, are permitted provided that the following conditions
72454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// are met:
82454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//  * Redistributions of source code must retain the above copyright
92454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//    notice, this list of conditions and the following disclaimer.
102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//  * Redistributions in binary form must reproduce the above copyright
112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//    notice, this list of conditions and the following disclaimer in
122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//    the documentation and/or other materials provided with the
132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//    distribution.
142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//
152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// SUCH DAMAGE.
272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//
282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// A small portable program used to dump the dynamic dependencies of a
302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// shared library. Requirements:
312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//   - Must support both 32-bit and 64-bit ELF binaries.
322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//   - Must support both little and big endian binaries.
332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//   - Must be compiled as a Unicode program on Windows.
342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//   - Follows Chromium coding-style guide.
352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//   - Single source file to make it easier to build anywhere.
362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//
382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Work-around Windows Unicode support.
392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//
402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Enable Windows Unicode support by default. Override this by
422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// setting WINDOWS_UNICODE at build time.
432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#if !defined(WINDOWS_UNICODE) && defined(_WIN32)
442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define WINDOWS_UNICODE 1
452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#ifdef _WIN32
482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#undef UNICODE
492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#undef _UNICODE
502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#ifdef WINDOWS_UNICODE
512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define UNICODE 1
522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _UNICODE 1
532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <windows.h>
552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <tchar.h>
562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#else
572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <stdlib.h>
582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <stdio.h>
592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <string.h>
602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <string>
632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Define String as a typedef for either std::string or std::wstring
652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// depending on the platform.
662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#if WINDOWS_UNICODE
672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnertypedef std::wstring String;
682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#else
692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnertypedef std::string String;
702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Use the following functions instead of their standard library equivalent.
732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#if !WINDOWS_UNICODE
742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define TCHAR char
752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _T(x) x
762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _tgetenv   getenv
772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _tcslen    strlen
782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _tcschr    strchr
792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _tcscmp    strcmp
802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _tcsncmp   strncmp
812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _tfopen    fopen
822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _tprintf   printf
832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _vftprintf vfprintf
842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _ftprintf  fprintf
852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _tstat     stat
862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _vtprintf  vprintf
872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define _stat      stat
882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Use TO_STRING(xxx) to convert a C-string into the equivalent String.
912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#if WINDOWS_UNICODE == 1
922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerstatic inline std::wstring __s2ws(const std::string& s) {
932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    int s_len = static_cast<int>(s.length() + 1);
942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    int len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), s_len, 0, 0);
952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    std::wstring result(len, L'\0');
962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    MultiByteToWideChar(CP_ACP, 0, s.c_str(), s_len, &result[0], len);
972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return result;
982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define TO_STRING(x) __s2ws(x)
1002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#else
1012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define TO_STRING(x)  (x)
1022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
1032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Use TO_CONST_TCHAR(xxx) to convert a const char* to a const char/wchar*
1052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#if WINDOWS_UNICODE == 1
1062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define TO_CONST_TCHAR(x) TO_STRING(x).c_str()
1072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#else
1082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define TO_CONST_TCHAR(x)  (x)
1092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
1102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//
1132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Start the real program now
1142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//
1152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <errno.h>
1172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#ifdef __linux__
1182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <glob.h>
1192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
1202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <limits.h>
1212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <stdarg.h>
1222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <stddef.h>
1232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <stdint.h>
1242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <stdlib.h>
1252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <stdio.h>
1262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <string.h>
1272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <sys/stat.h>
1282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <algorithm>
1302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <list>
1312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <map>
1322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <string>
1332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#include <vector>
1342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnernamespace {
1362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Utility functions.
1382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerenum {
1402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  MESSAGE_FLAG_PANIC = (1 << 0),
1412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  MESSAGE_FLAG_ERRNO = (1 << 1),
1422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner};
1432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnervoid vmessage(int flags, const TCHAR* fmt, va_list args) {
1452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  int old_errno = errno;
1462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (flags & MESSAGE_FLAG_PANIC)
1472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    fprintf(stderr, "ERROR: ");
1482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  _vftprintf(stderr, fmt, args);
1502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (flags & MESSAGE_FLAG_ERRNO) {
1512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    fprintf(stderr, ": %s", strerror(old_errno));
1522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
1532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  fprintf(stderr, "\n");
1542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (flags & MESSAGE_FLAG_PANIC)
1562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    exit(1);
1572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  errno = old_errno;
1592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
1602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnervoid panic(const TCHAR* fmt, ...) {
1622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  va_list args;
1632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  va_start(args, fmt);
1642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  vmessage(MESSAGE_FLAG_PANIC, fmt, args);
1652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  va_end(args);
1662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
1672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerint g_verbose = 0;
1692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnervoid log_n(int n, const TCHAR* fmt, ...) {
1712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (g_verbose >= n) {
1722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    va_list args;
1732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    va_start(args, fmt);
1742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _vtprintf(fmt, args);
1752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    va_end(args);
1762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
1772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
1782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define LOG_N(level,...) \
1802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  ({ if (g_verbose >= (level)) log_n((level), __VA_ARGS__); })
1812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define LOG(...)  LOG_N(1,__VA_ARGS__)
1832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define LOG2(...) LOG_N(2,__VA_ARGS__)
1842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#ifndef DEBUG
1862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define DEBUG 0
1872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
1882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#if DEBUG
1902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define DLOG(...) _tprintf(__VA_ARGS__)
1912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#else
1922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define DLOG(...) ((void)0)
1932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
1942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Path utilites
1962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
1972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Return the position of the last directory separator in a path,
1982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// or std::string::npos if none is found.
1992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnersize_t path_last_dirsep(const String& filepath) {
2002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#ifdef _WIN32
2012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  size_t sep_slash = filepath.rfind(_T('/'));
2022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  size_t sep_backslash = filepath.rfind(_T('\\'));
2032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  size_t sep;
2042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (sep_slash == std::string::npos)
2052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    sep = sep_backslash;
2062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  else if (sep_backslash == std::string::npos)
2072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    sep = sep_slash;
2082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  else
2092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    sep = std::max(sep_slash, sep_backslash);
2102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#else
2112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  size_t sep = filepath.rfind(_T('/'));
2122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
2132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return sep;
2142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
2152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Return the directory name of a given path.
2172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' TurnerString path_dirname(const String& filepath) {
2182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  size_t sep = path_last_dirsep(filepath);
2192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (sep == std::string::npos)
2202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return String(_T("."));
2212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  else if (sep == 0)
2222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return String(_T("/"));
2232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  else
2242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return filepath.substr(0, sep);
2252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
2262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Return the basename of a given path.
2282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' TurnerString path_basename(const String& filepath) {
2292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  size_t sep = path_last_dirsep(filepath);
2302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (sep == std::string::npos)
2312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return filepath;
2322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  else
2332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return filepath.substr(sep + 1);
2342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
2352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Reading utilities.
2382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turneruint16_t get_u16_le(const uint8_t* bytes) {
2402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return static_cast<uint16_t>(bytes[0] | (bytes[1] << 8));
2412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
2422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turneruint32_t get_u32_le(const uint8_t* bytes) {
2442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return static_cast<uint32_t>(
2452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24));
2462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
2472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turneruint64_t get_u64_le(const uint8_t* bytes) {
2492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  uint64_t lo = static_cast<uint64_t>(get_u32_le(bytes));
2502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  uint64_t hi = static_cast<uint64_t>(get_u32_le(bytes + 4));
2512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return lo | (hi << 32);
2522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
2532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turneruint16_t get_u16_be(const uint8_t* bytes) {
2552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return static_cast<uint16_t>((bytes[0] << 8) | bytes[1]);
2562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
2572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turneruint32_t get_u32_be(const uint8_t* bytes) {
2592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return static_cast<uint32_t>(
2602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);
2612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
2622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turneruint64_t get_u64_be(const uint8_t* bytes) {
2642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  uint64_t hi = static_cast<uint64_t>(get_u32_be(bytes));
2652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  uint64_t lo = static_cast<uint64_t>(get_u32_be(bytes + 4));
2662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return lo | (hi << 32);
2672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
2682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// FileReader utility classes
2702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerclass Reader {
2722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerpublic:
2732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  Reader() {}
2742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  virtual const uint8_t* GetBytesAt(off_t pos, size_t size) = 0;
2762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  virtual uint16_t GetU16At(off_t pos) = 0;
2772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  virtual uint32_t GetU32At(off_t pos) = 0;
2782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  virtual uint64_t GetU64At(off_t pos) = 0;
2792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  virtual ~Reader() {}
2812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner};
2822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerclass FileReader : public Reader {
2842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerpublic:
2852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  FileReader(FILE* file) : file_(file) {}
2862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  virtual const uint8_t* GetBytesAt(off_t pos, size_t size) {
2882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (size < kMaxBytes &&
2892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        fseek(file_, pos, SEEK_SET) == 0 &&
2902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        fread(buffer_, size, 1, file_) == 1) {
2912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      return buffer_;
2922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    } else
2932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      return NULL;
2942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
2952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
2962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerprivate:
2972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  static const size_t kMaxBytes = 32;
2982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  FILE* file_;
2992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  uint8_t buffer_[kMaxBytes];
3002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner};
3012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerclass FileLittleEndianReader : public FileReader {
3032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerpublic:
3042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  FileLittleEndianReader(FILE* file) : FileReader(file) {}
3052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  virtual uint16_t GetU16At(off_t pos) {
3072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const uint8_t* buf = GetBytesAt(pos, 2);
3082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return (buf != NULL) ? get_u16_le(buf) : 0;
3092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
3102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  virtual uint32_t GetU32At(off_t pos) {
3122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const uint8_t* buf = GetBytesAt(pos, 4);
3132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return (buf != NULL) ? get_u32_le(buf) : 0;
3142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
3152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  virtual uint64_t GetU64At(off_t pos) {
3172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const uint8_t* buf = GetBytesAt(pos, 8);
3182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return (buf != NULL) ? get_u64_le(buf) : 0ULL;
3192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
3202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner};
3212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerclass FileBigEndianReader : public FileReader {
3232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerpublic:
3242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  FileBigEndianReader(FILE* file) : FileReader(file) {}
3252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  virtual uint16_t GetU16At(off_t pos) {
3272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const uint8_t* buf = GetBytesAt(pos, 2);
3282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return (buf != NULL) ? get_u16_be(buf) : 0;
3292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
3302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  virtual uint32_t GetU32At(off_t pos) {
3322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const uint8_t* buf = GetBytesAt(pos, 4);
3332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return (buf != NULL) ? get_u32_be(buf) : 0;
3342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
3352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  virtual uint64_t GetU64At(off_t pos) {
3372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const uint8_t* buf = GetBytesAt(pos, 8);
3382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return (buf != NULL) ? get_u64_be(buf) : 0ULL;
3392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
3402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner};
3412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// ELF utility functions.
3432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// The first 16 common bytes.
3452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define EI_NIDENT 16
3462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define EI_CLASS   4
3482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define ELFCLASS32 1
3492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define ELFCLASS64 2
3502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define EI_DATA     5
3522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define ELFDATA2LSB 1
3532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define ELFDATA2MSB 2
3542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerbool elf_ident_is_elf(const uint8_t* ident) {
3562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return ident[0] == 0x7f &&
3572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner         ident[1] == 'E' &&
3582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner         ident[2] == 'L' &&
3592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner         ident[3] == 'F';
3602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
3612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerbool elf_ident_is_big_endian(const uint8_t* ident) {
3632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return ident[EI_DATA] == ELFDATA2MSB;
3642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
3652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerbool elf_ident_is_64bits(const uint8_t* ident) {
3672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return ident[EI_CLASS] == ELFCLASS64;
3682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
3692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define SHT_STRTAB  3
3712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define SHT_DYNAMIC 6
3722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// 32-bit ELF definitions.
3742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerclass Elf32 {
3762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerpublic:
3772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef uint16_t Half;
3782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef uint32_t Word;
3792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef uint32_t Off;
3802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef uint32_t Addr;
3812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef int32_t Sword;
3822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
3832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  struct Header {
3842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    uint8_t e_ident[EI_NIDENT];
3852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_type;
3862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_machine;
3872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word    e_version;
3882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Addr    e_entry;
3892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Off     e_phoff;
3902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Off     e_shoff;
3912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word    e_flags;
3922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_shsize;
3932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_phentsize;
3942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_phnum;
3952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_shentsize;
3962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_shnum;
3972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_shstrndx;
3982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  };
3992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
4002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  struct Shdr {
4012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word sh_name;
4022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word sh_type;
4032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word sh_flags;
4042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Addr sh_addr;
4052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Off  sh_offset;
4062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word sh_size;
4072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word sh_link;
4082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word sh_info;
4092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word sh_addralign;
4102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word sh_entsize;
4112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  };
4122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner};
4132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
4142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerclass Elf64 {
4152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerpublic:
4162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef uint16_t Half;
4172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef uint64_t Off;
4182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef uint64_t Addr;
4192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef int32_t  Sword;
4202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef uint32_t Word;
4212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef uint64_t Xword;
4222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef int64_t Sxword;
4232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
4242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  struct Header {
4252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    uint8_t e_ident[EI_NIDENT];
4262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_type;
4272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_machine;
4282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word    e_version;
4292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Addr    e_entry;
4302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Off     e_phoff;
4312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Off     e_shoff;
4322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word    e_flags;
4332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_shsize;
4342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_phentsize;
4352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_phnum;
4362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_shentsize;
4372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_shnum;
4382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half    e_shstrndx;
4392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  };
4402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
4412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  struct Shdr {
4422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word  sh_name;
4432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word  sh_type;
4442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Xword sh_flags;
4452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Addr  sh_addr;
4462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Off   sh_offset;
4472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Xword sh_size;
4482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word  sh_link;
4492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Word  sh_info;
4502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Xword sh_addralign;
4512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Xword sh_entsize;
4522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  };
4532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner};
4542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
4552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnertemplate <class ELF>
4562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerclass ElfParser {
4572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerpublic:
4582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  ElfParser(Reader& reader) : reader_(reader) {}
4592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
4602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef typename ELF::Word Word;
4612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef typename ELF::Sword Sword;
4622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef typename ELF::Addr Addr;
4632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef typename ELF::Off Off;
4642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef typename ELF::Half Half;
4652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef typename ELF::Header ElfHeader;
4662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef typename ELF::Shdr Shdr;
4672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
4682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Read an ELF::Word at a given position.
4692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  Word GetWordAt(off_t pos) {
4702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return reader_.GetU32At(pos);
4712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
4722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
4732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Read an ELF::Half at a given position.
4742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  Half GetHalfAt(off_t pos) {
4752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return reader_.GetU16At(pos);
4762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
4772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
4782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Read an ELF::Sword at a given position.
4792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  Sword GetSwordAt(off_t pos) {
4802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return static_cast<Sword>(GetWordAt(pos));
4812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
4822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
4832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Read an ELF::Addr at a given position.
4842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  Addr GetAddrAt(off_t pos);
4852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
4862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Read an ELF::Off at a given position.
4872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  Off GetOffAt(off_t pos) {
4882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return static_cast<Off>(GetAddrAt(pos));
4892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
4902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
4912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Helper class to iterate over the section table.
4922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  class SectionIterator {
4932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  public:
4942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    explicit SectionIterator(ElfParser& parser)
4952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      : parser_(parser) {
4962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      table_offset_ = parser_.GetOffAt(offsetof(ElfHeader, e_shoff));
4972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      table_count_ = parser_.GetHalfAt(offsetof(ElfHeader, e_shnum));
4982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      table_entry_size_ = parser_.GetHalfAt(offsetof(ElfHeader, e_shentsize));
4992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (table_entry_size_ < static_cast<Half>(sizeof(Shdr))) {
5002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        // malformed binary. Ignore all sections.
5012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        table_count_ = 0;
5022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
5032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
5042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
5052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Off NextOffset() {
5062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (table_count_ == 0)
5072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        return 0;
5082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      Off result = table_offset_;
5092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      table_offset_ += table_entry_size_;
5102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      table_count_ -= 1;
5112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      return result;
5122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
5132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
5142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    void Skip(int count) {
5152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      while (count > 0 && table_count_ > 0) {
5162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        table_offset_ += table_entry_size_;
5172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        table_count_--;
5182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        count--;
5192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
5202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
5212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
5222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  private:
5232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    ElfParser& parser_;
5242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Off table_offset_;
5252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half table_count_;
5262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Half table_entry_size_;
5272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  };
5282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
5292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Return the offset of the first section of a given type, or 0 if not
5302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // found. |*size| will be set to the section size in bytes in case of
5312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // success.
5322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  Off GetSectionOffsetByType(int table_type, Off* size) {
5332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    SectionIterator iter(*this);
5342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    for (;;) {
5352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      Off table_offset = iter.NextOffset();
5362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (table_offset == 0)
5372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        break;
5382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      Word sh_type = GetWordAt(table_offset + offsetof(Shdr, sh_type));
5392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (sh_type == static_cast<Word>(table_type)) {
5402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        *size = GetOffAt(table_offset + offsetof(Shdr, sh_size));
5412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        return GetOffAt(table_offset + offsetof(Shdr, sh_offset));
5422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
5432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
5442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return 0;
5452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
5462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
5472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Return the index of the string table for the dynamic section
5482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // in this ELF binary. Or 0 if not found.
5492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  int GetDynamicStringTableIndex() {
5502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    SectionIterator iter(*this);
5512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    for (;;) {
5522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      Off table_offset = iter.NextOffset();
5532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (table_offset == 0)
5542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        break;
5552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      Word sh_type = GetWordAt(table_offset + offsetof(Shdr, sh_type));
5562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (sh_type == SHT_DYNAMIC)
5572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        return GetWordAt(table_offset + offsetof(Shdr, sh_link));
5582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
5592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return 0;
5602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
5612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
5622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Return the offset of a section identified by its index, or 0 in case
5632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // of error (bad index).
5642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  Off GetSectionOffsetByIndex(int sec_index, Off* size) {
5652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    SectionIterator iter(*this);
5662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    iter.Skip(sec_index);
5672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Off table_offset = iter.NextOffset();
5682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (table_offset != 0) {
5692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      *size = GetOffAt(table_offset + offsetof(Shdr, sh_size));
5702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      return GetOffAt(table_offset + offsetof(Shdr, sh_offset));
5712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
5722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return 0;
5732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
5742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
5752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Return a string identified by its index and its string table
5762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Address. Returns an empty string in case of error.
5772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  String GetStringByIndex(Off str_index, int str_table_index) {
5782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    String result;
5792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
5802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (str_table_index != 0) {
5812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      Off str_table_size = 0;
5822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      Off str_table = GetSectionOffsetByIndex(str_table_index,
5832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner                                              &str_table_size);
5842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (str_table != 0 && str_index < str_table_size) {
5852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        str_table += str_index;
5862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        str_table_size -= str_index;
5872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        while (str_table_size > 0) {
5882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          const uint8_t* p = reader_.GetBytesAt(str_table, 1);
5892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          if (p == NULL || *p == '\0')
5902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner            break;
5912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          result.append(1, static_cast<const char>(*p));
5922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          str_table += 1;
5932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          str_table_size -= 1;
5942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        }
5952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
5962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
5972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return result;
5982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
5992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
6002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerprivate:
6012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  Reader& reader_;
6022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner};
6032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
6042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnertemplate <>
6052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' TurnerElf32::Addr ElfParser<Elf32>::GetAddrAt(off_t pos) {
6062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return reader_.GetU32At(pos);
6072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
6082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
6092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnertemplate <>
6102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' TurnerElf64::Addr ElfParser<Elf64>::GetAddrAt(off_t pos) {
6112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return reader_.GetU64At(pos);
6122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
6132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
6142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Helper class to iterate over items of a given type in the dynamic
6152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// section. A type of 0 (SHT_NULL) means iterate over all items.
6162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//
6172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Examples:
6182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//    // Iterate over all entries in the table, find the SHT_NEEDED ones.
6192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//    DynamicIterator<Elf32> iter(parser);
6202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//    while (iter.GetNext()) {
6212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//      if (iter.GetTag() == SHT_NEEDED) {
6222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//         Elf32::Off value = iter.GetValue();
6232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//         ...
6242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//      }
6252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//    }
6262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnertemplate <class ELF>
6272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerclass DynamicIterator {
6282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerpublic:
6292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  explicit DynamicIterator(ElfParser<ELF>& parser)
6302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    : parser_(parser),
6312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      dyn_size_(0),
6322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      dyn_offset_(0),
6332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      started_(false) {
6342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    dyn_offset_ = parser_.GetSectionOffsetByType(SHT_DYNAMIC, &dyn_size_);
6352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    started_ = (dyn_size_ < kEntrySize);
6362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
6372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
6382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  bool GetNext() {
6392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (!started_)
6402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      started_ = true;
6412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    else {
6422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (dyn_size_ < kEntrySize)
6432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        return false;
6442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      dyn_offset_ += kEntrySize;
6452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      dyn_size_ -= kEntrySize;
6462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
6472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return true;
6482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
6492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
6502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typename ELF::Off GetTag() {
6512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return parser_.GetOffAt(dyn_offset_);
6522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
6532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
6542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typename ELF::Off GetValue() {
6552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return parser_.GetOffAt(dyn_offset_ + kTagSize);
6562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
6572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
6582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerprivate:
6592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef typename ELF::Off Off;
6602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  static const Off kTagSize = static_cast<Off>(sizeof(Off));
6612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  static const Off kValueSize = kTagSize;
6622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  static const Off kEntrySize = kTagSize + kValueSize;
6632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
6642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  ElfParser<ELF>& parser_;
6652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  Off dyn_size_;
6662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  Off dyn_offset_;
6672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  bool started_;
6682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner};
6692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
6702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define DT_NEEDED 1
6712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define DT_SONAME 14
6722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
6732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnertemplate <class ELF>
6742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' TurnerString GetLibNameT(Reader& reader) {
6752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  ElfParser<ELF> parser(reader);
6762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  int str_table_index = parser.GetDynamicStringTableIndex();
6772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  DynamicIterator<ELF> iter(parser);
6782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  while (iter.GetNext()) {
6792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (iter.GetTag() == DT_SONAME) {
6802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      typename ELF::Off str_index = iter.GetValue();
6812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      return parser.GetStringByIndex(str_index, str_table_index);
6822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
6832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
6842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return String();
6852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
6862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
6872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnertemplate <class ELF>
6882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerint GetNeededLibsT(Reader& reader, std::vector<String>* result) {
6892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  ElfParser<ELF> parser(reader);
6902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  int str_table_index = parser.GetDynamicStringTableIndex();
6912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  DynamicIterator<ELF> iter(parser);
6922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  int count = 0;
6932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  while (iter.GetNext()) {
6942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (iter.GetTag() == DT_NEEDED) {
6952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      typename ELF::Off str_index = iter.GetValue();
6962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      String lib_name = parser.GetStringByIndex(str_index, str_table_index);
6972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (!lib_name.empty()) {
6982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        result->push_back(lib_name);
6992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        count++;
7002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
7012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
7022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
7032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return count;
7042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
7052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
7062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerclass ElfFile {
7072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerpublic:
7082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  ElfFile()
7092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    : file_(NULL), big_endian_(false), is_64bits_(false), reader_(NULL) {}
7102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
7112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  virtual ~ElfFile() {
7122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    delete reader_;
7132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Close();
7142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
7152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
7162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  bool Open(const TCHAR* path, String* error) {
7172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    Close();
7182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    file_ = _tfopen(path, _T("rb"));
7192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (file_ == NULL) {
7202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      error->assign(TO_STRING(strerror(errno)));
7212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      return false;
7222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
7232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    uint8_t ident[EI_NIDENT];
7242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (fread(ident, sizeof(ident), 1, file_) != 1) {
7252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      error->assign(TO_STRING(strerror(errno)));
7262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      Close();
7272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      return false;
7282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
7292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (!elf_ident_is_elf(ident)) {
7302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      *error = _T("Not an ELF binary file");
7312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      Close();
7322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      return false;
7332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
7342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    big_endian_ = elf_ident_is_big_endian(ident);
7352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    is_64bits_ = elf_ident_is_64bits(ident);
7362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
7372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (big_endian_) {
7382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      reader_ = new FileBigEndianReader(file_);
7392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    } else {
7402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      reader_ = new FileLittleEndianReader(file_);
7412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
7422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return true;
7432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
7442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
7452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  bool IsOk() { return file_ != NULL; }
7462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
7472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  bool IsBigEndian() { return big_endian_; }
7482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
7492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  const Reader& GetReader() { return *reader_; };
7502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
7512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Returns the embedded library name, extracted from the dynamic table.
7522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  String GetLibName() {
7532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (is_64bits_)
7542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      return GetLibNameT<Elf64>(*reader_);
7552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    else
7562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      return GetLibNameT<Elf32>(*reader_);
7572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
7582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
7592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Gets the list of needed libraries and appends them to |result|.
7602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Returns the number of library names appended.
7612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  int GetNeededLibs(std::vector<String>* result) {
7622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (is_64bits_)
7632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      return GetNeededLibsT<Elf64>(*reader_, result);
7642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    else
7652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      return GetNeededLibsT<Elf32>(*reader_, result);
7662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
7672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
7682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerprotected:
7692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  void Close() {
7702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (file_ != NULL) {
7712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      fclose(file_);
7722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      file_ = NULL;
7732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
7742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
7752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
7762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  FILE* file_;
7772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  bool big_endian_;
7782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  bool is_64bits_;
7792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  Reader* reader_;
7802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner};
7812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
7822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#ifdef __linux__
7832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerstatic bool IsLdSoConfSeparator(char ch) {
7842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // The ldconfig manpage indicates that /etc/ld.so.conf contains a list
7852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // of colon, space, tab newline or comma separated directories.
7862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return (ch == ' ' || ch == '\t' || ch == '\r' ||
7872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          ch == '\n' || ch == ',' || ch == ':');
7882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
7892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
7902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Parse the content of /etc/ld.so.conf, it contains according to the
7912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// documentation a 'comma, space, newline, tab separated list of
7922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// directories'. In practice, it can also include comments, and an
7932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// include directive and glob patterns, as in:
7942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner//  'include /etc/ld.so.conf.d/*.conf'
7952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnervoid AddHostLdSoConfPaths(const char* ld_so_conf_path,
7962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner                          std::vector<String>* lib_search_path) {
7972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  FILE* file = fopen(ld_so_conf_path, "rb");
7982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (!file)
7992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return;
8002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
8012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  char line[1024];
8022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  while (fgets(line, sizeof(line), file) != NULL) {
8032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const char* begin = line;
8042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const char* end = line + strlen(line);
8052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    while (end > begin && end[-1] == '\n')
8062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      end--;
8072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
8082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    bool prev_is_include = false;
8092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    while (begin < end) {
8102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      // Skip over separators
8112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      while (begin < end && IsLdSoConfSeparator(*begin))
8122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        begin++;
8132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
8142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (begin == end || begin[0] == '#') {
8152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        // Skip empty lines and comments.
8162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        break;
8172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
8182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      // Find end of current item
8192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      const char* next_pos = begin;
8202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      while (next_pos < end &&
8212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          !IsLdSoConfSeparator(*next_pos) &&
8222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          *next_pos != '#')
8232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        next_pos++;
8242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
8252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      size_t len = static_cast<size_t>(next_pos - begin);
8262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (prev_is_include) {
8272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        // If previous token was an 'include', treat this as a glob
8282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        // pattern and try to process all matching files.
8292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        prev_is_include = false;
8302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        if (len == 0) {
8312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          // Ignore stand-alone 'include' in a single line.
8322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          break;
8332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        }
8342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        String pattern(begin, len);
8352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        DLOG("%s: processing include '%s'\n",
8362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner             __FUNCTION__,
8372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner             pattern.c_str());
8382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
8392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        glob_t the_glob;
8402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        memset(&the_glob, 0, sizeof(the_glob));
8412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        int ret = ::glob(pattern.c_str(), 0, NULL, &the_glob);
8422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        if (ret == 0) {
8432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          // Iterate / include all matching files.
8442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          String filepath;
8452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          for (size_t n = 0; n < the_glob.gl_pathc; ++n) {
8462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner            filepath.assign(the_glob.gl_pathv[n]);
8472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner            DLOG("%s: Including %s\n", __FUNCTION__, filepath.c_str());
8482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner            AddHostLdSoConfPaths(filepath.c_str(), lib_search_path);
8492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          }
8502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        }
8512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        globfree(&the_glob);
8522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      } else {
8532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        // The previous token was not an 'include'. But is the current one?
8542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        static const char kInclude[] = "include";
8552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        const size_t kIncludeLen = sizeof(kInclude) - 1;
8562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        if (len == kIncludeLen && !memcmp(begin, kInclude, len)) {
8572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          prev_is_include = true;
8582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        } else if (len > 0) {
8592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          // No, it must be a directory name.
8602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          String dirpath(begin, len);
8612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          struct stat st;
8622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          if (::stat(dirpath.c_str(), &st) != 0) {
8632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner            LOG("Could not stat(): %s: %s\n", dirpath.c_str(), strerror(errno));
8642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          } else if (!S_ISDIR(st.st_mode)) {
8652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner            LOG("Not a directory: %s\n", dirpath.c_str());
8662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          } else {
8672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner            DLOG("%s: Adding %s\n", __FUNCTION__, dirpath.c_str());
8682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner            lib_search_path->push_back(dirpath);
8692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          }
8702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        }
8712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
8722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      // switch to next item in line.
8732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      begin = next_pos;
8742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
8752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
8762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  fclose(file);
8772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
8782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif  // __linux__
8792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
8802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Add host shared library search path to |lib_search_path|
8812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnervoid AddHostLibraryPaths(std::vector<String>* lib_search_path) {
8822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Only add libraries form LD_LIBRARY_PATH on ELF-based systems.
8832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#if defined(__ELF__)
8842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // If LD_LIBRARY_PATH is defined, process it
8852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  const TCHAR* env = _tgetenv(_T("LD_LIBRARY_PATH"));
8862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (env != NULL) {
8872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const TCHAR* pos = env;
8882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    while (*pos) {
8892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      size_t path_len;
8902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      const TCHAR* next_pos = _tcschr(pos, ':');
8912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (next_pos == NULL) {
8922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        path_len = _tcslen(pos);
8932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        next_pos = pos + path_len;
8942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      } else {
8952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        path_len = next_pos - pos;
8962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        next_pos += 1;
8972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
8982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
8992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (path_len == 0) {
9002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        // Per POSIX convention, an empty path item means "current path".
9012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        // Not that this is generally a very bad idea, security-wise.
9022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        lib_search_path->push_back(_T("."));
9032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      } else {
9042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        lib_search_path->push_back(String(pos, path_len));
9052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
9062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
9072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      pos = next_pos;
9082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
9092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
9102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#ifdef __linux__
9112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  AddHostLdSoConfPaths("/etc/ld.so.conf", lib_search_path);
9122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
9132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // TODO(digit): What about BSD systems?
9142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
9152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
9162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
9172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Returns true if |libname| is the name of an Android system library.
9182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerbool IsAndroidSystemLib(const String& libname) {
9192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  static const TCHAR* const kAndroidSystemLibs[] = {
9202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _T("libc.so"),
9212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _T("libdl.so"),
9222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _T("liblog.so"),
9232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _T("libm.so"),
9242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _T("libstdc++.so"),
9252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _T("libz.so"),
9262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _T("libandroid.so"),
9272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _T("libjnigraphics.so"),
9282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _T("libEGL.so"),
9292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _T("libGLESv1_CM.so"),
9302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _T("libGLESv2.so"),
9312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _T("libOpenSLES.so"),
9322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _T("libOpenMAXAL.so"),
9332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    NULL
9342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  };
9352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  for (size_t n = 0; kAndroidSystemLibs[n] != NULL; ++n) {
9362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (!libname.compare(kAndroidSystemLibs[n]))
9372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      return true;
9382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
9392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return false;
9402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
9412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
9422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Returns true if |libname| is the name of an NDK-compatible shared
9432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// library. This means its must begin with "lib" and end with "so"
9442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// (without any version numbers).
9452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerbool IsAndroidNdkCompatibleLib(const String& libname) {
9462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return libname.size() > 6 &&
9472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner         !libname.compare(0, 3, _T("lib")) &&
9482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner         !libname.compare(libname.size() - 3, 3, _T(".so"));
9492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
9502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
9512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Try to find a library named |libname| in |search_paths|
9522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Returns true on success, and sets |result| to the full library path,
9532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// false otherwise.
9542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerbool FindLibraryPath(const String& libname,
9552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner                     const std::vector<String>& search_paths,
9562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner                     String* result) {
9572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Check in the search paths.
9582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  LOG2(_T("  looking for library: %s\n"), libname.c_str());
9592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  for (size_t n = 0; n < search_paths.size(); ++n) {
9602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    String file_path = search_paths[n];
9612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (file_path.empty())
9622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      continue;
9632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (file_path[file_path.size() - 1] != _T('/') &&
9642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        file_path[file_path.size() - 1] != _T('\\')) {
9652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      file_path.append(_T("/"));
9662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
9672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    file_path.append(libname);
9682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
9692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    LOG2(_T("    in %s: "), file_path.c_str());
9702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    struct _stat st;
9712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (_tstat(file_path.c_str(), &st) < 0) {
9722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      LOG2(_T("%s\n"), TO_CONST_TCHAR(strerror(errno)));
9732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      continue;
9742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
9752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (!S_ISREG(st.st_mode)) {
9762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      LOG2(_T("Not a regular file!\n"));
9772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      continue;
9782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
9792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // Found the library file.
9802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    LOG2(_T("OK\n"));
9812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    result->assign(file_path);
9822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return true;
9832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
9842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
9852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return false;
9862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
9872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
9882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Recursive support
9892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
9902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerstruct LibNode {
9912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // An enumeration listing possible node types, which are:
9922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  enum Type {
9932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    NODE_NONE,   // No type yet.
9942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    NODE_PATH,   // Valid ELF library, |value| is file path.
9952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    NODE_ERROR,  // Invalid library name, |value| is error string.
9962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    NODE_SYSTEM, // Android system library, |value| is library name.
9972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  };
9982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
9992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  Type type;
10002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  String value;
10012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  std::vector<String> needed_libs;
10022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  LibNode() : type(NODE_NONE), value(), needed_libs() {}
10042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  explicit LibNode(const String& path)
10062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    : type(NODE_PATH), value(path), needed_libs() {}
10072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  void Set(Type type_p, const String& value_p) {
10092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    type = type_p;
10102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    value = value_p;
10112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
10122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner};
10132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnertypedef std::map<String, LibNode> DependencyGraph;
10152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnertypedef std::list<String> WorkQueue;
10162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Used internally by BuildDependencyGraph().
10182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnervoid UpdateDependencies(
10192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const String& libname,
10202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const String& libpath,
10212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    DependencyGraph& deps,
10222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    WorkQueue& queue) {
10232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  DLOG(_T("UPDATE libname=%s path=%s\n"), libname.c_str(), libpath.c_str());
10242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Sanity check: find if the library is already in the graph.
10252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (!libname.empty() && deps.find(libname) != deps.end()) {
10262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // Should not happen.
10272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    panic(_T("INTERNAL: Library already in graph: %s"), libname.c_str());
10282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
10292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  LibNode node;
10312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  ElfFile libfile;
10322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  String error;
10332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  String soname = libname;
10342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (!libfile.Open(libpath.c_str(), &error)) {
10352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    node.Set(LibNode::NODE_ERROR, error);
10362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  } else {
10372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    String soname = libfile.GetLibName();
10382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (soname.empty())
10392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      soname = libname;
10402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    else if (soname != libname) {
10412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      _ftprintf(stderr,
10422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner                _T("WARNING: Library has invalid soname ('%s'): %s\n"),
10432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner                soname.c_str(),
10442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner                libpath.c_str());
10452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
10462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // Discovered a new library, get its dependent libraries.
10472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    node.Set(LibNode::NODE_PATH, libpath);
10482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    libfile.GetNeededLibs(&node.needed_libs);
10492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    LOG(_T("%s depends on:"), soname.c_str());
10512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // Add them to the work queue.
10532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    for (size_t n = 0; n < node.needed_libs.size(); ++n) {
10542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      LOG(_T(" %s"), node.needed_libs[n].c_str());
10552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      queue.push_back(node.needed_libs[n]);
10562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
10572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    LOG(_T("\n"));
10582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
10592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  deps[soname] = node;
10602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
10612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Build the full dependency graph.
10632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// |root_libpath| is the path of the root library.
10642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// |lib_search_path| is the list of library search paths.
10652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Returns a new dependency graph object.
10662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' TurnerDependencyGraph BuildDependencyGraph(
10672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const String& root_libpath,
10682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const std::vector<String>& lib_search_path) {
10692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  DependencyGraph deps;
10702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  std::list<String> queue;
10712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // As a first step, build the full dependency graph, starting with the
10732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // root library. This records errors in the graph too.
10742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  UpdateDependencies(path_basename(root_libpath),
10752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner                     root_libpath,
10762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner                     deps, queue);
10772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  while (!queue.empty()) {
10792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // Pop first item from queue.
10802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    String libname = queue.front();
10812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    queue.pop_front();
10822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // Is the library already in the graph?
10842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    DependencyGraph::iterator iter = deps.find(libname);
10852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (iter != deps.end()) {
10862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      // Library already found, skip it.
10872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      continue;
10882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
10892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // Find the library in the current search path.
10912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    String libpath;
10922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (FindLibraryPath(libname, lib_search_path, &libpath)) {
10932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      UpdateDependencies(libname, libpath, deps, queue);
10942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      continue;
10952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
10962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
10972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (IsAndroidSystemLib(libname)) {
10982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      LOG(_T("Android system library: %s\n"), libname.c_str());
10992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      LibNode node;
11002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      node.Set(LibNode::NODE_SYSTEM, libname);
11012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      deps[libname] = node;
11022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      continue;
11032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
11042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
11052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _ftprintf(stderr,
11062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner              _T("WARNING: Could not find library: %s\n"),
11072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner              libname.c_str());
11082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    LibNode node;
11092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    node.Set(LibNode::NODE_ERROR, _T("Could not find library"));
11102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    deps[libname] = node;
11112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
11122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
11132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return deps;
11142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
11152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
11162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Print the dependency graph in a human-readable format to stdout.
11172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnervoid DumpDependencyGraph(const DependencyGraph& deps) {
11182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  _tprintf(_T("Dependency graph:\n"));
11192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  DependencyGraph::const_iterator iter = deps.begin();
11202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  for ( ; iter != deps.end(); ++iter ) {
11212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const String& libname = iter->first;
11222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const LibNode& node = iter->second;
11232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    String node_type;
11242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    switch (node.type) {
11252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      case LibNode::NODE_NONE:  // should not happen.
11262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        node_type = _T("NONE??");
11272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        break;
11282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      case LibNode::NODE_PATH:
11292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        node_type = _T("PATH");
11302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        break;
11312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      case LibNode::NODE_ERROR:
11322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        node_type = _T("ERROR");
11332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        break;
11342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      case LibNode::NODE_SYSTEM:
11352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        node_type = _T("SYSTEM");
11362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
11372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _tprintf(
11382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        _T("[%s] %s %s\n"),
11392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        libname.c_str(),
11402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        node_type.c_str(),
11412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        node.value.c_str());
11422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
11432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (node.type == LibNode::NODE_PATH) {
11442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      for (size_t n = 0; n < node.needed_libs.size(); ++n) {
11452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        _tprintf(_T("    %s\n"), node.needed_libs[n].c_str());
11462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
11472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
11482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
11492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
11502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
11512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Return the sorted list of libraries from a dependency graph.
11522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// They are topologically ordered, i.e. a library appears always
11532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// before any other library it depends on.
11542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnervoid GetTopologicalSortedLibraries(
11552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    DependencyGraph& deps,
11562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    std::vector<String>* result) {
11572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  result->clear();
11582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // First: Compute the number of visitors per library in the graph.
11592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  typedef std::map<String, int> VisitorMap;
11602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  VisitorMap visitors;
11612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  for (DependencyGraph::const_iterator iter = deps.begin();
11622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      iter != deps.end();
11632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      ++iter) {
11642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (visitors.find(iter->first) == visitors.end()) {
11652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      visitors[iter->first] = 0;
11662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
11672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
11682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const std::vector<String>& needed_libs = iter->second.needed_libs;
11692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    for (size_t n = 0; n < needed_libs.size(); ++n) {
11702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      const String& libname = needed_libs[n];
11712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      VisitorMap::iterator lib_iter = visitors.find(libname);
11722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (lib_iter != visitors.end())
11732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        lib_iter->second += 1;
11742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      else
11752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        visitors[libname] = 1;
11762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
11772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
11782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
11792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#if DEBUG
11802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  {
11812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    VisitorMap::const_iterator iter_end = visitors.end();
11822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    VisitorMap::const_iterator iter = visitors.begin();
11832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    for ( ; iter != iter_end; ++iter ) {
11842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      _tprintf(_T("-- %s %d\n"), iter->first.c_str(), iter->second);
11852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
11862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
11872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
11882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
11892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  while (!visitors.empty()) {
11902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // Find the library with the smallest number of visitors.
11912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // The value should be 0, unless there are circular dependencies.
11922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    VisitorMap::const_iterator iter_end = visitors.end();
11932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    VisitorMap::const_iterator iter;
11942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    int min_visitors = INT_MAX;
11952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    String min_libname;
11962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    for (iter = visitors.begin(); iter != iter_end; ++iter) {
11972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      // Note: Uses <= instead of < to ensure better diagnostics in
11982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      // case of circular dependencies. This shall return the latest
11992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      // node in the cycle, i.e. the first one where a 'back' edge
12002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      // exists.
12012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (iter->second <= min_visitors) {
12022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        min_libname = iter->first;
12032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        min_visitors = iter->second;
12042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
12052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
12062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (min_visitors == INT_MAX) {
12082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      // Should not happen.
12092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      panic(_T("INTERNAL: Could not find minimum visited node!"));
12102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
12112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // min_visitors should be 0, unless there are circular dependencies.
12132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (min_visitors != 0) {
12142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      // Warn about circular dependencies
12152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      _ftprintf(stderr,
12162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner                _T("WARNING: Circular dependency found from: %s\n"),
12172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner                min_libname.c_str());
12182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
12192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // Remove minimum node from the graph, and decrement the visitor
12212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // count of all its needed libraries. This also breaks dependency
12222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // cycles.
12232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    result->push_back(min_libname);
12242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const LibNode& node = deps[min_libname];
12252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const std::vector<String> needed_libs = node.needed_libs;
12262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    visitors.erase(min_libname);
12272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    for (size_t n = 0; n < needed_libs.size(); ++n)
12292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      visitors[needed_libs[n]]--;
12302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
12312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
12322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner// Main function
12342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#define PROGNAME "ndk-depends"
12362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnervoid print_usage(int exit_code) {
12382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  printf(
12392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "Usage: %s [options] <elf-file>\n\n"
12402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "This program is used to print the dependencies of a given ELF\n"
12422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "binary (shared library or executable). It supports any architecture,\n"
12432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "endianess and bitness.\n\n"
12442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "By default, all dependencies are printed in topological order,\n"
12462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "which means that each item always appear before other items\n"
12472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "it depends on. Except in case of circular dependencies, which will\n"
12482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "print a warning to stderr.\n\n"
12492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "The tool will try to find other libraries in the same directory\n"
12512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "as the input ELF file. It is possible however to provide\n"
12522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "additional search paths with the -L<path>, which adds an explicit path\n"
12532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "or --host-libs which adds host-specific library paths, on ELF-based systems\n"
12542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "only.\n\n"
12552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "Use --print-paths to print the path of each ELF binary.\n\n"
12572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "Use --print-direct to only print the direct dependencies\n"
12592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "of the input ELF binary. All other options except --verbose will be ignored.\n\n"
12602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "Use --print-java to print a Java source fragment that loads the\n"
12622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "libraries with System.loadLibrary() in the correct order. This can\n"
12632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "be useful when copied into your application's Java source code.\n\n"
12642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "Use --print-dot to print the dependency graph as a .dot file that can be\n"
12662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "parsed by the GraphViz tool. For example, to generate a PNG image of the\n"
12672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "graph, use something like:\n\n"
12682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "  ndk-depends /path/to/libfoo.so --print-dot | dot -Tpng -o /tmp/graph.png\n\n"
12702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "The --verbose option prints debugging information, which can be useful\n"
12722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "to diagnose problems with malformed ELF binaries.\n\n"
12732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "Valid options:\n"
12752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "  --help|-h|-?    Print this message.\n"
12762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "  --verbose       Increase verbosity.\n"
12772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "  --print-direct  Only print direct dependencies.\n"
12782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "  -L<path>        Append <path> to the library search path.\n"
12792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "  --host-libs     Append host library search path.\n"
12802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "  --print-paths   Print full paths of all libraries.\n"
12812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "  --print-java    Print Java library load sequence.\n"
12822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "  --print-dot     Print the dependency graph as a Graphviz .dot file.\n"
12832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    "\n", PROGNAME);
12842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  exit(exit_code);
12862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
12872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}  // namespace
12892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#ifdef _WIN32
12922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerint main(void) {
12932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  int argc = 0;
12942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  TCHAR** argv = CommandLineToArgvW(GetCommandLine(), &argc);
12952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#else
12962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turnerint main(int argc, const char** argv) {
12972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner#endif
12982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
12992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  enum PrintFormat {
13002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    PRINT_DEFAULT = 0,
13012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    PRINT_DIRECT,
13022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    PRINT_PATHS,
13032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    PRINT_JAVA,
13042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    PRINT_DOT_FILE,
13052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  };
13062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  bool do_help = false;
13082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  PrintFormat print_format = PRINT_DEFAULT;
13092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  std::vector<String> lib_search_path;
13102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  std::vector<String> params;
13112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Process options.
13132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  while (argc > 1) {
13142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    if (argv[1][0] == _T('-')) {
13152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      const TCHAR* arg = argv[1];
13162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (!_tcscmp(arg, _T("--help")) ||
13172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          !_tcscmp(arg, _T("-h")) ||
13182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          !_tcscmp(arg, _T("-?")))
13192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        do_help = true;
13202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      else if (!_tcscmp(arg, _T("--print-direct"))) {
13212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        print_format = PRINT_DIRECT;
13222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      } else if (!_tcscmp(arg, _T("-L"))) {
13232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        if (argc < 3)
13242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          panic(_T("Option -L requires an argument."));
13252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        lib_search_path.push_back(String(argv[2]));
13262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        argc--;
13272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        argv++;
13282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      } else if (!_tcsncmp(arg, _T("-L"), 2)) {
13292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        lib_search_path.push_back(String(arg+2));
13302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      } else if (!_tcscmp(arg, _T("--host-libs"))) {
13312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        AddHostLibraryPaths(&lib_search_path);
13322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      } else if (!_tcscmp(arg, _T("--print-java"))) {
13332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        print_format = PRINT_JAVA;
13342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      } else if (!_tcscmp(arg, _T("--print-paths"))) {
13352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        print_format = PRINT_PATHS;
13362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      } else if (!_tcscmp(arg, _T("--print-dot"))) {
13372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        print_format = PRINT_DOT_FILE;
13382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      } else if (!_tcscmp(arg, _T("--verbose"))) {
13392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        g_verbose++;
13402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      } else {
13412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        panic(_T("Unsupported option '%s', see --help."), arg);
13422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
13432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    } else {
13442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      params.push_back(String(argv[1]));
13452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
13462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    argc--;
13472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    argv++;
13482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
13492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (do_help)
13512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    print_usage(0);
13522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (params.empty())
13542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    panic(_T("Please provide the path of an ELF shared library or executable."
13552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner             "\nSee --help for usage details."));
13562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Insert ELF file directory at the head of the search path.
13582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  lib_search_path.insert(lib_search_path.begin(), path_dirname(params[0]));
13592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (g_verbose >= 1) {
13612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _tprintf(_T("Current library search path:\n"));
13622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    for (size_t n = 0; n < lib_search_path.size(); ++n)
13632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      _tprintf(_T("  %s\n"), lib_search_path[n].c_str());
13642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _tprintf(_T("\n"));
13652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
13662454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13672454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Open main input file.
13682454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  const TCHAR* libfile_path = params[0].c_str();
13692454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13702454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  ElfFile libfile;
13712454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  String error;
13722454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (!libfile.Open(libfile_path, &error)) {
13732454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    panic(_T("Could not open file '%s': %s"), libfile_path, error.c_str());
13742454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
13752454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13762454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (print_format == PRINT_DIRECT) {
13772454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // Simple dump, one line per dependency. No frills, no recursion.
13782454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    std::vector<String> needed_libs;
13792454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    libfile.GetNeededLibs(&needed_libs);
13802454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13812454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    for (size_t i = 0; i < needed_libs.size(); ++i)
13822454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      _tprintf(_T("%s\n"), needed_libs[i].c_str());
13832454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13842454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return 0;
13852454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
13862454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13872454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Topological sort of all dependencies.
13882454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  LOG(_T("Building dependency graph...\n"));
13892454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  DependencyGraph deps = BuildDependencyGraph(
13902454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      libfile_path, lib_search_path);
13912454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13922454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (g_verbose >= 2)
13932454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    DumpDependencyGraph(deps);
13942454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13952454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  LOG(_T("Building sorted list of binaries:\n"));
13962454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  std::vector<String> needed_libs;
13972454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  GetTopologicalSortedLibraries(deps, &needed_libs);
13982454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
13992454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (print_format == PRINT_JAVA) {
14002454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // Print Java libraries in reverse order.
14012454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    std::reverse(needed_libs.begin(), needed_libs.end());
14022454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    for (size_t i = 0; i < needed_libs.size(); ++i) {
14032454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      const String& lib = needed_libs[i];
14042454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (IsAndroidSystemLib(lib)) {
14052454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        // Skip system libraries.
14062454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        continue;
14072454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
14082454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      if (!IsAndroidNdkCompatibleLib(lib)) {
14092454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        _ftprintf(
14102454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner            stderr,
14112454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner            _T("WARNING: Non-compatible library name ignored: %s\n"),
14122454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner            lib.c_str());
14132454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        continue;
14142454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
14152454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      _tprintf(_T("System.loadLibrary(%s);\n"),
14162454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner                lib.substr(3, lib.size() - 6).c_str());
14172454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
14182454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return 0;
14192454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
14202454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
14212454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (print_format == PRINT_DOT_FILE) {
14222454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // Using the topological order helps generates a more human-friendly
14232454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // directed graph.
14242454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _tprintf(_T("digraph {\n"));
14252454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    for (size_t i = 0; i < needed_libs.size(); ++i) {
14262454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      const String& libname = needed_libs[i];
14272454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      const std::vector<String>& libdeps = deps[libname].needed_libs;
14282454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      for (size_t n = 0; n < libdeps.size(); ++n) {
14292454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        // Note: Use quoting to deal with special characters like -
14302454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        // which are not normally part of DOT 'id' tokens.
14312454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        _tprintf(_T("  \"%s\" -> \"%s\"\n"), libname.c_str(), libdeps[n].c_str());
14322454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
14332454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
14342454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _tprintf(_T("}\n"));
14352454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return 0;
14362454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
14372454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
14382454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  if (print_format == PRINT_PATHS) {
14392454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    // Print libraries with path.
14402454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    for (size_t i = 0; i < needed_libs.size(); ++i) {
14412454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      const String& lib = needed_libs[i];
14422454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      LibNode& node = deps[lib];
14432454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      const TCHAR* format;
14442454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      switch (node.type) {
14452454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        case LibNode::NODE_PATH:
14462454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          format = _T("%s -> %s\n");
14472454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          break;
14482454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        case LibNode::NODE_SYSTEM:
14492454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          format = _T("%s -> $ /system/lib/%s\n");
14502454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          break;
14512454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner        default:
14522454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner          format = _T("%s -> !! %s\n");
14532454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      }
14542454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner      _tprintf(format, lib.c_str(), deps[lib].value.c_str());
14552454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    }
14562454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    return 0;
14572454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
14582454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner
14592454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  // Print simple library names.
14602454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  for (size_t i = 0; i < needed_libs.size(); ++i) {
14612454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    const String& lib = needed_libs[i];
14622454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner    _tprintf(_T("%s\n"), lib.c_str());
14632454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  }
14642454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner  return 0;
14652454d616a21ad5d1382b0c0615e6ead399433cc5David 'Digit' Turner}
1466