tools/profiler/shared-libraries-win32.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/profiler/shared-libraries-win32.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,137 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include <windows.h>
    1.10 +#include <tlhelp32.h>
    1.11 +#include <dbghelp.h>
    1.12 +#include <sstream>
    1.13 +
    1.14 +#include "shared-libraries.h"
    1.15 +#include "nsWindowsHelpers.h"
    1.16 +
    1.17 +#define CV_SIGNATURE 0x53445352 // 'SDSR'
    1.18 +
    1.19 +struct CodeViewRecord70
    1.20 +{
    1.21 +  uint32_t signature;
    1.22 +  GUID pdbSignature;
    1.23 +  uint32_t pdbAge;
    1.24 +  char pdbFileName[1];
    1.25 +};
    1.26 +
    1.27 +static bool GetPdbInfo(uintptr_t aStart, nsID& aSignature, uint32_t& aAge, char** aPdbName)
    1.28 +{
    1.29 +  if (!aStart) {
    1.30 +    return false;
    1.31 +  }
    1.32 +
    1.33 +  PIMAGE_DOS_HEADER dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(aStart);
    1.34 +  if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
    1.35 +    return false;
    1.36 +  }
    1.37 +
    1.38 +  PIMAGE_NT_HEADERS ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(
    1.39 +      aStart + dosHeader->e_lfanew);
    1.40 +  if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) {
    1.41 +    return false;
    1.42 +  }
    1.43 +
    1.44 +  uint32_t relativeVirtualAddress =
    1.45 +    ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
    1.46 +  if (!relativeVirtualAddress) {
    1.47 +    return false;
    1.48 +  }
    1.49 +
    1.50 +  PIMAGE_DEBUG_DIRECTORY debugDirectory =
    1.51 +    reinterpret_cast<PIMAGE_DEBUG_DIRECTORY>(aStart + relativeVirtualAddress);
    1.52 +  if (!debugDirectory || debugDirectory->Type != IMAGE_DEBUG_TYPE_CODEVIEW) {
    1.53 +    return false;
    1.54 +  }
    1.55 +
    1.56 +  CodeViewRecord70 *debugInfo = reinterpret_cast<CodeViewRecord70 *>(
    1.57 +      aStart + debugDirectory->AddressOfRawData);
    1.58 +  if (!debugInfo || debugInfo->signature != CV_SIGNATURE) {
    1.59 +    return false;
    1.60 +  }
    1.61 +
    1.62 +  aAge = debugInfo->pdbAge;
    1.63 +  GUID& pdbSignature = debugInfo->pdbSignature;
    1.64 +  aSignature.m0 = pdbSignature.Data1;
    1.65 +  aSignature.m1 = pdbSignature.Data2;
    1.66 +  aSignature.m2 = pdbSignature.Data3;
    1.67 +  memcpy(aSignature.m3, pdbSignature.Data4, sizeof(pdbSignature.Data4));
    1.68 +
    1.69 +  // The PDB file name could be different from module filename, so report both
    1.70 +  // e.g. The PDB for C:\Windows\SysWOW64\ntdll.dll is wntdll.pdb
    1.71 +  char * leafName = strrchr(debugInfo->pdbFileName, '\\');
    1.72 +  if (leafName) {
    1.73 +    // Only report the file portion of the path
    1.74 +    *aPdbName = leafName + 1;
    1.75 +  } else {
    1.76 +    *aPdbName = debugInfo->pdbFileName;
    1.77 +  }
    1.78 +
    1.79 +  return true;
    1.80 +}
    1.81 +
    1.82 +static bool IsDashOrBraces(char c)
    1.83 +{
    1.84 +  return c == '-' || c == '{' || c == '}';
    1.85 +}
    1.86 +
    1.87 +SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
    1.88 +{
    1.89 +  SharedLibraryInfo sharedLibraryInfo;
    1.90 +
    1.91 +  nsAutoHandle snap(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()));
    1.92 +
    1.93 +  MODULEENTRY32 module = {0};
    1.94 +  module.dwSize = sizeof(MODULEENTRY32);
    1.95 +  if (Module32First(snap, &module)) {
    1.96 +    do {
    1.97 +      nsID pdbSig;
    1.98 +      uint32_t pdbAge;
    1.99 +      char *pdbName = NULL;
   1.100 +
   1.101 +      // Load the module again to make sure that its handle will remain remain
   1.102 +      // valid as we attempt to read the PDB information from it.  We load the
   1.103 +      // DLL as a datafile so that if the module actually gets unloaded between
   1.104 +      // the call to Module32Next and the following LoadLibraryEx, we don't end
   1.105 +      // up running the now newly loaded module's DllMain function.  If the
   1.106 +      // module is already loaded, LoadLibraryEx just increments its refcount.
   1.107 +      //
   1.108 +      // Note that because of the race condition above, merely loading the DLL
   1.109 +      // again is not safe enough, therefore we also need to make sure that we
   1.110 +      // can read the memory mapped at the base address before we can safely
   1.111 +      // proceed to actually access those pages.
   1.112 +      HMODULE handleLock = LoadLibraryEx(module.szExePath, NULL, LOAD_LIBRARY_AS_DATAFILE);
   1.113 +      MEMORY_BASIC_INFORMATION vmemInfo = {0};
   1.114 +      if (handleLock &&
   1.115 +          sizeof(vmemInfo) == VirtualQuery(module.modBaseAddr, &vmemInfo, sizeof(vmemInfo)) &&
   1.116 +          vmemInfo.State == MEM_COMMIT &&
   1.117 +          GetPdbInfo((uintptr_t)module.modBaseAddr, pdbSig, pdbAge, &pdbName)) {
   1.118 +        std::ostringstream stream;
   1.119 +        stream << pdbSig.ToString() << std::hex << pdbAge;
   1.120 +        std::string breakpadId = stream.str();
   1.121 +        std::string::iterator end =
   1.122 +          std::remove_if(breakpadId.begin(), breakpadId.end(), IsDashOrBraces);
   1.123 +        breakpadId.erase(end, breakpadId.end());
   1.124 +        std::transform(breakpadId.begin(), breakpadId.end(),
   1.125 +                       breakpadId.begin(), toupper);
   1.126 +
   1.127 +        SharedLibrary shlib((uintptr_t)module.modBaseAddr,
   1.128 +                            (uintptr_t)module.modBaseAddr+module.modBaseSize,
   1.129 +                            0, // DLLs are always mapped at offset 0 on Windows
   1.130 +                            breakpadId,
   1.131 +                            pdbName);
   1.132 +        sharedLibraryInfo.AddSharedLibrary(shlib);
   1.133 +      }
   1.134 +      FreeLibrary(handleLock); // ok to free null handles
   1.135 +    } while (Module32Next(snap, &module));
   1.136 +  }
   1.137 +
   1.138 +  return sharedLibraryInfo;
   1.139 +}
   1.140 +

mercurial