Backed out 2 changesets (bug 1330833) for windows 64 xpcshell failures a=backout

Backed out changeset 466565fa382a (bug 1330833)
Backed out changeset 927194e7769d (bug 1330833)

MozReview-Commit-ID: GB4KsH29xYC
This commit is contained in:
Wes Kocher
2017-02-16 17:20:54 -08:00
parent 3b126e5559
commit 3f83b41f7e
20 changed files with 91 additions and 743 deletions

View File

@@ -12,7 +12,6 @@
#include <prproces.h>
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
@@ -25,7 +24,6 @@
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsThreadManager.h"
#include "nsXPCOMCIDInternal.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsXPCOMPrivate.h"
@@ -78,8 +76,6 @@
#include "mozilla/PoisonIOInterposer.h"
#include "mozilla/StartupTimeline.h"
#include "mozilla/HangMonitor.h"
#include "nsNativeCharsetUtils.h"
#include "nsProxyRelease.h"
#if defined(MOZ_GECKO_PROFILER)
#include "shared-libraries.h"
@@ -100,8 +96,6 @@ namespace {
using namespace mozilla;
using namespace mozilla::HangMonitor;
using Telemetry::Common::AutoHashtable;
using mozilla::dom::Promise;
using mozilla::dom::AutoJSAPI;
// The maximum number of chrome hangs stacks that we're keeping.
const size_t kMaxChromeStacksKept = 50;
@@ -1660,197 +1654,8 @@ CreateJSStackObject(JSContext *cx, const CombinedStacks &stacks) {
return ret;
}
#if defined(MOZ_GECKO_PROFILER)
class GetLoadedModulesResultRunnable final : public Runnable
{
nsMainThreadPtrHandle<Promise> mPromise;
SharedLibraryInfo mRawModules;
nsCOMPtr<nsIThread> mWorkerThread;
public:
GetLoadedModulesResultRunnable(const nsMainThreadPtrHandle<Promise>& aPromise, const SharedLibraryInfo& rawModules)
: mPromise(aPromise)
, mRawModules(rawModules)
, mWorkerThread(do_GetCurrentThread())
{
MOZ_ASSERT(!NS_IsMainThread());
}
NS_IMETHOD
Run() override
{
MOZ_ASSERT(NS_IsMainThread());
mWorkerThread->Shutdown();
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mPromise->GlobalJSObject()))) {
mPromise->MaybeReject(NS_ERROR_FAILURE);
return NS_OK;
}
JSContext* cx = jsapi.cx();
JS::RootedObject moduleArray(cx, JS_NewArrayObject(cx, 0));
if (!moduleArray) {
mPromise->MaybeReject(NS_ERROR_FAILURE);
return NS_OK;
}
for (unsigned int i = 0, n = mRawModules.GetSize(); i != n; i++) {
const SharedLibrary &info = mRawModules.GetEntry(i);
nsString basename = info.GetName();
#if defined(XP_MACOSX) || defined(XP_LINUX)
int32_t pos = basename.RFindChar('/');
if (pos != kNotFound) {
basename.Cut(0, pos + 1);
}
#endif
nsString debug_basename = info.GetDebugName();
#if defined(XP_MACOSX) || defined(XP_LINUX)
pos = debug_basename.RFindChar('/');
if (pos != kNotFound) {
debug_basename.Cut(0, pos + 1);
}
#endif
JS::RootedObject moduleObj(cx, JS_NewPlainObject(cx));
if (!moduleObj) {
mPromise->MaybeReject(NS_ERROR_FAILURE);
return NS_OK;
}
// Module name.
JS::RootedString moduleName(cx, JS_NewUCStringCopyZ(cx, basename.get()));
if (!moduleName || !JS_DefineProperty(cx, moduleObj, "name", moduleName, JSPROP_ENUMERATE)) {
mPromise->MaybeReject(NS_ERROR_FAILURE);
return NS_OK;
}
// Module debug name.
JS::RootedValue moduleDebugName(cx);
if (!debug_basename.IsEmpty()) {
JS::RootedString str_moduleDebugName(cx, JS_NewUCStringCopyZ(cx, debug_basename.get()));
if (!str_moduleDebugName) {
mPromise->MaybeReject(NS_ERROR_FAILURE);
return NS_OK;
}
moduleDebugName.setString(str_moduleDebugName);
}
else {
moduleDebugName.setNull();
}
if (!JS_DefineProperty(cx, moduleObj, "debugName", moduleDebugName, JSPROP_ENUMERATE)) {
mPromise->MaybeReject(NS_ERROR_FAILURE);
return NS_OK;
}
// Module Breakpad identifier.
JS::RootedValue id(cx);
if (!info.GetBreakpadId().empty()) {
JS::RootedString str_id(cx, JS_NewStringCopyZ(cx, info.GetBreakpadId().c_str()));
if (!str_id) {
mPromise->MaybeReject(NS_ERROR_FAILURE);
return NS_OK;
}
id.setString(str_id);
} else {
id.setNull();
}
if (!JS_DefineProperty(cx, moduleObj, "debugID", id, JSPROP_ENUMERATE)) {
mPromise->MaybeReject(NS_ERROR_FAILURE);
return NS_OK;
}
// Module version.
JS::RootedValue version(cx);
if (!info.GetVersion().empty()) {
JS::RootedString v(cx, JS_NewStringCopyZ(cx, info.GetVersion().c_str()));
if (!v) {
mPromise->MaybeReject(NS_ERROR_FAILURE);
return NS_OK;
}
version.setString(v);
} else {
version.setNull();
}
if (!JS_DefineProperty(cx, moduleObj, "version", version, JSPROP_ENUMERATE)) {
mPromise->MaybeReject(NS_ERROR_FAILURE);
return NS_OK;
}
if (!JS_DefineElement(cx, moduleArray, i, moduleObj, JSPROP_ENUMERATE)) {
mPromise->MaybeReject(NS_ERROR_FAILURE);
return NS_OK;
}
}
mPromise->MaybeResolve(moduleArray);
return NS_OK;
}
};
class GetLoadedModulesRunnable final : public Runnable
{
nsMainThreadPtrHandle<Promise> mPromise;
public:
explicit GetLoadedModulesRunnable(const nsMainThreadPtrHandle<Promise>& aPromise)
: mPromise(aPromise)
{ }
NS_IMETHOD
Run() override
{
nsCOMPtr<nsIRunnable> resultRunnable = new GetLoadedModulesResultRunnable(mPromise, SharedLibraryInfo::GetInfoForSelf());
return NS_DispatchToMainThread(resultRunnable);
}
};
#endif // MOZ_GECKO_PROFILER
NS_IMETHODIMP
TelemetryImpl::GetLoadedModules(JSContext *cx, nsISupports** aPromise)
{
nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(cx));
if (NS_WARN_IF(!global)) {
return NS_ERROR_FAILURE;
}
ErrorResult result;
RefPtr<Promise> promise = Promise::Create(global, result);
if (NS_WARN_IF(result.Failed())) {
return result.StealNSResult();
}
#if defined(MOZ_GECKO_PROFILER)
nsCOMPtr<nsIThreadManager> tm = do_GetService(NS_THREADMANAGER_CONTRACTID);
nsCOMPtr<nsIThread> getModulesThread;
nsresult rv = tm->NewThread(0, 0, getter_AddRefs(getModulesThread));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsMainThreadPtrHandle<Promise> mainThreadPromise(new nsMainThreadPtrHolder<Promise>(promise));
nsCOMPtr<nsIRunnable> runnable = new GetLoadedModulesRunnable(mainThreadPromise);
promise.forget(aPromise);
return getModulesThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
#else // MOZ_GECKO_PROFILER
return NS_ERROR_NOT_IMPLEMENTED;
#endif // MOZ_GECKO_PROFILER
}
static bool
IsValidBreakpadId(const std::string &breakpadId)
{
IsValidBreakpadId(const std::string &breakpadId) {
if (breakpadId.size() < 33) {
return false;
}
@@ -3224,14 +3029,15 @@ GetStackAndModules(const std::vector<uintptr_t>& aPCs)
#ifdef MOZ_GECKO_PROFILER
for (unsigned i = 0, n = rawModules.GetSize(); i != n; ++i) {
const SharedLibrary &info = rawModules.GetEntry(i);
std::string basename = info.GetNativeDebugName();
const std::string &name = info.GetName();
std::string basename = name;
#if defined(XP_MACOSX) || defined(XP_LINUX)
// We want to use just the basename as the libname, but the
// current profiler addon needs the full path name, so we compute the
// basename in here.
size_t pos = basename.rfind('/');
size_t pos = name.rfind('/');
if (pos != std::string::npos) {
basename = basename.substr(pos + 1);
basename = name.substr(pos + 1);
}
#endif
mozilla::Telemetry::ProcessedStack::Module module = {

View File

@@ -84,8 +84,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "TelemetrySend",
"resource://gre/modules/TelemetrySend.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryReportingPolicy",
"resource://gre/modules/TelemetryReportingPolicy.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryModules",
"resource://gre/modules/TelemetryModules.jsm");
/**
* Setup Telemetry logging. This function also gets called when loggin related
@@ -752,9 +750,6 @@ var Impl = {
// in the future.
TelemetryStorage.removeFHRDatabase();
// Report the modules loaded in the Firefox process.
TelemetryModules.start();
this._delayedInitTaskDeferred.resolve();
} catch (e) {
this._delayedInitTaskDeferred.reject(e);

View File

@@ -1,99 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
"resource://gre/modules/Preferences.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Log",
"resource://gre/modules/Log.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryController",
"resource://gre/modules/TelemetryController.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gUpdateTimerManager",
"@mozilla.org/updates/timer-manager;1", "nsIUpdateTimerManager");
XPCOMUtils.defineLazyServiceGetter(this, "Telemetry",
"@mozilla.org/base/telemetry;1", "nsITelemetry");
this.EXPORTED_SYMBOLS = [
"TelemetryModules",
];
const LOGGER_NAME = "Toolkit.Telemetry";
const LOGGER_PREFIX = "TelemetryModules::";
// The default is 1 week.
const MODULES_PING_INTERVAL_SECONDS = 7 * 24 * 60 * 60;
const MODULES_PING_INTERVAL_PREFERENCE = "toolkit.telemetry.modulesPing.interval";
const MAX_MODULES_NUM = 512;
const MAX_NAME_LENGTH = 64;
const TRUNCATION_DELIMITER = "\u2026";
this.TelemetryModules = Object.freeze({
_log: Log.repository.getLoggerWithMessagePrefix(LOGGER_NAME, LOGGER_PREFIX),
start() {
// The list of loaded modules is obtainable only when the profiler is enabled.
// If it isn't, we don't want to send the ping at all.
if (!AppConstants.MOZ_GECKO_PROFILER) {
return;
}
// Use nsIUpdateTimerManager for a long-duration timer that survives across sessions.
gUpdateTimerManager.registerTimer(
"telemetry_modules_ping",
this,
Preferences.get(MODULES_PING_INTERVAL_PREFERENCE, MODULES_PING_INTERVAL_SECONDS)
);
},
/**
* Called when the 'telemetry_modules_ping' timer fires.
*/
notify() {
try {
Telemetry.getLoadedModules().then(
modules => {
modules = modules.filter(module => module.name.length > 0);
// Cut the list of modules to MAX_MODULES_NUM entries.
if (modules.length > MAX_MODULES_NUM) {
modules = modules.slice(0, MAX_MODULES_NUM);
}
// Cut the file names of the modules to MAX_NAME_LENGTH characters.
for (let module of modules) {
if (module.name.length > MAX_NAME_LENGTH) {
module.name = module.name.substr(0, MAX_NAME_LENGTH - 1) + TRUNCATION_DELIMITER;
}
if (module.debugName !== null && module.debugName.length > MAX_NAME_LENGTH) {
module.debugName = module.debugName.substr(0, MAX_NAME_LENGTH - 1) + TRUNCATION_DELIMITER;
}
}
TelemetryController.submitExternalPing("modules",
{
version: 1,
modules,
},
{
addClientId: true,
addEnvironment: true,
}
);
},
err => this._log.error("notify - promise failed", ex)
);
} catch (ex) {
this._log.error("notify - caught exception", ex);
}
},
});

View File

@@ -1,45 +0,0 @@
"modules" ping
============
This ping is sent once a week and includes the modules loaded in the Firefox process.
The client ID and environment is submitted with this ping.
Structure:
.. code-block:: js
{
type: "modules",
... common ping data
clientId: <UUID>,
environment: { ... },
payload: {
version: 1,
modules: [
{
name: <string>, // Name of the module file (e.g. xul.dll)
version: <string>, // Version of the module
debugID: <string>, // ID of the debug information file
debugName: <string>, // Name of the debug information file
},
...
],
}
}
Notes
~~~~~
The version information is only available on Windows, it is null on other platforms.
The debug name is the name of the PDB on Windows (which isn't always the same as the module name modulo the extension, e.g. the PDB for C:\Windows\SysWOW64\ntdll.dll is wntdll.pdb) and is the same as the module name on other platforms.
The debug ID is platform-dependent. It is compatible with the Breakpad ID used on Socorro.
Sometimes the debug name and debug ID are missing for Windows modules (often with malware). In this case, they will be "null".
The length of the modules array is limited to 512 entries.
The name and debug name are length limited, with a maximum of 64 characters.

View File

@@ -118,10 +118,6 @@ The following prefs are for testing purpose only.
Timeout until we decide whether a user is idle or not (seconds).
``toolkit.telemetry.modulesPing.interval``
Interval between "modules" ping transmissions.
``toolkit.telemetry.send.overrideOfficialCheck``
If true, allows sending pings on unofficial builds. Requires a restart.

View File

@@ -30,8 +30,6 @@ if CONFIG['GNU_CXX']:
if CONFIG['ENABLE_TESTS']:
DIRS += ['tests/gtest']
TEST_DIRS += ['tests']
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
@@ -74,7 +72,6 @@ EXTRA_JS_MODULES += [
'TelemetryController.jsm',
'TelemetryEnvironment.jsm',
'TelemetryLog.jsm',
'TelemetryModules.jsm',
'TelemetryReportingPolicy.jsm',
'TelemetrySend.jsm',
'TelemetrySession.jsm',

View File

@@ -180,25 +180,6 @@ interface nsITelemetry : nsISupports
[implicit_jscontext]
jsval snapshotCapturedStacks([optional] in boolean clear);
/*
* Returns an array of the modules loaded in the process. The data has the following structure:
*
* [
* {
* "name": <string>, // Name of the module file (e.g. xul.dll)
* "version": <string>, // Version of the module
* "debugName": <string>, // ID of the debug information file
* "debugID": <string>, // Name of the debug information file
* },
* ...
* ]
*
* @return An array of modules.
* @throws NS_ERROR_FAILURE on failure.
*/
[implicit_jscontext]
nsISupports getLoadedModules();
/*
* An array of thread hang stats,
* [<thread>, <thread>, ...]

View File

@@ -1,8 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
void nothing()
{
return;
}

View File

@@ -1,17 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIST_INSTALL = False
SOURCES += [
'modules-test.cpp',
]
SharedLibrary('modules-test')
if CONFIG['COMPILE_ENVIRONMENT']:
shared_library = '!%smodules-test%s' % (CONFIG['DLL_PREFIX'], CONFIG['DLL_SUFFIX'])
TEST_HARNESS_FILES.xpcshell.toolkit.components.telemetry.tests.unit += [shared_library]

View File

@@ -1,176 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Cu.import("resource://gre/modules/TelemetryModules.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
const MAX_NAME_LENGTH = 64;
const libModules = ctypes.libraryName("modules-test");
const libUnicode = ctypes.libraryName("modμles-test");
const libLongName = "lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_Fusce_sit_amet_tellus_non_magna_euismod_vestibulum_Vivamus_turpis_duis.dll"
const libUnicodePDB = "testUnicodePDB.dll";
const libNoPDB = "testNoPDB.dll";
const libxul = OS.Path.basename(OS.Constants.Path.libxul);
const libModulesFile = do_get_file(libModules).path;
const libUnicodeFile = OS.Path.join(OS.Path.dirname(libModulesFile), libUnicode);
const libLongNameFile = OS.Path.join(OS.Path.dirname(libModulesFile), libLongName);
const libUnicodePDBFile = do_get_file(libUnicodePDB).path;
const libNoPDBFile = do_get_file(libNoPDB).path;
let libModulesHandle, libUnicodeHandle, libLongNameHandle, libUnicodePDBHandle, libNoPDBHandle;
let expectedLibs;
if (AppConstants.platform === "win") {
const version = AppConstants.MOZ_APP_VERSION.substring(0, AppConstants.MOZ_APP_VERSION.indexOf(".") + 2);
expectedLibs = [
{
name: libxul,
debugName: libxul.replace(".dll", ".pdb"),
version,
},
{
name: libModules,
debugName: libModules.replace(".dll", ".pdb"),
version,
},
{
name: libUnicode,
debugName: libModules.replace(".dll", ".pdb"),
version,
},
{
name: libLongName.substring(0, MAX_NAME_LENGTH - 1) + "…",
debugName: libModules.replace(".dll", ".pdb"),
version,
},
{
name: libUnicodePDB,
debugName: "libmodμles.pdb",
version: null,
},
{
name: libNoPDB,
debugName: null,
version: null,
},
];
} else if (AppConstants.platform === "android") {
// Listing shared libraries doesn't work in Android xpcshell tests.
// https://hg.mozilla.org/mozilla-central/file/0eef1d5a39366059677c6d7944cfe8a97265a011/tools/profiler/core/shared-libraries-linux.cc#l95
expectedLibs = [];
} else {
expectedLibs = [
{
name: libxul,
debugName: libxul,
version: null,
},
{
name: libModules,
debugName: libModules,
version: null,
},
{
name: libUnicode,
debugName: libUnicode,
version: null,
},
{
name: libLongName.substring(0, MAX_NAME_LENGTH - 1) + "…",
debugName: libLongName.substring(0, MAX_NAME_LENGTH - 1) + "…",
version: null,
},
];
}
add_task(function* setup() {
do_get_profile();
yield OS.File.copy(libModulesFile, libUnicodeFile);
yield OS.File.copy(libModulesFile, libLongName);
if (AppConstants.platform !== "android") {
libModulesHandle = ctypes.open(libModulesFile);
libUnicodeHandle = ctypes.open(libUnicodeFile);
libLongNameHandle = ctypes.open(libLongNameFile);
if (AppConstants.platform === "win") {
libUnicodePDBHandle = ctypes.open(libUnicodePDBFile);
libNoPDBHandle = ctypes.open(libNoPDBFile);
}
}
// Force the timer to fire (using a small interval).
Cc["@mozilla.org/updates/timer-manager;1"].getService(Ci.nsIObserver).observe(null, "utm-test-init", "");
Preferences.set("toolkit.telemetry.modulesPing.interval", 0);
Preferences.set("app.update.url", "http:/localhost");
// Start the local ping server and setup Telemetry to use it during the tests.
PingServer.start();
Preferences.set("toolkit.telemetry.server", "http://localhost:" + PingServer.port);
});
do_register_cleanup(function() {
if (libModulesHandle) {
libModulesHandle.close();
}
if (libUnicodeHandle) {
libUnicodeHandle.close();
}
if (libLongNameHandle) {
libLongNameHandle.close();
}
if (libUnicodePDBHandle) {
libUnicodePDBHandle.close();
}
if (libNoPDBHandle) {
libNoPDBHandle.close();
}
return OS.File.remove(libUnicodeFile)
.then(() => OS.File.remove(libLongNameFile))
.then(() => PingServer.stop());
});
add_task({
skip_if: () => !AppConstants.MOZ_GECKO_PROFILER,
}, function* test_send_ping() {
yield TelemetryController.testSetup();
let found = yield PingServer.promiseNextPing();
Assert.ok(!!found, "Telemetry ping submitted.");
Assert.strictEqual(found.type, "modules", "Ping type is 'modules'");
Assert.ok(found.environment, "'modules' ping has an environment.");
Assert.ok(!!found.clientId, "'modules' ping has a client ID.");
Assert.ok(!!found.payload.modules, "Telemetry ping payload contains the 'modules' array.");
for (let lib of expectedLibs) {
let test_lib = found.payload.modules.find(module => module.name === lib.name);
Assert.ok(!!test_lib, "There is a '" + lib.name + "' module.");
if (lib.version !== null) {
Assert.ok(test_lib.version.startsWith(lib.version), "The version of the " + lib.name + " module (" + test_lib.version + ") is correct (it starts with '" + lib.version + "').");
} else {
Assert.strictEqual(test_lib.version, null, "The version of the " + lib.name + " module is null.");
}
Assert.strictEqual(test_lib.debugName, lib.debugName, "The " + lib.name + " module has the correct debug name.");
if (lib.debugName === null) {
Assert.strictEqual(test_lib.debugID, null, "The " + lib.name + " module doesn't have a debug ID.");
} else {
Assert.greater(test_lib.debugID.length, 0, "The " + lib.name + " module has a debug ID.");
}
}
let test_lib = found.payload.modules.find(module => module.name === libLongName);
Assert.ok(!test_lib, "There isn't a '" + libLongName + "' module.");
});

View File

@@ -14,8 +14,6 @@ support-files =
system.xpi
restartless.xpi
theme.xpi
testUnicodePDB.dll
testNoPDB.dll
!/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
generated-files =
dictionary.xpi
@@ -65,6 +63,5 @@ tags = addons
skip-if = toolkit == 'android'
[test_TelemetryCaptureStack.js]
[test_TelemetryEvents.js]
[test_TelemetryModules.js]
[test_PingSender.js]
skip-if = (os == "android") || (os == "linux" && bits == 32)

View File

@@ -638,7 +638,7 @@ void EHAddrSpace::Update() {
// itself.
continue;
EHTable tab(reinterpret_cast<const void *>(lib.GetStart()),
lib.GetEnd() - lib.GetStart(), lib.GetNativeDebugName());
lib.GetEnd() - lib.GetStart(), lib.GetName());
if (tab.isValid())
tables.push_back(tab);
}

View File

@@ -888,9 +888,34 @@ AddSharedLibraryInfoToStream(std::ostream& aStream, const SharedLibrary& aLib)
aStream << "\"start\":" << aLib.GetStart();
aStream << ",\"end\":" << aLib.GetEnd();
aStream << ",\"offset\":" << aLib.GetOffset();
aStream << ",\"name\":\"" << aLib.GetNativeDebugName() << "\"";
aStream << ",\"name\":\"" << aLib.GetName() << "\"";
const std::string& breakpadId = aLib.GetBreakpadId();
aStream << ",\"breakpadId\":\"" << breakpadId << "\"";
#ifdef XP_WIN
// FIXME: remove this XP_WIN code when the profiler plugin has switched to
// using breakpadId.
std::string pdbSignature = breakpadId.substr(0, 32);
std::string pdbAgeStr = breakpadId.substr(32, breakpadId.size() - 1);
std::stringstream stream;
stream << pdbAgeStr;
unsigned pdbAge;
stream << std::hex;
stream >> pdbAge;
#ifdef DEBUG
std::ostringstream oStream;
oStream << pdbSignature << std::hex << std::uppercase << pdbAge;
MOZ_ASSERT(breakpadId == oStream.str());
#endif
aStream << ",\"pdbSignature\":\"" << pdbSignature << "\"";
aStream << ",\"pdbAge\":" << pdbAge;
aStream << ",\"pdbName\":\"" << aLib.GetName() << "\"";
#endif
aStream << "}";
}

View File

@@ -14,8 +14,6 @@
#include <fstream>
#include "platform.h"
#include "shared-libraries.h"
#include "mozilla/Unused.h"
#include "nsNativeCharsetUtils.h"
#include "common/linux/file_id.h"
#include <algorithm>
@@ -82,11 +80,7 @@ dl_iterate_callback(struct dl_phdr_info *dl_info, size_t size, void *data)
libEnd = end;
}
const char *name = dl_info->dlpi_name;
nsAutoString nameStr;
mozilla::Unused << NS_WARN_IF(NS_FAILED(NS_CopyNativeToUnicode(nsDependentCString(name), nameStr)));
SharedLibrary shlib(libStart, libEnd, 0, getId(name), nameStr, nameStr, "");
SharedLibrary shlib(libStart, libEnd, 0, getId(name), name);
info.AddSharedLibrary(shlib);
return 0;
@@ -152,11 +146,7 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
continue;
}
#endif
nsAutoString nameStr;
mozilla::Unused << NS_WARN_IF(NS_FAILED(NS_CopyNativeToUnicode(nsDependentCString(name), nameStr)));
SharedLibrary shlib(start, end, offset, getId(name), nameStr, nameStr, "");
SharedLibrary shlib(start, end, offset, getId(name), name);
info.AddSharedLibrary(shlib);
if (count > 10000) {
LOG("Get maps failed");

View File

@@ -14,8 +14,6 @@
#include <stdlib.h>
#include <vector>
#include <sstream>
#include "mozilla/Unused.h"
#include "nsNativeCharsetUtils.h"
#include "shared-libraries.h"
@@ -72,11 +70,8 @@ void addSharedLibrary(const platform_mach_header* header, char *name, SharedLibr
uuid << '0';
}
nsAutoString nameStr;
mozilla::Unused << NS_WARN_IF(NS_FAILED(NS_CopyNativeToUnicode(nsDependentCString(name), nameStr)));
info.AddSharedLibrary(SharedLibrary(start, start + size, 0, uuid.str(),
nameStr, nameStr, ""));
name));
}
// Use dyld to inspect the macho image information. We can build the SharedLibraryEntry structure

View File

@@ -4,15 +4,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <windows.h>
#include <tlhelp32.h>
#include <dbghelp.h>
#include <sstream>
#include <psapi.h>
#include "shared-libraries.h"
#include "nsWindowsHelpers.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "nsNativeCharsetUtils.h"
#define CV_SIGNATURE 0x53445352 // 'SDSR'
@@ -21,7 +18,6 @@ struct CodeViewRecord70
uint32_t signature;
GUID pdbSignature;
uint32_t pdbAge;
// A UTF-8 string, according to https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/PDB/dbi/locator.cpp#L785
char pdbFileName[1];
};
@@ -69,7 +65,13 @@ static bool GetPdbInfo(uintptr_t aStart, nsID& aSignature, uint32_t& aAge, char*
// The PDB file name could be different from module filename, so report both
// e.g. The PDB for C:\Windows\SysWOW64\ntdll.dll is wntdll.pdb
*aPdbName = debugInfo->pdbFileName;
char * leafName = strrchr(debugInfo->pdbFileName, '\\');
if (leafName) {
// Only report the file portion of the path
*aPdbName = leafName + 1;
} else {
*aPdbName = debugInfo->pdbFileName;
}
return true;
}
@@ -79,121 +81,55 @@ static bool IsDashOrBraces(char c)
return c == '-' || c == '{' || c == '}';
}
std::string GetVersion(WCHAR* dllPath)
{
DWORD infoSize = GetFileVersionInfoSizeW(dllPath, nullptr);
if (infoSize == 0) {
return "";
}
mozilla::UniquePtr<unsigned char[]> infoData = mozilla::MakeUnique<unsigned char[]>(infoSize);
if (!GetFileVersionInfoW(dllPath, 0, infoSize, infoData.get())) {
return "";
}
VS_FIXEDFILEINFO* vInfo;
UINT vInfoLen;
if (!VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen)) {
return "";
}
if (!vInfo) {
return "";
}
std::ostringstream stream;
stream << (vInfo->dwFileVersionMS >> 16) << "."
<< (vInfo->dwFileVersionMS & 0xFFFF) << "."
<< (vInfo->dwFileVersionLS >> 16) << "."
<< (vInfo->dwFileVersionLS & 0xFFFF);
return stream.str();
}
SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
{
SharedLibraryInfo sharedLibraryInfo;
HANDLE hProcess = GetCurrentProcess();
mozilla::UniquePtr<HMODULE[]> hMods;
size_t modulesNum = 0;
if (hProcess != NULL) {
DWORD modulesSize;
if (!EnumProcessModules(hProcess, nullptr, 0, &modulesSize)) {
return sharedLibraryInfo;
}
modulesNum = modulesSize / sizeof(HMODULE);
hMods = mozilla::MakeUnique<HMODULE[]>(modulesNum);
if (!EnumProcessModules(hProcess, hMods.get(), modulesNum * sizeof(HMODULE), &modulesSize)) {
return sharedLibraryInfo;
}
}
nsAutoHandle snap(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()));
for (unsigned int i = 0; i <= modulesNum; i++) {
nsID pdbSig;
uint32_t pdbAge;
nsAutoString pdbNameStr;
char *pdbName = NULL;
std::string breakpadId;
WCHAR modulePath[MAX_PATH + 1];
MODULEENTRY32 module = {0};
module.dwSize = sizeof(MODULEENTRY32);
if (Module32First(snap, &module)) {
do {
nsID pdbSig;
uint32_t pdbAge;
char *pdbName = NULL;
if (!GetModuleFileNameEx(hProcess, hMods[i], modulePath, sizeof(modulePath) / sizeof(WCHAR))) {
continue;
}
// Load the module again to make sure that its handle will remain remain
// valid as we attempt to read the PDB information from it. We load the
// DLL as a datafile so that if the module actually gets unloaded between
// the call to Module32Next and the following LoadLibraryEx, we don't end
// up running the now newly loaded module's DllMain function. If the
// module is already loaded, LoadLibraryEx just increments its refcount.
//
// Note that because of the race condition above, merely loading the DLL
// again is not safe enough, therefore we also need to make sure that we
// can read the memory mapped at the base address before we can safely
// proceed to actually access those pages.
HMODULE handleLock = LoadLibraryEx(module.szExePath, NULL, LOAD_LIBRARY_AS_DATAFILE);
MEMORY_BASIC_INFORMATION vmemInfo = {0};
if (handleLock &&
sizeof(vmemInfo) == VirtualQuery(module.modBaseAddr, &vmemInfo, sizeof(vmemInfo)) &&
vmemInfo.State == MEM_COMMIT &&
GetPdbInfo((uintptr_t)module.modBaseAddr, pdbSig, pdbAge, &pdbName)) {
std::ostringstream stream;
stream << pdbSig.ToString() << std::hex << pdbAge;
std::string breakpadId = stream.str();
std::string::iterator end =
std::remove_if(breakpadId.begin(), breakpadId.end(), IsDashOrBraces);
breakpadId.erase(end, breakpadId.end());
std::transform(breakpadId.begin(), breakpadId.end(),
breakpadId.begin(), toupper);
MODULEINFO module = {0};
if (!GetModuleInformation(hProcess, hMods[i], &module, sizeof(MODULEINFO))) {
continue;
}
// Load the module again to make sure that its handle will remain remain
// valid as we attempt to read the PDB information from it. We load the
// DLL as a datafile so that if the module actually gets unloaded between
// the call to EnumProcessModules and the following LoadLibraryEx, we don't
// end up running the now newly loaded module's DllMain function. If the
// module is already loaded, LoadLibraryEx just increments its refcount.
//
// Note that because of the race condition above, merely loading the DLL
// again is not safe enough, therefore we also need to make sure that we
// can read the memory mapped at the base address before we can safely
// proceed to actually access those pages.
HMODULE handleLock = LoadLibraryEx(modulePath, NULL, LOAD_LIBRARY_AS_DATAFILE);
MEMORY_BASIC_INFORMATION vmemInfo = { 0 };
if (handleLock &&
sizeof(vmemInfo) == VirtualQuery(module.lpBaseOfDll, &vmemInfo, sizeof(vmemInfo)) &&
vmemInfo.State == MEM_COMMIT &&
GetPdbInfo((uintptr_t)module.lpBaseOfDll, pdbSig, pdbAge, &pdbName)) {
std::ostringstream stream;
stream << pdbSig.ToString() << std::hex << pdbAge;
breakpadId = stream.str();
std::string::iterator end =
std::remove_if(breakpadId.begin(), breakpadId.end(), IsDashOrBraces);
breakpadId.erase(end, breakpadId.end());
std::transform(breakpadId.begin(), breakpadId.end(),
breakpadId.begin(), toupper);
pdbNameStr = NS_ConvertUTF8toUTF16(pdbName);
int32_t pos = pdbNameStr.RFindChar('\\');
if (pos != kNotFound) {
pdbNameStr.Cut(0, pos + 1);
SharedLibrary shlib((uintptr_t)module.modBaseAddr,
(uintptr_t)module.modBaseAddr+module.modBaseSize,
0, // DLLs are always mapped at offset 0 on Windows
breakpadId,
pdbName);
sharedLibraryInfo.AddSharedLibrary(shlib);
}
}
nsAutoString moduleName(modulePath);
int32_t pos = moduleName.RFindChar('\\');
if (pos != kNotFound) {
moduleName.Cut(0, pos + 1);
}
SharedLibrary shlib((uintptr_t)module.lpBaseOfDll,
(uintptr_t)module.lpBaseOfDll + module.SizeOfImage,
0, // DLLs are always mapped at offset 0 on Windows
breakpadId,
moduleName,
pdbNameStr,
GetVersion(modulePath));
sharedLibraryInfo.AddSharedLibrary(shlib);
FreeLibrary(handleLock); // ok to free null handles
FreeLibrary(handleLock); // ok to free null handles
} while (Module32Next(snap, &module));
}
return sharedLibraryInfo;

View File

@@ -32,8 +32,6 @@ read_procmaps(lul::LUL* aLUL)
for (size_t i = 0; i < info.GetSize(); i++) {
const SharedLibrary& lib = info.GetEntry(i);
std::string nativeName = lib.GetNativeDebugName();
# if defined(USE_FAULTY_LIB)
// We're using faulty.lib. Use a special-case object mapper.
AutoObjectMapperFaultyLib mapper(aLUL->mLog);
@@ -46,11 +44,11 @@ read_procmaps(lul::LUL* aLUL)
// to NotifyAfterMap().
void* image = nullptr;
size_t size = 0;
bool ok = mapper.Map(&image, &size, nativeName);
bool ok = mapper.Map(&image, &size, lib.GetName());
if (ok && image && size > 0) {
aLUL->NotifyAfterMap(lib.GetStart(), lib.GetEnd()-lib.GetStart(),
nativeName.c_str(), image);
} else if (!ok && lib.GetDebugName().IsEmpty()) {
lib.GetName().c_str(), image);
} else if (!ok && lib.GetName() == "") {
// The object has no name and (as a consequence) the mapper
// failed to map it. This happens on Linux, where
// GetInfoForSelf() produces two such mappings: one for the

View File

@@ -17,8 +17,6 @@
#include <stdlib.h>
#include <stdint.h>
#include <nsID.h>
#include "nsString.h"
#include "nsNativeCharsetUtils.h"
class SharedLibrary {
public:
@@ -27,16 +25,12 @@ public:
uintptr_t aEnd,
uintptr_t aOffset,
const std::string& aBreakpadId,
const nsString& aName,
const nsString& aDebugName,
const std::string& aVersion)
const std::string& aName)
: mStart(aStart)
, mEnd(aEnd)
, mOffset(aOffset)
, mBreakpadId(aBreakpadId)
, mName(aName)
, mDebugName(aDebugName)
, mVersion(aVersion)
{}
SharedLibrary(const SharedLibrary& aEntry)
@@ -45,8 +39,6 @@ public:
, mOffset(aEntry.mOffset)
, mBreakpadId(aEntry.mBreakpadId)
, mName(aEntry.mName)
, mDebugName(aEntry.mDebugName)
, mVersion(aEntry.mVersion)
{}
SharedLibrary& operator=(const SharedLibrary& aEntry)
@@ -59,8 +51,6 @@ public:
mOffset = aEntry.mOffset;
mBreakpadId = aEntry.mBreakpadId;
mName = aEntry.mName;
mDebugName = aEntry.mDebugName;
mVersion = aEntry.mVersion;
return *this;
}
@@ -70,25 +60,14 @@ public:
(mEnd == other.mEnd) &&
(mOffset == other.mOffset) &&
(mName == other.mName) &&
(mDebugName == other.mDebugName) &&
(mBreakpadId == other.mBreakpadId) &&
(mVersion == other.mVersion);
(mBreakpadId == other.mBreakpadId);
}
uintptr_t GetStart() const { return mStart; }
uintptr_t GetEnd() const { return mEnd; }
uintptr_t GetOffset() const { return mOffset; }
const std::string &GetBreakpadId() const { return mBreakpadId; }
const nsString &GetName() const { return mName; }
const std::string GetNativeDebugName() const {
nsAutoCString debugNameStr;
NS_CopyUnicodeToNative(mDebugName, debugNameStr);
return debugNameStr.get();
}
const nsString &GetDebugName() const { return mDebugName; }
const std::string &GetVersion() const { return mVersion; }
const std::string &GetName() const { return mName; }
private:
SharedLibrary() {}
@@ -97,9 +76,7 @@ private:
uintptr_t mEnd;
uintptr_t mOffset;
std::string mBreakpadId;
nsString mName;
nsString mDebugName;
std::string mVersion;
std::string mName;
};
static bool