LCOV - code coverage report
Current view: top level - xpcom/build - LateWriteChecks.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 83 1.2 %
Date: 2017-07-14 16:53:18 Functions: 0 11 0.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 <algorithm>
       8             : 
       9             : #include "mozilla/IOInterposer.h"
      10             : #include "mozilla/PoisonIOInterposer.h"
      11             : #include "mozilla/ProcessedStack.h"
      12             : #include "mozilla/SHA1.h"
      13             : #include "mozilla/Scoped.h"
      14             : #include "mozilla/StaticPtr.h"
      15             : #include "mozilla/Telemetry.h"
      16             : #include "nsAppDirectoryServiceDefs.h"
      17             : #include "nsDirectoryServiceUtils.h"
      18             : #include "nsPrintfCString.h"
      19             : #include "mozilla/StackWalk.h"
      20             : #include "plstr.h"
      21             : #include "prio.h"
      22             : 
      23             : #ifdef XP_WIN
      24             : #define NS_T(str) L ## str
      25             : #define NS_SLASH "\\"
      26             : #include <fcntl.h>
      27             : #include <io.h>
      28             : #include <stdio.h>
      29             : #include <stdlib.h>
      30             : #include <sys/stat.h>
      31             : #include <windows.h>
      32             : #else
      33             : #define NS_SLASH "/"
      34             : #endif
      35             : 
      36             : #include "LateWriteChecks.h"
      37             : 
      38             : using namespace mozilla;
      39             : 
      40             : /*************************** Auxiliary Declarations ***************************/
      41             : 
      42             : // This a wrapper over a file descriptor that provides a Printf method and
      43             : // computes the sha1 of the data that passes through it.
      44             : class SHA1Stream
      45             : {
      46             : public:
      47           0 :   explicit SHA1Stream(FILE* aStream)
      48           0 :     : mFile(aStream)
      49             :   {
      50           0 :     MozillaRegisterDebugFILE(mFile);
      51           0 :   }
      52             : 
      53           0 :   void Printf(const char* aFormat, ...) MOZ_FORMAT_PRINTF(2, 3)
      54             :   {
      55           0 :     MOZ_ASSERT(mFile);
      56             :     va_list list;
      57           0 :     va_start(list, aFormat);
      58           0 :     nsAutoCString str;
      59           0 :     str.AppendPrintf(aFormat, list);
      60           0 :     va_end(list);
      61           0 :     mSHA1.update(str.get(), str.Length());
      62           0 :     fwrite(str.get(), 1, str.Length(), mFile);
      63           0 :   }
      64           0 :   void Finish(SHA1Sum::Hash& aHash)
      65             :   {
      66           0 :     int fd = fileno(mFile);
      67           0 :     fflush(mFile);
      68           0 :     MozillaUnRegisterDebugFD(fd);
      69           0 :     fclose(mFile);
      70           0 :     mSHA1.finish(aHash);
      71           0 :     mFile = nullptr;
      72           0 :   }
      73             : private:
      74             :   FILE* mFile;
      75             :   SHA1Sum mSHA1;
      76             : };
      77             : 
      78             : static void
      79           0 : RecordStackWalker(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure)
      80             : {
      81             :   std::vector<uintptr_t>* stack =
      82           0 :     static_cast<std::vector<uintptr_t>*>(aClosure);
      83           0 :   stack->push_back(reinterpret_cast<uintptr_t>(aPC));
      84           0 : }
      85             : 
      86             : /**************************** Late-Write Observer  ****************************/
      87             : 
      88             : /**
      89             :  * An implementation of IOInterposeObserver to be registered with IOInterposer.
      90             :  * This observer logs all writes as late writes.
      91             :  */
      92             : class LateWriteObserver final : public IOInterposeObserver
      93             : {
      94             : public:
      95           0 :   explicit LateWriteObserver(const char* aProfileDirectory)
      96           0 :     : mProfileDirectory(PL_strdup(aProfileDirectory))
      97             :   {
      98           0 :   }
      99           0 :   ~LateWriteObserver()
     100           0 :   {
     101           0 :     PL_strfree(mProfileDirectory);
     102           0 :     mProfileDirectory = nullptr;
     103           0 :   }
     104             : 
     105             :   void Observe(IOInterposeObserver::Observation& aObservation);
     106             : private:
     107             :   char* mProfileDirectory;
     108             : };
     109             : 
     110             : void
     111           0 : LateWriteObserver::Observe(IOInterposeObserver::Observation& aOb)
     112             : {
     113             :   // Crash if that is the shutdown check mode
     114           0 :   if (gShutdownChecks == SCM_CRASH) {
     115           0 :     MOZ_CRASH();
     116             :   }
     117             : 
     118             :   // If we have shutdown mode SCM_NOTHING or we can't record then abort
     119           0 :   if (gShutdownChecks == SCM_NOTHING || !Telemetry::CanRecordExtended()) {
     120           0 :     return;
     121             :   }
     122             : 
     123             :   // Write the stack and loaded libraries to a file. We can get here
     124             :   // concurrently from many writes, so we use multiple temporary files.
     125           0 :   std::vector<uintptr_t> rawStack;
     126             : 
     127             :   MozStackWalk(RecordStackWalker, /* skipFrames */ 0, /* maxFrames */ 0,
     128           0 :                reinterpret_cast<void*>(&rawStack), 0, nullptr);
     129           0 :   Telemetry::ProcessedStack stack = Telemetry::GetStackAndModules(rawStack);
     130             : 
     131             :   nsPrintfCString nameAux("%s%s%s", mProfileDirectory,
     132           0 :                           NS_SLASH, "Telemetry.LateWriteTmpXXXXXX");
     133             :   char* name;
     134           0 :   nameAux.GetMutableData(&name);
     135             : 
     136             :   // We want the sha1 of the entire file, so please don't write to fd
     137             :   // directly; use sha1Stream.
     138             :   FILE* stream;
     139             : #ifdef XP_WIN
     140             :   HANDLE hFile;
     141             :   do {
     142             :     // mkstemp isn't supported so keep trying until we get a file
     143             :     int result = _mktemp_s(name, strlen(name) + 1);
     144             :     hFile = CreateFileA(name, GENERIC_WRITE, 0, nullptr, CREATE_NEW,
     145             :                         FILE_ATTRIBUTE_NORMAL, nullptr);
     146             :   } while (GetLastError() == ERROR_FILE_EXISTS);
     147             : 
     148             :   if (hFile == INVALID_HANDLE_VALUE) {
     149             :     MOZ_CRASH("Um, how did we get here?");
     150             :   }
     151             : 
     152             :   // http://support.microsoft.com/kb/139640
     153             :   int fd = _open_osfhandle((intptr_t)hFile, _O_APPEND);
     154             :   if (fd == -1) {
     155             :     MOZ_CRASH("Um, how did we get here?");
     156             :   }
     157             : 
     158             :   stream = _fdopen(fd, "w");
     159             : #else
     160           0 :   int fd = mkstemp(name);
     161           0 :   if (fd == -1) {
     162           0 :     MOZ_CRASH("mkstemp failed");
     163             :   }
     164           0 :   stream = fdopen(fd, "w");
     165             : #endif
     166             : 
     167           0 :   SHA1Stream sha1Stream(stream);
     168             : 
     169           0 :   size_t numModules = stack.GetNumModules();
     170           0 :   sha1Stream.Printf("%u\n", (unsigned)numModules);
     171           0 :   for (size_t i = 0; i < numModules; ++i) {
     172           0 :     Telemetry::ProcessedStack::Module module = stack.GetModule(i);
     173           0 :     sha1Stream.Printf("%s %s\n", module.mBreakpadId.c_str(),
     174           0 :                       NS_ConvertUTF16toUTF8(module.mName).get());
     175             :   }
     176             : 
     177           0 :   size_t numFrames = stack.GetStackSize();
     178           0 :   sha1Stream.Printf("%u\n", (unsigned)numFrames);
     179           0 :   for (size_t i = 0; i < numFrames; ++i) {
     180           0 :     const Telemetry::ProcessedStack::Frame& frame = stack.GetFrame(i);
     181             :     // NOTE: We write the offsets, while the atos tool expects a value with
     182             :     // the virtual address added. For example, running otool -l on the the firefox
     183             :     // binary shows
     184             :     //      cmd LC_SEGMENT_64
     185             :     //      cmdsize 632
     186             :     //      segname __TEXT
     187             :     //      vmaddr 0x0000000100000000
     188             :     // so to print the line matching the offset 123 one has to run
     189             :     // atos -o firefox 0x100000123.
     190           0 :     sha1Stream.Printf("%d %x\n", frame.mModIndex, (unsigned)frame.mOffset);
     191             :   }
     192             : 
     193             :   SHA1Sum::Hash sha1;
     194           0 :   sha1Stream.Finish(sha1);
     195             : 
     196             :   // Note: These files should be deleted by telemetry once it reads them. If
     197             :   // there were no telemetry runs by the time we shut down, we just add files
     198             :   // to the existing ones instead of replacing them. Given that each of these
     199             :   // files is a bug to be fixed, that is probably the right thing to do.
     200             : 
     201             :   // We append the sha1 of the contents to the file name. This provides a simple
     202             :   // client side deduplication.
     203             :   nsPrintfCString finalName("%s%s", mProfileDirectory,
     204           0 :                             "/Telemetry.LateWriteFinal-");
     205           0 :   for (int i = 0; i < 20; ++i) {
     206           0 :     finalName.AppendPrintf("%02x", sha1[i]);
     207             :   }
     208           0 :   PR_Delete(finalName.get());
     209           0 :   PR_Rename(name, finalName.get());
     210             : }
     211             : 
     212             : /******************************* Setup/Teardown *******************************/
     213             : 
     214           3 : static StaticAutoPtr<LateWriteObserver> sLateWriteObserver;
     215             : 
     216             : namespace mozilla {
     217             : 
     218             : void
     219           0 : InitLateWriteChecks()
     220             : {
     221           0 :   nsCOMPtr<nsIFile> mozFile;
     222           0 :   NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mozFile));
     223           0 :   if (mozFile) {
     224           0 :     nsAutoCString nativePath;
     225           0 :     nsresult rv = mozFile->GetNativePath(nativePath);
     226           0 :     if (NS_SUCCEEDED(rv) && nativePath.get()) {
     227           0 :       sLateWriteObserver = new LateWriteObserver(nativePath.get());
     228             :     }
     229             :   }
     230           0 : }
     231             : 
     232             : void
     233           0 : BeginLateWriteChecks()
     234             : {
     235           0 :   if (sLateWriteObserver) {
     236             :     IOInterposer::Register(
     237             :       IOInterposeObserver::OpWriteFSync,
     238             :       sLateWriteObserver
     239           0 :     );
     240             :   }
     241           0 : }
     242             : 
     243             : void
     244           0 : StopLateWriteChecks()
     245             : {
     246           0 :   if (sLateWriteObserver) {
     247             :     IOInterposer::Unregister(
     248             :       IOInterposeObserver::OpAll,
     249             :       sLateWriteObserver
     250           0 :     );
     251             :     // Deallocation would not be thread-safe, and StopLateWriteChecks() is
     252             :     // called at shutdown and only in special cases.
     253             :     // sLateWriteObserver = nullptr;
     254             :   }
     255           0 : }
     256             : 
     257             : } // namespace mozilla

Generated by: LCOV version 1.13