tools/profiler/shared-libraries-win32.cc

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include <windows.h>
     7 #include <tlhelp32.h>
     8 #include <dbghelp.h>
     9 #include <sstream>
    11 #include "shared-libraries.h"
    12 #include "nsWindowsHelpers.h"
    14 #define CV_SIGNATURE 0x53445352 // 'SDSR'
    16 struct CodeViewRecord70
    17 {
    18   uint32_t signature;
    19   GUID pdbSignature;
    20   uint32_t pdbAge;
    21   char pdbFileName[1];
    22 };
    24 static bool GetPdbInfo(uintptr_t aStart, nsID& aSignature, uint32_t& aAge, char** aPdbName)
    25 {
    26   if (!aStart) {
    27     return false;
    28   }
    30   PIMAGE_DOS_HEADER dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(aStart);
    31   if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
    32     return false;
    33   }
    35   PIMAGE_NT_HEADERS ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(
    36       aStart + dosHeader->e_lfanew);
    37   if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) {
    38     return false;
    39   }
    41   uint32_t relativeVirtualAddress =
    42     ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
    43   if (!relativeVirtualAddress) {
    44     return false;
    45   }
    47   PIMAGE_DEBUG_DIRECTORY debugDirectory =
    48     reinterpret_cast<PIMAGE_DEBUG_DIRECTORY>(aStart + relativeVirtualAddress);
    49   if (!debugDirectory || debugDirectory->Type != IMAGE_DEBUG_TYPE_CODEVIEW) {
    50     return false;
    51   }
    53   CodeViewRecord70 *debugInfo = reinterpret_cast<CodeViewRecord70 *>(
    54       aStart + debugDirectory->AddressOfRawData);
    55   if (!debugInfo || debugInfo->signature != CV_SIGNATURE) {
    56     return false;
    57   }
    59   aAge = debugInfo->pdbAge;
    60   GUID& pdbSignature = debugInfo->pdbSignature;
    61   aSignature.m0 = pdbSignature.Data1;
    62   aSignature.m1 = pdbSignature.Data2;
    63   aSignature.m2 = pdbSignature.Data3;
    64   memcpy(aSignature.m3, pdbSignature.Data4, sizeof(pdbSignature.Data4));
    66   // The PDB file name could be different from module filename, so report both
    67   // e.g. The PDB for C:\Windows\SysWOW64\ntdll.dll is wntdll.pdb
    68   char * leafName = strrchr(debugInfo->pdbFileName, '\\');
    69   if (leafName) {
    70     // Only report the file portion of the path
    71     *aPdbName = leafName + 1;
    72   } else {
    73     *aPdbName = debugInfo->pdbFileName;
    74   }
    76   return true;
    77 }
    79 static bool IsDashOrBraces(char c)
    80 {
    81   return c == '-' || c == '{' || c == '}';
    82 }
    84 SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
    85 {
    86   SharedLibraryInfo sharedLibraryInfo;
    88   nsAutoHandle snap(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()));
    90   MODULEENTRY32 module = {0};
    91   module.dwSize = sizeof(MODULEENTRY32);
    92   if (Module32First(snap, &module)) {
    93     do {
    94       nsID pdbSig;
    95       uint32_t pdbAge;
    96       char *pdbName = NULL;
    98       // Load the module again to make sure that its handle will remain remain
    99       // valid as we attempt to read the PDB information from it.  We load the
   100       // DLL as a datafile so that if the module actually gets unloaded between
   101       // the call to Module32Next and the following LoadLibraryEx, we don't end
   102       // up running the now newly loaded module's DllMain function.  If the
   103       // module is already loaded, LoadLibraryEx just increments its refcount.
   104       //
   105       // Note that because of the race condition above, merely loading the DLL
   106       // again is not safe enough, therefore we also need to make sure that we
   107       // can read the memory mapped at the base address before we can safely
   108       // proceed to actually access those pages.
   109       HMODULE handleLock = LoadLibraryEx(module.szExePath, NULL, LOAD_LIBRARY_AS_DATAFILE);
   110       MEMORY_BASIC_INFORMATION vmemInfo = {0};
   111       if (handleLock &&
   112           sizeof(vmemInfo) == VirtualQuery(module.modBaseAddr, &vmemInfo, sizeof(vmemInfo)) &&
   113           vmemInfo.State == MEM_COMMIT &&
   114           GetPdbInfo((uintptr_t)module.modBaseAddr, pdbSig, pdbAge, &pdbName)) {
   115         std::ostringstream stream;
   116         stream << pdbSig.ToString() << std::hex << pdbAge;
   117         std::string breakpadId = stream.str();
   118         std::string::iterator end =
   119           std::remove_if(breakpadId.begin(), breakpadId.end(), IsDashOrBraces);
   120         breakpadId.erase(end, breakpadId.end());
   121         std::transform(breakpadId.begin(), breakpadId.end(),
   122                        breakpadId.begin(), toupper);
   124         SharedLibrary shlib((uintptr_t)module.modBaseAddr,
   125                             (uintptr_t)module.modBaseAddr+module.modBaseSize,
   126                             0, // DLLs are always mapped at offset 0 on Windows
   127                             breakpadId,
   128                             pdbName);
   129         sharedLibraryInfo.AddSharedLibrary(shlib);
   130       }
   131       FreeLibrary(handleLock); // ok to free null handles
   132     } while (Module32Next(snap, &module));
   133   }
   135   return sharedLibraryInfo;
   136 }

mercurial