mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Bug 1634785 - Deduplicate shared libraries code r=mstange,profiler-reviewers
This patch finally removes the shared libraries code that was inside tools/profiler and uses the one in base profiler everywhere. Differential Revision: https://phabricator.services.mozilla.com/D220887
This commit is contained in:
parent
08a2b8a117
commit
7221e787cb
@ -16,6 +16,11 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace IPC {
|
||||||
|
template <typename T>
|
||||||
|
struct ParamTraits;
|
||||||
|
} // namespace IPC
|
||||||
|
|
||||||
class SharedLibrary {
|
class SharedLibrary {
|
||||||
public:
|
public:
|
||||||
SharedLibrary(uintptr_t aStart, uintptr_t aEnd, uintptr_t aOffset,
|
SharedLibrary(uintptr_t aStart, uintptr_t aEnd, uintptr_t aOffset,
|
||||||
@ -62,9 +67,9 @@ class SharedLibrary {
|
|||||||
mDebugPath.length() + mVersion.length() + mArch.size();
|
mDebugPath.length() + mVersion.length() + mArch.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
SharedLibrary() : mStart{0}, mEnd{0}, mOffset{0} {}
|
SharedLibrary() : mStart{0}, mEnd{0}, mOffset{0} {}
|
||||||
|
|
||||||
|
private:
|
||||||
uintptr_t mStart;
|
uintptr_t mStart;
|
||||||
uintptr_t mEnd;
|
uintptr_t mEnd;
|
||||||
uintptr_t mOffset;
|
uintptr_t mOffset;
|
||||||
@ -86,6 +91,8 @@ class SharedLibrary {
|
|||||||
std::string mDebugPath;
|
std::string mDebugPath;
|
||||||
std::string mVersion;
|
std::string mVersion;
|
||||||
std::string mArch;
|
std::string mArch;
|
||||||
|
|
||||||
|
friend struct IPC::ParamTraits<SharedLibrary>;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool CompareAddresses(const SharedLibrary& first,
|
static bool CompareAddresses(const SharedLibrary& first,
|
||||||
@ -96,12 +103,12 @@ static bool CompareAddresses(const SharedLibrary& first,
|
|||||||
class SharedLibraryInfo {
|
class SharedLibraryInfo {
|
||||||
public:
|
public:
|
||||||
#ifdef MOZ_GECKO_PROFILER
|
#ifdef MOZ_GECKO_PROFILER
|
||||||
static SharedLibraryInfo GetInfoForSelf();
|
MFBT_API static SharedLibraryInfo GetInfoForSelf();
|
||||||
# ifdef XP_WIN
|
# ifdef XP_WIN
|
||||||
static SharedLibraryInfo GetInfoFromPath(const wchar_t* aPath);
|
MFBT_API static SharedLibraryInfo GetInfoFromPath(const wchar_t* aPath);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
static void Initialize();
|
MFBT_API static void Initialize();
|
||||||
#else
|
#else
|
||||||
static SharedLibraryInfo GetInfoForSelf() { return SharedLibraryInfo(); }
|
static SharedLibraryInfo GetInfoForSelf() { return SharedLibraryInfo(); }
|
||||||
# ifdef XP_WIN
|
# ifdef XP_WIN
|
||||||
@ -177,6 +184,8 @@ class SharedLibraryInfo {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<SharedLibrary> mEntries;
|
std::vector<SharedLibrary> mEntries;
|
||||||
|
|
||||||
|
friend struct IPC::ParamTraits<SharedLibraryInfo>;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BASE_PROFILER_SHARED_LIBRARIES_H_
|
#endif // BASE_PROFILER_SHARED_LIBRARIES_H_
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include "mozilla/GfxMessageUtils.h" // For ParamTraits<GeckoProcessType>
|
#include "mozilla/GfxMessageUtils.h" // For ParamTraits<GeckoProcessType>
|
||||||
#include "mozilla/ResultExtensions.h"
|
#include "mozilla/ResultExtensions.h"
|
||||||
#include "mozilla/Try.h"
|
#include "mozilla/Try.h"
|
||||||
#include "shared-libraries.h"
|
#include "BaseProfilerSharedLibraries.h"
|
||||||
|
|
||||||
static const char MAGIC[] = "permahangsavev1";
|
static const char MAGIC[] = "permahangsavev1";
|
||||||
|
|
||||||
@ -399,7 +399,8 @@ void ReadModuleInformation(HangStack& stack) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (moduleReferenced) {
|
if (moduleReferenced) {
|
||||||
HangModule module(info.GetDebugName(), info.GetBreakpadId());
|
HangModule module(NS_ConvertUTF8toUTF16(info.GetDebugName().c_str()),
|
||||||
|
nsCString(info.GetBreakpadId().c_str()));
|
||||||
stack.modules().AppendElement(module);
|
stack.modules().AppendElement(module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -721,7 +721,9 @@ class GetLoadedModulesResultRunnable final : public Runnable {
|
|||||||
|
|
||||||
// Module name.
|
// Module name.
|
||||||
JS::Rooted<JSString*> moduleName(
|
JS::Rooted<JSString*> moduleName(
|
||||||
cx, JS_NewUCStringCopyZ(cx, info.GetModuleName().get()));
|
cx,
|
||||||
|
JS_NewUCStringCopyZ(
|
||||||
|
cx, NS_ConvertUTF8toUTF16(info.GetModuleName().c_str()).get()));
|
||||||
if (!moduleName || !JS_DefineProperty(cx, moduleObj, "name", moduleName,
|
if (!moduleName || !JS_DefineProperty(cx, moduleObj, "name", moduleName,
|
||||||
JSPROP_ENUMERATE)) {
|
JSPROP_ENUMERATE)) {
|
||||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||||
@ -731,9 +733,11 @@ class GetLoadedModulesResultRunnable final : public Runnable {
|
|||||||
// Module debug name.
|
// Module debug name.
|
||||||
JS::Rooted<JS::Value> moduleDebugName(cx);
|
JS::Rooted<JS::Value> moduleDebugName(cx);
|
||||||
|
|
||||||
if (!info.GetDebugName().IsEmpty()) {
|
if (!info.GetDebugName().empty()) {
|
||||||
JS::Rooted<JSString*> str_moduleDebugName(
|
JS::Rooted<JSString*> str_moduleDebugName(
|
||||||
cx, JS_NewUCStringCopyZ(cx, info.GetDebugName().get()));
|
cx,
|
||||||
|
JS_NewUCStringCopyZ(
|
||||||
|
cx, NS_ConvertUTF8toUTF16(info.GetDebugName().c_str()).get()));
|
||||||
if (!str_moduleDebugName) {
|
if (!str_moduleDebugName) {
|
||||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -752,9 +756,9 @@ class GetLoadedModulesResultRunnable final : public Runnable {
|
|||||||
// Module Breakpad identifier.
|
// Module Breakpad identifier.
|
||||||
JS::Rooted<JS::Value> id(cx);
|
JS::Rooted<JS::Value> id(cx);
|
||||||
|
|
||||||
if (!info.GetBreakpadId().IsEmpty()) {
|
if (!info.GetBreakpadId().empty()) {
|
||||||
JS::Rooted<JSString*> str_id(
|
JS::Rooted<JSString*> str_id(
|
||||||
cx, JS_NewStringCopyZ(cx, info.GetBreakpadId().get()));
|
cx, JS_NewStringCopyZ(cx, info.GetBreakpadId().c_str()));
|
||||||
if (!str_id) {
|
if (!str_id) {
|
||||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -772,9 +776,9 @@ class GetLoadedModulesResultRunnable final : public Runnable {
|
|||||||
// Module version.
|
// Module version.
|
||||||
JS::Rooted<JS::Value> version(cx);
|
JS::Rooted<JS::Value> version(cx);
|
||||||
|
|
||||||
if (!info.GetVersion().IsEmpty()) {
|
if (!info.GetVersion().empty()) {
|
||||||
JS::Rooted<JSString*> v(
|
JS::Rooted<JSString*> v(
|
||||||
cx, JS_NewStringCopyZ(cx, info.GetVersion().BeginReading()));
|
cx, JS_NewStringCopyZ(cx, info.GetVersion().c_str()));
|
||||||
if (!v) {
|
if (!v) {
|
||||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -792,7 +796,8 @@ class GetLoadedModulesResultRunnable final : public Runnable {
|
|||||||
|
|
||||||
# if defined(XP_WIN)
|
# if defined(XP_WIN)
|
||||||
// Cert Subject.
|
// Cert Subject.
|
||||||
if (auto subject = mCertSubjects.Lookup(info.GetModulePath())) {
|
if (auto subject = mCertSubjects.Lookup(
|
||||||
|
NS_ConvertUTF8toUTF16(info.GetModulePath().c_str()))) {
|
||||||
JS::Rooted<JSString*> jsOrg(cx, ToJSString(cx, *subject));
|
JS::Rooted<JSString*> jsOrg(cx, ToJSString(cx, *subject));
|
||||||
if (!jsOrg) {
|
if (!jsOrg) {
|
||||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||||
@ -832,10 +837,12 @@ class GetLoadedModulesResultRunnable final : public Runnable {
|
|||||||
for (unsigned int i = 0, n = mRawModules.GetSize(); i != n; i++) {
|
for (unsigned int i = 0, n = mRawModules.GetSize(); i != n; i++) {
|
||||||
const SharedLibrary& info = mRawModules.GetEntry(i);
|
const SharedLibrary& info = mRawModules.GetEntry(i);
|
||||||
|
|
||||||
auto orgName = dllSvc->GetBinaryOrgName(info.GetModulePath().get());
|
auto orgName = dllSvc->GetBinaryOrgName(
|
||||||
|
NS_ConvertUTF8toUTF16(info.GetModulePath().c_str()).get());
|
||||||
if (orgName) {
|
if (orgName) {
|
||||||
mCertSubjects.InsertOrUpdate(info.GetModulePath(),
|
mCertSubjects.InsertOrUpdate(
|
||||||
nsDependentString(orgName.get()));
|
NS_ConvertUTF8toUTF16(info.GetModulePath().c_str()),
|
||||||
|
nsDependentString(orgName.get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,8 +141,9 @@ static ProcessedStack GetStackAndModulesInternal(
|
|||||||
#ifdef MOZ_GECKO_PROFILER
|
#ifdef MOZ_GECKO_PROFILER
|
||||||
for (unsigned i = 0, n = rawModules.GetSize(); i != n; ++i) {
|
for (unsigned i = 0, n = rawModules.GetSize(); i != n; ++i) {
|
||||||
const SharedLibrary& info = rawModules.GetEntry(i);
|
const SharedLibrary& info = rawModules.GetEntry(i);
|
||||||
mozilla::Telemetry::ProcessedStack::Module module = {info.GetDebugName(),
|
mozilla::Telemetry::ProcessedStack::Module module = {
|
||||||
info.GetBreakpadId()};
|
NS_ConvertUTF8toUTF16(info.GetDebugName().c_str()),
|
||||||
|
nsCString(info.GetBreakpadId().c_str())};
|
||||||
Ret.AddModule(module);
|
Ret.AddModule(module);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#include "mozilla/ipc/MessageChannel.h"
|
#include "mozilla/ipc/MessageChannel.h"
|
||||||
#include "mozilla/Vector.h"
|
#include "mozilla/Vector.h"
|
||||||
#include "nsStringFwd.h"
|
#include "nsStringFwd.h"
|
||||||
#include "shared-libraries.h"
|
#include "BaseProfilerSharedLibraries.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace Telemetry {
|
namespace Telemetry {
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
#include "nsITelemetry.h"
|
#include "nsITelemetry.h"
|
||||||
#include "nsUnicharUtils.h"
|
#include "nsUnicharUtils.h"
|
||||||
#include "nsXULAppAPI.h"
|
#include "nsXULAppAPI.h"
|
||||||
#include "shared-libraries.h"
|
#include "BaseProfilerSharedLibraries.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace Telemetry {
|
namespace Telemetry {
|
||||||
@ -173,9 +173,9 @@ static bool SerializeModule(JSContext* aCx,
|
|||||||
if (aModule->mResolvedDosName->GetPath(path) == NS_OK) {
|
if (aModule->mResolvedDosName->GetPath(path) == NS_OK) {
|
||||||
SharedLibraryInfo info = SharedLibraryInfo::GetInfoFromPath(path.Data());
|
SharedLibraryInfo info = SharedLibraryInfo::GetInfoFromPath(path.Data());
|
||||||
if (info.GetSize() > 0) {
|
if (info.GetSize() > 0) {
|
||||||
nsCString breakpadId = info.GetEntry(0).GetBreakpadId();
|
nsString breakpadId =
|
||||||
if (!AddLengthLimitedStringProp(aCx, obj, "debugID",
|
NS_ConvertUTF8toUTF16(info.GetEntry(0).GetBreakpadId());
|
||||||
NS_ConvertASCIItoUTF16(breakpadId))) {
|
if (!AddLengthLimitedStringProp(aCx, obj, "debugID", breakpadId)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
#include "EHABIStackWalk.h"
|
#include "EHABIStackWalk.h"
|
||||||
|
|
||||||
#include "shared-libraries.h"
|
#include "BaseProfilerSharedLibraries.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
#include "mozilla/Atomics.h"
|
#include "mozilla/Atomics.h"
|
||||||
@ -560,7 +560,7 @@ void EHAddrSpace::Update() {
|
|||||||
// the start address will not point at the file header. But this is worked
|
// the start address will not point at the file header. But this is worked
|
||||||
// around by magic number checks in the EHTable constructor.
|
// around by magic number checks in the EHTable constructor.
|
||||||
EHTable tab(reinterpret_cast<const void*>(lib.GetStart()),
|
EHTable tab(reinterpret_cast<const void*>(lib.GetStart()),
|
||||||
lib.GetEnd() - lib.GetStart(), lib.GetNativeDebugPath());
|
lib.GetEnd() - lib.GetStart(), lib.GetDebugPath());
|
||||||
if (tab.isValid()) tables.push_back(tab);
|
if (tab.isValid()) tables.push_back(tab);
|
||||||
}
|
}
|
||||||
space = new EHAddrSpace(tables);
|
space = new EHAddrSpace(tables);
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
#include "nsDebug.h"
|
#include "nsDebug.h"
|
||||||
#include "nsISupports.h"
|
#include "nsISupports.h"
|
||||||
#include "nsXPCOM.h"
|
#include "nsXPCOM.h"
|
||||||
#include "shared-libraries.h"
|
#include "BaseProfilerSharedLibraries.h"
|
||||||
#include "VTuneProfiler.h"
|
#include "VTuneProfiler.h"
|
||||||
#include "ETWTools.h"
|
#include "ETWTools.h"
|
||||||
|
|
||||||
@ -3061,12 +3061,10 @@ static void AddSharedLibraryInfoToStream(JSONWriter& aWriter,
|
|||||||
aWriter.IntProperty("start", SafeJSInteger(aLib.GetStart()));
|
aWriter.IntProperty("start", SafeJSInteger(aLib.GetStart()));
|
||||||
aWriter.IntProperty("end", SafeJSInteger(aLib.GetEnd()));
|
aWriter.IntProperty("end", SafeJSInteger(aLib.GetEnd()));
|
||||||
aWriter.IntProperty("offset", SafeJSInteger(aLib.GetOffset()));
|
aWriter.IntProperty("offset", SafeJSInteger(aLib.GetOffset()));
|
||||||
aWriter.StringProperty("name", NS_ConvertUTF16toUTF8(aLib.GetModuleName()));
|
aWriter.StringProperty("name", aLib.GetModuleName());
|
||||||
aWriter.StringProperty("path", NS_ConvertUTF16toUTF8(aLib.GetModulePath()));
|
aWriter.StringProperty("path", aLib.GetModulePath());
|
||||||
aWriter.StringProperty("debugName",
|
aWriter.StringProperty("debugName", aLib.GetDebugName());
|
||||||
NS_ConvertUTF16toUTF8(aLib.GetDebugName()));
|
aWriter.StringProperty("debugPath", aLib.GetDebugPath());
|
||||||
aWriter.StringProperty("debugPath",
|
|
||||||
NS_ConvertUTF16toUTF8(aLib.GetDebugPath()));
|
|
||||||
aWriter.StringProperty("breakpadId", aLib.GetBreakpadId());
|
aWriter.StringProperty("breakpadId", aLib.GetBreakpadId());
|
||||||
aWriter.StringProperty("codeId", aLib.GetCodeId());
|
aWriter.StringProperty("codeId", aLib.GetCodeId());
|
||||||
aWriter.StringProperty("arch", aLib.GetArch());
|
aWriter.StringProperty("arch", aLib.GetArch());
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "mozilla/Vector.h"
|
#include "mozilla/Vector.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "shared-libraries.h"
|
#include "BaseProfilerSharedLibraries.h"
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
@ -1,280 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#include "shared-libraries.h"
|
|
||||||
|
|
||||||
#define PATH_MAX_TOSTRING(x) #x
|
|
||||||
#define PATH_MAX_STRING(x) PATH_MAX_TOSTRING(x)
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include "platform.h"
|
|
||||||
#include "shared-libraries.h"
|
|
||||||
#include "GeckoProfiler.h"
|
|
||||||
#include "mozilla/Sprintf.h"
|
|
||||||
#include "mozilla/Unused.h"
|
|
||||||
#include "nsDebug.h"
|
|
||||||
#include "nsNativeCharsetUtils.h"
|
|
||||||
#include <nsTArray.h>
|
|
||||||
|
|
||||||
#include "common/linux/file_id.h"
|
|
||||||
#include <algorithm>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#if defined(GP_OS_linux) || defined(GP_OS_android)
|
|
||||||
# include <features.h>
|
|
||||||
#endif
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#if defined(GP_OS_linux) || defined(GP_OS_android) || defined(GP_OS_freebsd)
|
|
||||||
# include <link.h> // dl_phdr_info
|
|
||||||
#else
|
|
||||||
# error "Unexpected configuration"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(GP_OS_android)
|
|
||||||
extern "C" MOZ_EXPORT __attribute__((weak)) int dl_iterate_phdr(
|
|
||||||
int (*callback)(struct dl_phdr_info* info, size_t size, void* data),
|
|
||||||
void* data);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct LoadedLibraryInfo {
|
|
||||||
LoadedLibraryInfo(const char* aName, unsigned long aBaseAddress,
|
|
||||||
unsigned long aFirstMappingStart,
|
|
||||||
unsigned long aLastMappingEnd)
|
|
||||||
: mName(aName),
|
|
||||||
mBaseAddress(aBaseAddress),
|
|
||||||
mFirstMappingStart(aFirstMappingStart),
|
|
||||||
mLastMappingEnd(aLastMappingEnd) {}
|
|
||||||
|
|
||||||
nsCString mName;
|
|
||||||
unsigned long mBaseAddress;
|
|
||||||
unsigned long mFirstMappingStart;
|
|
||||||
unsigned long mLastMappingEnd;
|
|
||||||
};
|
|
||||||
|
|
||||||
static nsCString IDtoUUIDString(
|
|
||||||
const google_breakpad::wasteful_vector<uint8_t>& aIdentifier) {
|
|
||||||
using namespace google_breakpad;
|
|
||||||
|
|
||||||
nsCString uuid;
|
|
||||||
const std::string str = FileID::ConvertIdentifierToUUIDString(aIdentifier);
|
|
||||||
uuid.Append(str.c_str(), str.size());
|
|
||||||
// This is '0', not '\0', since it represents the breakpad id age.
|
|
||||||
uuid.Append('0');
|
|
||||||
return uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return raw Build ID in hex.
|
|
||||||
static nsCString IDtoString(
|
|
||||||
const google_breakpad::wasteful_vector<uint8_t>& aIdentifier) {
|
|
||||||
using namespace google_breakpad;
|
|
||||||
|
|
||||||
nsCString uuid;
|
|
||||||
const std::string str = FileID::ConvertIdentifierToString(aIdentifier);
|
|
||||||
uuid.Append(str.c_str(), str.size());
|
|
||||||
return uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the breakpad Id for the binary file pointed by bin_name
|
|
||||||
static nsCString getBreakpadId(const char* bin_name) {
|
|
||||||
using namespace google_breakpad;
|
|
||||||
|
|
||||||
PageAllocator allocator;
|
|
||||||
auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier(&allocator);
|
|
||||||
|
|
||||||
FileID file_id(bin_name);
|
|
||||||
if (file_id.ElfFileIdentifier(identifier)) {
|
|
||||||
return IDtoUUIDString(identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""_ns;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the code Id for the binary file pointed by bin_name
|
|
||||||
static nsCString getCodeId(const char* bin_name) {
|
|
||||||
using namespace google_breakpad;
|
|
||||||
|
|
||||||
PageAllocator allocator;
|
|
||||||
auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier(&allocator);
|
|
||||||
|
|
||||||
FileID file_id(bin_name);
|
|
||||||
if (file_id.ElfFileIdentifier(identifier)) {
|
|
||||||
return IDtoString(identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""_ns;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SharedLibrary SharedLibraryAtPath(const char* path,
|
|
||||||
unsigned long libStart,
|
|
||||||
unsigned long libEnd,
|
|
||||||
unsigned long offset = 0) {
|
|
||||||
nsAutoString pathStr;
|
|
||||||
mozilla::Unused << NS_WARN_IF(
|
|
||||||
NS_FAILED(NS_CopyNativeToUnicode(nsDependentCString(path), pathStr)));
|
|
||||||
|
|
||||||
nsAutoString nameStr = pathStr;
|
|
||||||
int32_t pos = nameStr.RFindChar('/');
|
|
||||||
if (pos != kNotFound) {
|
|
||||||
nameStr.Cut(0, pos + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SharedLibrary(libStart, libEnd, offset, getBreakpadId(path),
|
|
||||||
getCodeId(path), nameStr, pathStr, nameStr, pathStr,
|
|
||||||
""_ns, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dl_iterate_callback(struct dl_phdr_info* dl_info, size_t size,
|
|
||||||
void* data) {
|
|
||||||
auto libInfoList = reinterpret_cast<nsTArray<LoadedLibraryInfo>*>(data);
|
|
||||||
|
|
||||||
if (dl_info->dlpi_phnum <= 0) return 0;
|
|
||||||
|
|
||||||
unsigned long baseAddress = dl_info->dlpi_addr;
|
|
||||||
unsigned long firstMappingStart = -1;
|
|
||||||
unsigned long lastMappingEnd = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < dl_info->dlpi_phnum; i++) {
|
|
||||||
if (dl_info->dlpi_phdr[i].p_type != PT_LOAD) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
unsigned long start = dl_info->dlpi_addr + dl_info->dlpi_phdr[i].p_vaddr;
|
|
||||||
unsigned long end = start + dl_info->dlpi_phdr[i].p_memsz;
|
|
||||||
if (start < firstMappingStart) {
|
|
||||||
firstMappingStart = start;
|
|
||||||
}
|
|
||||||
if (end > lastMappingEnd) {
|
|
||||||
lastMappingEnd = end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
libInfoList->AppendElement(LoadedLibraryInfo(
|
|
||||||
dl_info->dlpi_name, baseAddress, firstMappingStart, lastMappingEnd));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() {
|
|
||||||
SharedLibraryInfo info;
|
|
||||||
|
|
||||||
#if defined(GP_OS_linux)
|
|
||||||
// We need to find the name of the executable (exeName, exeNameLen) and the
|
|
||||||
// address of its executable section (exeExeAddr) in the running image.
|
|
||||||
char exeName[PATH_MAX];
|
|
||||||
memset(exeName, 0, sizeof(exeName));
|
|
||||||
|
|
||||||
ssize_t exeNameLen = readlink("/proc/self/exe", exeName, sizeof(exeName) - 1);
|
|
||||||
if (exeNameLen == -1) {
|
|
||||||
// readlink failed for whatever reason. Note this, but keep going.
|
|
||||||
exeName[0] = '\0';
|
|
||||||
exeNameLen = 0;
|
|
||||||
LOG("SharedLibraryInfo::GetInfoForSelf(): readlink failed");
|
|
||||||
} else {
|
|
||||||
// Assert no buffer overflow.
|
|
||||||
MOZ_RELEASE_ASSERT(exeNameLen >= 0 &&
|
|
||||||
exeNameLen < static_cast<ssize_t>(sizeof(exeName)));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long exeExeAddr = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(GP_OS_android)
|
|
||||||
// If dl_iterate_phdr doesn't exist, we give up immediately.
|
|
||||||
if (!dl_iterate_phdr) {
|
|
||||||
// On ARM Android, dl_iterate_phdr is provided by the custom linker.
|
|
||||||
// So if libxul was loaded by the system linker (e.g. as part of
|
|
||||||
// xpcshell when running tests), it won't be available and we should
|
|
||||||
// not call it.
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(GP_OS_linux) || defined(GP_OS_android)
|
|
||||||
// Read info from /proc/self/maps. We ignore most of it.
|
|
||||||
pid_t pid = profiler_current_process_id().ToNumber();
|
|
||||||
char path[PATH_MAX];
|
|
||||||
char modulePath[PATH_MAX + 1];
|
|
||||||
SprintfLiteral(path, "/proc/%d/maps", pid);
|
|
||||||
std::ifstream maps(path);
|
|
||||||
std::string line;
|
|
||||||
while (std::getline(maps, line)) {
|
|
||||||
int ret;
|
|
||||||
unsigned long start;
|
|
||||||
unsigned long end;
|
|
||||||
char perm[6 + 1] = "";
|
|
||||||
unsigned long offset;
|
|
||||||
modulePath[0] = 0;
|
|
||||||
ret = sscanf(line.c_str(),
|
|
||||||
"%lx-%lx %6s %lx %*s %*x %" PATH_MAX_STRING(PATH_MAX) "s\n",
|
|
||||||
&start, &end, perm, &offset, modulePath);
|
|
||||||
if (!strchr(perm, 'x')) {
|
|
||||||
// Ignore non executable entries
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ret != 5 && ret != 4) {
|
|
||||||
LOG("SharedLibraryInfo::GetInfoForSelf(): "
|
|
||||||
"reading /proc/self/maps failed");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
# if defined(GP_OS_linux)
|
|
||||||
// Try to establish the main executable's load address.
|
|
||||||
if (exeNameLen > 0 && strcmp(modulePath, exeName) == 0) {
|
|
||||||
exeExeAddr = start;
|
|
||||||
}
|
|
||||||
# elif defined(GP_OS_android)
|
|
||||||
// Use /proc/pid/maps to get the dalvik-jit section since it has no
|
|
||||||
// associated phdrs.
|
|
||||||
if (0 == strcmp(modulePath, "/dev/ashmem/dalvik-jit-code-cache")) {
|
|
||||||
info.AddSharedLibrary(
|
|
||||||
SharedLibraryAtPath(modulePath, start, end, offset));
|
|
||||||
if (info.GetSize() > 10000) {
|
|
||||||
LOG("SharedLibraryInfo::GetInfoForSelf(): "
|
|
||||||
"implausibly large number of mappings acquired");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
nsTArray<LoadedLibraryInfo> libInfoList;
|
|
||||||
|
|
||||||
// We collect the bulk of the library info using dl_iterate_phdr.
|
|
||||||
dl_iterate_phdr(dl_iterate_callback, &libInfoList);
|
|
||||||
|
|
||||||
for (const auto& libInfo : libInfoList) {
|
|
||||||
info.AddSharedLibrary(
|
|
||||||
SharedLibraryAtPath(libInfo.mName.get(), libInfo.mFirstMappingStart,
|
|
||||||
libInfo.mLastMappingEnd,
|
|
||||||
libInfo.mFirstMappingStart - libInfo.mBaseAddress));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(GP_OS_linux)
|
|
||||||
// Make another pass over the information we just harvested from
|
|
||||||
// dl_iterate_phdr. If we see a nameless object mapped at what we earlier
|
|
||||||
// established to be the main executable's load address, attach the
|
|
||||||
// executable's name to that entry.
|
|
||||||
for (size_t i = 0; i < info.GetSize(); i++) {
|
|
||||||
SharedLibrary& lib = info.GetMutableEntry(i);
|
|
||||||
if (lib.GetStart() <= exeExeAddr && exeExeAddr <= lib.GetEnd() &&
|
|
||||||
lib.GetNativeDebugPath().empty()) {
|
|
||||||
lib = SharedLibraryAtPath(exeName, lib.GetStart(), lib.GetEnd(),
|
|
||||||
lib.GetOffset());
|
|
||||||
|
|
||||||
// We only expect to see one such entry.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedLibraryInfo::Initialize() { /* do nothing */ }
|
|
@ -1,211 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#include "shared-libraries.h"
|
|
||||||
|
|
||||||
#include "ClearOnShutdown.h"
|
|
||||||
#include "mozilla/StaticMutex.h"
|
|
||||||
#include "mozilla/Unused.h"
|
|
||||||
#include "nsNativeCharsetUtils.h"
|
|
||||||
#include <AvailabilityMacros.h>
|
|
||||||
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <mach-o/arch.h>
|
|
||||||
#include <mach-o/dyld_images.h>
|
|
||||||
#include <mach-o/dyld.h>
|
|
||||||
#include <mach-o/loader.h>
|
|
||||||
#include <mach/mach_init.h>
|
|
||||||
#include <mach/mach_traps.h>
|
|
||||||
#include <mach/task_info.h>
|
|
||||||
#include <mach/task.h>
|
|
||||||
#include <sstream>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
// Architecture specific abstraction.
|
|
||||||
#if defined(GP_ARCH_x86)
|
|
||||||
typedef mach_header platform_mach_header;
|
|
||||||
typedef segment_command mach_segment_command_type;
|
|
||||||
# define MACHO_MAGIC_NUMBER MH_MAGIC
|
|
||||||
# define CMD_SEGMENT LC_SEGMENT
|
|
||||||
# define seg_size uint32_t
|
|
||||||
#else
|
|
||||||
typedef mach_header_64 platform_mach_header;
|
|
||||||
typedef segment_command_64 mach_segment_command_type;
|
|
||||||
# define MACHO_MAGIC_NUMBER MH_MAGIC_64
|
|
||||||
# define CMD_SEGMENT LC_SEGMENT_64
|
|
||||||
# define seg_size uint64_t
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct NativeSharedLibrary {
|
|
||||||
const platform_mach_header* header;
|
|
||||||
std::string path;
|
|
||||||
};
|
|
||||||
static std::vector<NativeSharedLibrary>* sSharedLibrariesList = nullptr;
|
|
||||||
static mozilla::StaticMutex sSharedLibrariesMutex MOZ_UNANNOTATED;
|
|
||||||
|
|
||||||
static void SharedLibraryAddImage(const struct mach_header* mh,
|
|
||||||
intptr_t vmaddr_slide) {
|
|
||||||
// NOTE: Presumably for backwards-compatibility reasons, this function accepts
|
|
||||||
// a mach_header even on 64-bit where it ought to be a mach_header_64. We cast
|
|
||||||
// it to the right type here.
|
|
||||||
auto header = reinterpret_cast<const platform_mach_header*>(mh);
|
|
||||||
|
|
||||||
Dl_info info;
|
|
||||||
if (!dladdr(header, &info)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mozilla::StaticMutexAutoLock lock(sSharedLibrariesMutex);
|
|
||||||
if (!sSharedLibrariesList) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NativeSharedLibrary lib = {header, info.dli_fname};
|
|
||||||
sSharedLibrariesList->push_back(lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SharedLibraryRemoveImage(const struct mach_header* mh,
|
|
||||||
intptr_t vmaddr_slide) {
|
|
||||||
// NOTE: Presumably for backwards-compatibility reasons, this function accepts
|
|
||||||
// a mach_header even on 64-bit where it ought to be a mach_header_64. We cast
|
|
||||||
// it to the right type here.
|
|
||||||
auto header = reinterpret_cast<const platform_mach_header*>(mh);
|
|
||||||
|
|
||||||
mozilla::StaticMutexAutoLock lock(sSharedLibrariesMutex);
|
|
||||||
if (!sSharedLibrariesList) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t count = sSharedLibrariesList->size();
|
|
||||||
for (uint32_t i = 0; i < count; ++i) {
|
|
||||||
if ((*sSharedLibrariesList)[i].header == header) {
|
|
||||||
sSharedLibrariesList->erase(sSharedLibrariesList->begin() + i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedLibraryInfo::Initialize() {
|
|
||||||
// NOTE: We intentionally leak this memory here. We're allocating dynamically
|
|
||||||
// in order to avoid static initializers.
|
|
||||||
sSharedLibrariesList = new std::vector<NativeSharedLibrary>();
|
|
||||||
|
|
||||||
_dyld_register_func_for_add_image(SharedLibraryAddImage);
|
|
||||||
_dyld_register_func_for_remove_image(SharedLibraryRemoveImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addSharedLibrary(const platform_mach_header* header,
|
|
||||||
const char* path, SharedLibraryInfo& info) {
|
|
||||||
const struct load_command* cmd =
|
|
||||||
reinterpret_cast<const struct load_command*>(header + 1);
|
|
||||||
|
|
||||||
seg_size size = 0;
|
|
||||||
unsigned long long start = reinterpret_cast<unsigned long long>(header);
|
|
||||||
// Find the cmd segment in the macho image. It will contain the offset we care
|
|
||||||
// about.
|
|
||||||
const uint8_t* uuid_bytes = nullptr;
|
|
||||||
for (unsigned int i = 0;
|
|
||||||
cmd && (i < header->ncmds) && (uuid_bytes == nullptr || size == 0);
|
|
||||||
++i) {
|
|
||||||
if (cmd->cmd == CMD_SEGMENT) {
|
|
||||||
const mach_segment_command_type* seg =
|
|
||||||
reinterpret_cast<const mach_segment_command_type*>(cmd);
|
|
||||||
|
|
||||||
if (!strcmp(seg->segname, "__TEXT")) {
|
|
||||||
size = seg->vmsize;
|
|
||||||
}
|
|
||||||
} else if (cmd->cmd == LC_UUID) {
|
|
||||||
const uuid_command* ucmd = reinterpret_cast<const uuid_command*>(cmd);
|
|
||||||
uuid_bytes = ucmd->uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd = reinterpret_cast<const struct load_command*>(
|
|
||||||
reinterpret_cast<const char*>(cmd) + cmd->cmdsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoCString uuid;
|
|
||||||
nsAutoCString breakpadId;
|
|
||||||
if (uuid_bytes != nullptr) {
|
|
||||||
uuid.AppendPrintf(
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X"
|
|
||||||
"%02X",
|
|
||||||
uuid_bytes[0], uuid_bytes[1], uuid_bytes[2], uuid_bytes[3],
|
|
||||||
uuid_bytes[4], uuid_bytes[5], uuid_bytes[6], uuid_bytes[7],
|
|
||||||
uuid_bytes[8], uuid_bytes[9], uuid_bytes[10], uuid_bytes[11],
|
|
||||||
uuid_bytes[12], uuid_bytes[13], uuid_bytes[14], uuid_bytes[15]);
|
|
||||||
|
|
||||||
// Breakpad id is the same as the uuid but with the additional trailing 0
|
|
||||||
// for the breakpad id age.
|
|
||||||
breakpadId.AppendPrintf(
|
|
||||||
"%s"
|
|
||||||
"0" /* breakpad id age */,
|
|
||||||
uuid.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString pathStr;
|
|
||||||
mozilla::Unused << NS_WARN_IF(
|
|
||||||
NS_FAILED(NS_CopyNativeToUnicode(nsDependentCString(path), pathStr)));
|
|
||||||
|
|
||||||
nsAutoString nameStr = pathStr;
|
|
||||||
int32_t pos = nameStr.RFindChar('/');
|
|
||||||
if (pos != kNotFound) {
|
|
||||||
nameStr.Cut(0, pos + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const NXArchInfo* archInfo =
|
|
||||||
NXGetArchInfoFromCpuType(header->cputype, header->cpusubtype);
|
|
||||||
|
|
||||||
info.AddSharedLibrary(SharedLibrary(start, start + size, 0, breakpadId, uuid,
|
|
||||||
nameStr, pathStr, nameStr, pathStr, ""_ns,
|
|
||||||
archInfo ? archInfo->name : ""));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translate the statically stored sSharedLibrariesList information into a
|
|
||||||
// SharedLibraryInfo object.
|
|
||||||
SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() {
|
|
||||||
mozilla::StaticMutexAutoLock lock(sSharedLibrariesMutex);
|
|
||||||
SharedLibraryInfo sharedLibraryInfo;
|
|
||||||
|
|
||||||
for (auto& info : *sSharedLibrariesList) {
|
|
||||||
addSharedLibrary(info.header, info.path.c_str(), sharedLibraryInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the entry for dyld itself.
|
|
||||||
// We only support macOS 10.12+, which corresponds to dyld version 15+.
|
|
||||||
// dyld version 15 added the dyldPath property.
|
|
||||||
task_dyld_info_data_t task_dyld_info;
|
|
||||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
|
||||||
if (task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info,
|
|
||||||
&count) != KERN_SUCCESS) {
|
|
||||||
return sharedLibraryInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dyld_all_image_infos* aii =
|
|
||||||
(struct dyld_all_image_infos*)task_dyld_info.all_image_info_addr;
|
|
||||||
if (aii->version >= 15) {
|
|
||||||
const platform_mach_header* header =
|
|
||||||
reinterpret_cast<const platform_mach_header*>(
|
|
||||||
aii->dyldImageLoadAddress);
|
|
||||||
addSharedLibrary(header, aii->dyldPath, sharedLibraryInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sharedLibraryInfo;
|
|
||||||
}
|
|
@ -1,145 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#include "shared-libraries.h"
|
|
||||||
#include "nsWindowsHelpers.h"
|
|
||||||
#include "mozilla/NativeNt.h"
|
|
||||||
#include "mozilla/WindowsEnumProcessModules.h"
|
|
||||||
#include "mozilla/WindowsProcessMitigations.h"
|
|
||||||
#include "nsPrintfCString.h"
|
|
||||||
|
|
||||||
static bool IsModuleUnsafeToLoad(const nsAString& aModuleName) {
|
|
||||||
// Hackaround for Bug 1723868. There is no safe way to prevent the module
|
|
||||||
// Microsoft's VP9 Video Decoder from being unloaded because mfplat.dll may
|
|
||||||
// have posted more than one task to unload the module in the work queue
|
|
||||||
// without calling LoadLibrary.
|
|
||||||
if (aModuleName.LowerCaseEqualsLiteral("msvp9dec_store.dll")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddSharedLibraryFromModuleInfo(SharedLibraryInfo& sharedLibraryInfo,
|
|
||||||
const wchar_t* aModulePath,
|
|
||||||
mozilla::Maybe<HMODULE> aModule) {
|
|
||||||
nsDependentSubstring moduleNameStr(
|
|
||||||
mozilla::nt::GetLeafName(nsDependentString(aModulePath)));
|
|
||||||
|
|
||||||
// If the module is unsafe to call LoadLibraryEx for, we skip.
|
|
||||||
if (IsModuleUnsafeToLoad(moduleNameStr)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If EAF+ is enabled, parsing ntdll's PE header causes a crash.
|
|
||||||
if (mozilla::IsEafPlusEnabled() &&
|
|
||||||
moduleNameStr.LowerCaseEqualsLiteral("ntdll.dll")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the module again - to make sure that its handle will remain valid as
|
|
||||||
// we attempt to read the PDB information from it - or for the first time if
|
|
||||||
// we only have a path. We want to load the DLL without running the newly
|
|
||||||
// loaded module's DllMain function, but not as a data file because we want
|
|
||||||
// to be able to do RVA computations easily. Hence, we use the flag
|
|
||||||
// LOAD_LIBRARY_AS_IMAGE_RESOURCE which ensures that the sections (not PE
|
|
||||||
// headers) will be relocated by the loader. Otherwise GetPdbInfo() and/or
|
|
||||||
// GetVersionInfo() can cause a crash. If the original handle |aModule| is
|
|
||||||
// valid, LoadLibraryEx just increments its refcount.
|
|
||||||
nsModuleHandle handleLock(
|
|
||||||
::LoadLibraryExW(aModulePath, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE));
|
|
||||||
if (!handleLock) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mozilla::nt::PEHeaders headers(handleLock.get());
|
|
||||||
if (!headers) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mozilla::Maybe<mozilla::Range<const uint8_t>> bounds = headers.GetBounds();
|
|
||||||
if (!bounds) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put the original |aModule| into SharedLibrary, but we get debug info
|
|
||||||
// from |handleLock| as |aModule| might be inaccessible.
|
|
||||||
const uintptr_t modStart =
|
|
||||||
aModule.isSome() ? reinterpret_cast<uintptr_t>(*aModule)
|
|
||||||
: reinterpret_cast<uintptr_t>(handleLock.get());
|
|
||||||
const uintptr_t modEnd = modStart + bounds->length();
|
|
||||||
|
|
||||||
nsAutoCString breakpadId;
|
|
||||||
nsAutoString pdbPathStr;
|
|
||||||
if (const auto* debugInfo = headers.GetPdbInfo()) {
|
|
||||||
MOZ_ASSERT(breakpadId.IsEmpty());
|
|
||||||
const GUID& pdbSig = debugInfo->pdbSignature;
|
|
||||||
breakpadId.AppendPrintf(
|
|
||||||
"%08lX" // m0
|
|
||||||
"%04X%04X" // m1,m2
|
|
||||||
"%02X%02X%02X%02X%02X%02X%02X%02X" // m3
|
|
||||||
"%X", // pdbAge
|
|
||||||
pdbSig.Data1, pdbSig.Data2, pdbSig.Data3, pdbSig.Data4[0],
|
|
||||||
pdbSig.Data4[1], pdbSig.Data4[2], pdbSig.Data4[3], pdbSig.Data4[4],
|
|
||||||
pdbSig.Data4[5], pdbSig.Data4[6], pdbSig.Data4[7], debugInfo->pdbAge);
|
|
||||||
|
|
||||||
// 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
|
|
||||||
pdbPathStr = NS_ConvertUTF8toUTF16(debugInfo->pdbFileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoCString codeId;
|
|
||||||
DWORD timestamp;
|
|
||||||
DWORD imageSize;
|
|
||||||
if (headers.GetTimeStamp(timestamp) && headers.GetImageSize(imageSize)) {
|
|
||||||
codeId.AppendPrintf(
|
|
||||||
"%08lX" // Uppercase 8 digits of hex timestamp with leading zeroes.
|
|
||||||
"%lx", // Lowercase hex image size
|
|
||||||
timestamp, imageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoCString versionStr;
|
|
||||||
uint64_t version;
|
|
||||||
if (headers.GetVersionInfo(version)) {
|
|
||||||
versionStr.AppendPrintf("%u.%u.%u.%u",
|
|
||||||
static_cast<uint32_t>((version >> 48) & 0xFFFFu),
|
|
||||||
static_cast<uint32_t>((version >> 32) & 0xFFFFu),
|
|
||||||
static_cast<uint32_t>((version >> 16) & 0xFFFFu),
|
|
||||||
static_cast<uint32_t>(version & 0xFFFFu));
|
|
||||||
}
|
|
||||||
|
|
||||||
const nsString& pdbNameStr =
|
|
||||||
PromiseFlatString(mozilla::nt::GetLeafName(pdbPathStr));
|
|
||||||
SharedLibrary shlib(modStart, modEnd,
|
|
||||||
0, // DLLs are always mapped at offset 0 on Windows
|
|
||||||
breakpadId, codeId, PromiseFlatString(moduleNameStr),
|
|
||||||
nsDependentString(aModulePath), pdbNameStr, pdbPathStr,
|
|
||||||
versionStr, "");
|
|
||||||
sharedLibraryInfo.AddSharedLibrary(shlib);
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() {
|
|
||||||
SharedLibraryInfo sharedLibraryInfo;
|
|
||||||
|
|
||||||
auto addSharedLibraryFromModuleInfo =
|
|
||||||
[&sharedLibraryInfo](const wchar_t* aModulePath, HMODULE aModule) {
|
|
||||||
AddSharedLibraryFromModuleInfo(sharedLibraryInfo, aModulePath,
|
|
||||||
mozilla::Some(aModule));
|
|
||||||
};
|
|
||||||
|
|
||||||
mozilla::EnumerateProcessModules(addSharedLibraryFromModuleInfo);
|
|
||||||
return sharedLibraryInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedLibraryInfo SharedLibraryInfo::GetInfoFromPath(const wchar_t* aPath) {
|
|
||||||
SharedLibraryInfo sharedLibraryInfo;
|
|
||||||
AddSharedLibraryFromModuleInfo(sharedLibraryInfo, aPath, mozilla::Nothing());
|
|
||||||
return sharedLibraryInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedLibraryInfo::Initialize() { /* do nothing */ }
|
|
@ -37,7 +37,7 @@
|
|||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "shared-libraries.h"
|
#include "BaseProfilerSharedLibraries.h"
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
|
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "PlatformMacros.h"
|
#include "PlatformMacros.h"
|
||||||
#include "LulMain.h"
|
#include "LulMain.h"
|
||||||
#include "shared-libraries.h"
|
#include "BaseProfilerSharedLibraries.h"
|
||||||
#include "AutoObjectMapper.h"
|
#include "AutoObjectMapper.h"
|
||||||
|
|
||||||
// Contains miscellaneous helpers that are used to connect the Gecko Profiler
|
// Contains miscellaneous helpers that are used to connect the Gecko Profiler
|
||||||
@ -31,7 +31,7 @@ void read_procmaps(lul::LUL* aLUL) {
|
|||||||
for (size_t i = 0; i < info.GetSize(); i++) {
|
for (size_t i = 0; i < info.GetSize(); i++) {
|
||||||
const SharedLibrary& lib = info.GetEntry(i);
|
const SharedLibrary& lib = info.GetEntry(i);
|
||||||
|
|
||||||
std::string nativePath = lib.GetNativeDebugPath();
|
std::string nativePath = lib.GetDebugPath();
|
||||||
|
|
||||||
// We can use the standard POSIX-based mapper.
|
// We can use the standard POSIX-based mapper.
|
||||||
AutoObjectMapperPOSIX mapper(aLUL->mLog);
|
AutoObjectMapperPOSIX mapper(aLUL->mLog);
|
||||||
@ -44,7 +44,7 @@ void read_procmaps(lul::LUL* aLUL) {
|
|||||||
if (ok && image && size > 0) {
|
if (ok && image && size > 0) {
|
||||||
aLUL->NotifyAfterMap(lib.GetStart(), lib.GetEnd() - lib.GetStart(),
|
aLUL->NotifyAfterMap(lib.GetStart(), lib.GetEnd() - lib.GetStart(),
|
||||||
nativePath.c_str(), image);
|
nativePath.c_str(), image);
|
||||||
} else if (!ok && lib.GetDebugName().IsEmpty()) {
|
} else if (!ok && lib.GetDebugName().empty()) {
|
||||||
// The object has no name and (as a consequence) the mapper failed to map
|
// The object has no name and (as a consequence) the mapper failed to map
|
||||||
// it. This happens on Linux, where GetInfoForSelf() produces such a
|
// it. This happens on Linux, where GetInfoForSelf() produces such a
|
||||||
// mapping for the VDSO. This is a problem on x86-{linux,android} because
|
// mapping for the VDSO. This is a problem on x86-{linux,android} because
|
||||||
|
@ -66,10 +66,6 @@ if CONFIG["MOZ_GECKO_PROFILER"]:
|
|||||||
"lul/LulMain.cpp",
|
"lul/LulMain.cpp",
|
||||||
"lul/platform-linux-lul.cpp",
|
"lul/platform-linux-lul.cpp",
|
||||||
]
|
]
|
||||||
# These files cannot be built in unified mode because of name clashes with mozglue headers on Android.
|
|
||||||
SOURCES += [
|
|
||||||
"core/shared-libraries-linux.cc",
|
|
||||||
]
|
|
||||||
if not CONFIG["MOZ_CRASHREPORTER"]:
|
if not CONFIG["MOZ_CRASHREPORTER"]:
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
"/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc",
|
"/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc",
|
||||||
@ -94,9 +90,6 @@ if CONFIG["MOZ_GECKO_PROFILER"]:
|
|||||||
"core/EHABIStackWalk.cpp",
|
"core/EHABIStackWalk.cpp",
|
||||||
]
|
]
|
||||||
elif CONFIG["OS_TARGET"] == "Darwin":
|
elif CONFIG["OS_TARGET"] == "Darwin":
|
||||||
UNIFIED_SOURCES += [
|
|
||||||
"core/shared-libraries-macos.cc",
|
|
||||||
]
|
|
||||||
if CONFIG["TARGET_CPU"] == "aarch64":
|
if CONFIG["TARGET_CPU"] == "aarch64":
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
"core/PowerCounters-mac-arm64.cpp",
|
"core/PowerCounters-mac-arm64.cpp",
|
||||||
@ -115,7 +108,6 @@ if CONFIG["MOZ_GECKO_PROFILER"]:
|
|||||||
}
|
}
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
"core/ProfilerCPUFreq-win.cpp",
|
"core/ProfilerCPUFreq-win.cpp",
|
||||||
"core/shared-libraries-win32.cc",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
LOCAL_INCLUDES += [
|
LOCAL_INCLUDES += [
|
||||||
@ -180,7 +172,6 @@ EXPORTS += [
|
|||||||
"public/ProfilerParent.h",
|
"public/ProfilerParent.h",
|
||||||
"public/ProfilerRustBindings.h",
|
"public/ProfilerRustBindings.h",
|
||||||
"public/ProfilerStackWalk.h",
|
"public/ProfilerStackWalk.h",
|
||||||
"public/shared-libraries.h",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
EXPORTS.mozilla += [
|
EXPORTS.mozilla += [
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
#ifndef ProfileAdditionalInformation_h
|
#ifndef ProfileAdditionalInformation_h
|
||||||
#define ProfileAdditionalInformation_h
|
#define ProfileAdditionalInformation_h
|
||||||
|
|
||||||
#include "shared-libraries.h"
|
#include "BaseProfilerSharedLibraries.h"
|
||||||
#include "js/Value.h"
|
#include "js/Value.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
|
|
||||||
|
@ -1,202 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#ifndef SHARED_LIBRARIES_H_
|
|
||||||
#define SHARED_LIBRARIES_H_
|
|
||||||
|
|
||||||
#include "nsNativeCharsetUtils.h"
|
|
||||||
#include "nsString.h"
|
|
||||||
#include <nsID.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace IPC {
|
|
||||||
class MessageReader;
|
|
||||||
class MessageWriter;
|
|
||||||
template <typename T>
|
|
||||||
struct ParamTraits;
|
|
||||||
} // namespace IPC
|
|
||||||
|
|
||||||
class SharedLibrary {
|
|
||||||
public:
|
|
||||||
SharedLibrary(uintptr_t aStart, uintptr_t aEnd, uintptr_t aOffset,
|
|
||||||
const nsCString& aBreakpadId, const nsCString& aCodeId,
|
|
||||||
const nsString& aModuleName, const nsString& aModulePath,
|
|
||||||
const nsString& aDebugName, const nsString& aDebugPath,
|
|
||||||
const nsCString& aVersion, const char* aArch)
|
|
||||||
: mStart(aStart),
|
|
||||||
mEnd(aEnd),
|
|
||||||
mOffset(aOffset),
|
|
||||||
mBreakpadId(aBreakpadId),
|
|
||||||
mCodeId(aCodeId),
|
|
||||||
mModuleName(aModuleName),
|
|
||||||
mModulePath(aModulePath),
|
|
||||||
mDebugName(aDebugName),
|
|
||||||
mDebugPath(aDebugPath),
|
|
||||||
mVersion(aVersion),
|
|
||||||
mArch(aArch) {}
|
|
||||||
|
|
||||||
bool operator==(const SharedLibrary& other) const {
|
|
||||||
return (mStart == other.mStart) && (mEnd == other.mEnd) &&
|
|
||||||
(mOffset == other.mOffset) && (mModuleName == other.mModuleName) &&
|
|
||||||
(mModulePath == other.mModulePath) &&
|
|
||||||
(mDebugName == other.mDebugName) &&
|
|
||||||
(mDebugPath == other.mDebugPath) &&
|
|
||||||
(mBreakpadId == other.mBreakpadId) && (mCodeId == other.mCodeId) &&
|
|
||||||
(mVersion == other.mVersion) && (mArch == other.mArch);
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t GetStart() const { return mStart; }
|
|
||||||
uintptr_t GetEnd() const { return mEnd; }
|
|
||||||
uintptr_t GetOffset() const { return mOffset; }
|
|
||||||
const nsCString& GetBreakpadId() const { return mBreakpadId; }
|
|
||||||
const nsCString& GetCodeId() const { return mCodeId; }
|
|
||||||
const nsString& GetModuleName() const { return mModuleName; }
|
|
||||||
const nsString& GetModulePath() const { return mModulePath; }
|
|
||||||
const std::string GetNativeDebugPath() const {
|
|
||||||
nsAutoCString debugPathStr;
|
|
||||||
|
|
||||||
NS_CopyUnicodeToNative(mDebugPath, debugPathStr);
|
|
||||||
|
|
||||||
return debugPathStr.get();
|
|
||||||
}
|
|
||||||
const nsString& GetDebugName() const { return mDebugName; }
|
|
||||||
const nsString& GetDebugPath() const { return mDebugPath; }
|
|
||||||
const nsCString& GetVersion() const { return mVersion; }
|
|
||||||
const std::string& GetArch() const { return mArch; }
|
|
||||||
size_t SizeOf() const {
|
|
||||||
return sizeof *this + mBreakpadId.Length() + mCodeId.Length() +
|
|
||||||
mModuleName.Length() * 2 + mModulePath.Length() * 2 +
|
|
||||||
mDebugName.Length() * 2 + mDebugPath.Length() * 2 +
|
|
||||||
mVersion.Length() + mArch.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedLibrary() : mStart{0}, mEnd{0}, mOffset{0} {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
uintptr_t mStart;
|
|
||||||
uintptr_t mEnd;
|
|
||||||
uintptr_t mOffset;
|
|
||||||
nsCString mBreakpadId;
|
|
||||||
// A string carrying an identifier for a binary.
|
|
||||||
//
|
|
||||||
// All platforms have different formats:
|
|
||||||
// - Windows: The code ID for a Windows PE file.
|
|
||||||
// It's the PE timestamp and PE image size.
|
|
||||||
// - macOS: The code ID for a macOS / iOS binary (mach-O).
|
|
||||||
// It's the mach-O UUID without dashes and without the trailing 0 for the
|
|
||||||
// breakpad ID.
|
|
||||||
// - Linux/Android: The code ID for a Linux ELF file.
|
|
||||||
// It's the complete build ID, as hex string.
|
|
||||||
nsCString mCodeId;
|
|
||||||
nsString mModuleName;
|
|
||||||
nsString mModulePath;
|
|
||||||
nsString mDebugName;
|
|
||||||
nsString mDebugPath;
|
|
||||||
nsCString mVersion;
|
|
||||||
std::string mArch;
|
|
||||||
|
|
||||||
friend struct IPC::ParamTraits<SharedLibrary>;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool CompareAddresses(const SharedLibrary& first,
|
|
||||||
const SharedLibrary& second) {
|
|
||||||
return first.GetStart() < second.GetStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
class SharedLibraryInfo {
|
|
||||||
public:
|
|
||||||
#ifdef MOZ_GECKO_PROFILER
|
|
||||||
static SharedLibraryInfo GetInfoForSelf();
|
|
||||||
# ifdef XP_WIN
|
|
||||||
static SharedLibraryInfo GetInfoFromPath(const wchar_t* aPath);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
static void Initialize();
|
|
||||||
#else
|
|
||||||
static SharedLibraryInfo GetInfoForSelf() { return SharedLibraryInfo(); }
|
|
||||||
# ifdef XP_WIN
|
|
||||||
static SharedLibraryInfo GetInfoFromPath(const wchar_t* aPath) {
|
|
||||||
return SharedLibraryInfo();
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
static void Initialize() {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void AddSharedLibrary(SharedLibrary entry) { mEntries.push_back(entry); }
|
|
||||||
|
|
||||||
void AddAllSharedLibraries(const SharedLibraryInfo& sharedLibraryInfo) {
|
|
||||||
mEntries.insert(mEntries.end(), sharedLibraryInfo.mEntries.begin(),
|
|
||||||
sharedLibraryInfo.mEntries.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
const SharedLibrary& GetEntry(size_t i) const { return mEntries[i]; }
|
|
||||||
|
|
||||||
SharedLibrary& GetMutableEntry(size_t i) { return mEntries[i]; }
|
|
||||||
|
|
||||||
// Removes items in the range [first, last)
|
|
||||||
// i.e. element at the "last" index is not removed
|
|
||||||
void RemoveEntries(size_t first, size_t last) {
|
|
||||||
mEntries.erase(mEntries.begin() + first, mEntries.begin() + last);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Contains(const SharedLibrary& searchItem) const {
|
|
||||||
return (mEntries.end() !=
|
|
||||||
std::find(mEntries.begin(), mEntries.end(), searchItem));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t GetSize() const { return mEntries.size(); }
|
|
||||||
|
|
||||||
void SortByAddress() {
|
|
||||||
std::sort(mEntries.begin(), mEntries.end(), CompareAddresses);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove duplicate entries from the vector.
|
|
||||||
//
|
|
||||||
// We purposefully don't use the operator== implementation of SharedLibrary
|
|
||||||
// because it compares all the fields including mStart, mEnd and mOffset which
|
|
||||||
// are not the same across different processes.
|
|
||||||
void DeduplicateEntries() {
|
|
||||||
static auto cmpSort = [](const SharedLibrary& a, const SharedLibrary& b) {
|
|
||||||
return std::tie(a.GetModuleName(), a.GetBreakpadId()) <
|
|
||||||
std::tie(b.GetModuleName(), b.GetBreakpadId());
|
|
||||||
};
|
|
||||||
static auto cmpEqual = [](const SharedLibrary& a, const SharedLibrary& b) {
|
|
||||||
return std::tie(a.GetModuleName(), a.GetBreakpadId()) ==
|
|
||||||
std::tie(b.GetModuleName(), b.GetBreakpadId());
|
|
||||||
};
|
|
||||||
// std::unique requires the vector to be sorted first. It can only remove
|
|
||||||
// consecutive duplicate elements.
|
|
||||||
std::sort(mEntries.begin(), mEntries.end(), cmpSort);
|
|
||||||
// Remove the duplicates since it's sorted now.
|
|
||||||
mEntries.erase(std::unique(mEntries.begin(), mEntries.end(), cmpEqual),
|
|
||||||
mEntries.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clear() { mEntries.clear(); }
|
|
||||||
|
|
||||||
size_t SizeOf() const {
|
|
||||||
size_t size = 0;
|
|
||||||
|
|
||||||
for (const auto& item : mEntries) {
|
|
||||||
size += item.SizeOf();
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<SharedLibrary> mEntries;
|
|
||||||
|
|
||||||
friend struct IPC::ParamTraits<SharedLibraryInfo>;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue
Block a user