LCOV - code coverage report
Current view: top level - tools/profiler/core - shared-libraries-linux.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 2 69 2.9 %
Date: 2017-07-14 16:53:18 Functions: 1 5 20.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "shared-libraries.h"
       8             : 
       9             : #define PATH_MAX_TOSTRING(x) #x
      10             : #define PATH_MAX_STRING(x) PATH_MAX_TOSTRING(x)
      11             : #include <stdlib.h>
      12             : #include <stdio.h>
      13             : #include <string.h>
      14             : #include <limits.h>
      15             : #include <unistd.h>
      16             : #include <fstream>
      17             : #include "platform.h"
      18             : #include "shared-libraries.h"
      19             : #include "mozilla/Sprintf.h"
      20             : #include "mozilla/Unused.h"
      21             : #include "nsDebug.h"
      22             : #include "nsNativeCharsetUtils.h"
      23             : 
      24             : #include "common/linux/file_id.h"
      25             : #include <algorithm>
      26             : #include <dlfcn.h>
      27             : #include <features.h>
      28             : #include <sys/types.h>
      29             : 
      30             : #if defined(GP_OS_linux)
      31             : # include <link.h>      // dl_phdr_info
      32             : #elif defined(GP_OS_android)
      33             : # include "ElfLoader.h" // dl_phdr_info
      34             : extern "C" MOZ_EXPORT __attribute__((weak))
      35             : int dl_iterate_phdr(
      36             :           int (*callback)(struct dl_phdr_info *info, size_t size, void *data),
      37             :           void *data);
      38             : #else
      39             : # error "Unexpected configuration"
      40             : #endif
      41             : 
      42             : // Get the breakpad Id for the binary file pointed by bin_name
      43           0 : static std::string getId(const char *bin_name)
      44             : {
      45             :   using namespace google_breakpad;
      46             :   using namespace std;
      47             : 
      48           0 :   PageAllocator allocator;
      49           0 :   auto_wasteful_vector<uint8_t, sizeof(MDGUID)> identifier(&allocator);
      50             : 
      51           0 :   FileID file_id(bin_name);
      52           0 :   if (file_id.ElfFileIdentifier(identifier)) {
      53           0 :     return FileID::ConvertIdentifierToUUIDString(identifier) + "0";
      54             :   }
      55             : 
      56           0 :   return "";
      57             : }
      58             : 
      59             : static SharedLibrary
      60           0 : SharedLibraryAtPath(const char* path, unsigned long libStart,
      61             :                     unsigned long libEnd, unsigned long offset = 0)
      62             : {
      63           0 :   nsAutoString pathStr;
      64             :   mozilla::Unused <<
      65           0 :     NS_WARN_IF(NS_FAILED(NS_CopyNativeToUnicode(nsDependentCString(path),
      66             :                                                 pathStr)));
      67             : 
      68           0 :   nsAutoString nameStr = pathStr;
      69           0 :   int32_t pos = nameStr.RFindChar('/');
      70           0 :   if (pos != kNotFound) {
      71           0 :     nameStr.Cut(0, pos + 1);
      72             :   }
      73             : 
      74           0 :   return SharedLibrary(libStart, libEnd, offset, getId(path),
      75             :                        nameStr, pathStr, nameStr, pathStr,
      76           0 :                        "", "");
      77             : }
      78             : 
      79             : static int
      80           0 : dl_iterate_callback(struct dl_phdr_info *dl_info, size_t size, void *data)
      81             : {
      82           0 :   SharedLibraryInfo& info = *reinterpret_cast<SharedLibraryInfo*>(data);
      83             : 
      84           0 :   if (dl_info->dlpi_phnum <= 0)
      85           0 :     return 0;
      86             : 
      87           0 :   unsigned long libStart = -1;
      88           0 :   unsigned long libEnd = 0;
      89             : 
      90           0 :   for (size_t i = 0; i < dl_info->dlpi_phnum; i++) {
      91           0 :     if (dl_info->dlpi_phdr[i].p_type != PT_LOAD) {
      92           0 :       continue;
      93             :     }
      94           0 :     unsigned long start = dl_info->dlpi_addr + dl_info->dlpi_phdr[i].p_vaddr;
      95           0 :     unsigned long end = start + dl_info->dlpi_phdr[i].p_memsz;
      96           0 :     if (start < libStart)
      97           0 :       libStart = start;
      98           0 :     if (end > libEnd)
      99           0 :       libEnd = end;
     100             :   }
     101             : 
     102             :   info.AddSharedLibrary(
     103           0 :     SharedLibraryAtPath(dl_info->dlpi_name, libStart, libEnd));
     104             : 
     105           0 :   return 0;
     106             : }
     107             : 
     108           0 : SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
     109             : {
     110           0 :   SharedLibraryInfo info;
     111             : 
     112             : #if defined(GP_OS_linux)
     113             :   // We need to find the name of the executable (exeName, exeNameLen) and the
     114             :   // address of its executable section (exeExeAddr) in the running image.
     115             :   char exeName[PATH_MAX];
     116           0 :   memset(exeName, 0, sizeof(exeName));
     117             : 
     118           0 :   ssize_t exeNameLen = readlink("/proc/self/exe", exeName, sizeof(exeName) - 1);
     119           0 :   if (exeNameLen == -1) {
     120             :     // readlink failed for whatever reason.  Note this, but keep going.
     121           0 :     exeName[0] = '\0';
     122           0 :     exeNameLen = 0;
     123           0 :     LOG("SharedLibraryInfo::GetInfoForSelf(): readlink failed");
     124             :   } else {
     125             :     // Assert no buffer overflow.
     126           0 :     MOZ_RELEASE_ASSERT(exeNameLen >= 0 &&
     127             :                        exeNameLen < static_cast<ssize_t>(sizeof(exeName)));
     128             :   }
     129             : 
     130           0 :   unsigned long exeExeAddr = 0;
     131             : #endif
     132             : 
     133             : #if defined(GP_OS_android)
     134             :   // If dl_iterate_phdr doesn't exist, we give up immediately.
     135             :   if (!dl_iterate_phdr) {
     136             :     // On ARM Android, dl_iterate_phdr is provided by the custom linker.
     137             :     // So if libxul was loaded by the system linker (e.g. as part of
     138             :     // xpcshell when running tests), it won't be available and we should
     139             :     // not call it.
     140             :     return info;
     141             :   }
     142             : #endif
     143             : 
     144             :   // Read info from /proc/self/maps. We ignore most of it.
     145           0 :   pid_t pid = getpid();
     146             :   char path[PATH_MAX];
     147           0 :   SprintfLiteral(path, "/proc/%d/maps", pid);
     148           0 :   std::ifstream maps(path);
     149           0 :   std::string line;
     150           0 :   while (std::getline(maps, line)) {
     151             :     int ret;
     152             :     unsigned long start;
     153             :     unsigned long end;
     154           0 :     char perm[6 + 1] = "";
     155             :     unsigned long offset;
     156           0 :     char modulePath[PATH_MAX + 1] = "";
     157           0 :     ret = sscanf(line.c_str(),
     158             :                  "%lx-%lx %6s %lx %*s %*x %" PATH_MAX_STRING(PATH_MAX) "s\n",
     159           0 :                  &start, &end, perm, &offset, modulePath);
     160           0 :     if (!strchr(perm, 'x')) {
     161             :       // Ignore non executable entries
     162           0 :       continue;
     163             :     }
     164           0 :     if (ret != 5 && ret != 4) {
     165           0 :       LOG("SharedLibraryInfo::GetInfoForSelf(): "
     166             :           "reading /proc/self/maps failed");
     167           0 :       continue;
     168             :     }
     169             : 
     170             : #if defined(GP_OS_linux)
     171             :     // Try to establish the main executable's load address.
     172           0 :     if (exeNameLen > 0 && strcmp(modulePath, exeName) == 0) {
     173           0 :       exeExeAddr = start;
     174             :     }
     175             : #elif defined(GP_OS_android)
     176             :     // Use /proc/pid/maps to get the dalvik-jit section since it has no
     177             :     // associated phdrs.
     178             :     if (0 == strcmp(modulePath, "/dev/ashmem/dalvik-jit-code-cache")) {
     179             :       info.AddSharedLibrary(SharedLibraryAtPath(modulePath, start, end,
     180             :                                                 offset));
     181             :       if (info.GetSize() > 10000) {
     182             :         LOG("SharedLibraryInfo::GetInfoForSelf(): "
     183             :             "implausibly large number of mappings acquired");
     184             :         break;
     185             :       }
     186             :     }
     187             : #endif
     188             :   }
     189             : 
     190             :   // We collect the bulk of the library info using dl_iterate_phdr.
     191           0 :   dl_iterate_phdr(dl_iterate_callback, &info);
     192             : 
     193             : #if defined(GP_OS_linux)
     194             :   // Make another pass over the information we just harvested from
     195             :   // dl_iterate_phdr.  If we see a nameless object mapped at what we earlier
     196             :   // established to be the main executable's load address, attach the
     197             :   // executable's name to that entry.
     198           0 :   for (size_t i = 0; i < info.GetSize(); i++) {
     199           0 :     SharedLibrary& lib = info.GetMutableEntry(i);
     200           0 :     if (lib.GetStart() == exeExeAddr && lib.GetNativeDebugPath() == "") {
     201           0 :       lib = SharedLibraryAtPath(exeName, lib.GetStart(), lib.GetEnd(),
     202           0 :                                 lib.GetOffset());
     203             : 
     204             :       // We only expect to see one such entry.
     205           0 :       break;
     206             :     }
     207             :   }
     208             : #endif
     209             : 
     210           0 :   return info;
     211             : }
     212             : 
     213             : void
     214           3 : SharedLibraryInfo::Initialize()
     215             : {
     216             :   /* do nothing */
     217           3 : }

Generated by: LCOV version 1.13