xpcom/build/LateWriteChecks.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial