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