mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Backed out 8 changesets (bug 1634785) for causing bustages in EHABIStackWalk.cpp CLOSED TREE
Backed out changeset 3ea11e90d26d (bug 1634785) Backed out changeset cb492d775d37 (bug 1634785) Backed out changeset 1c43270bdcaf (bug 1634785) Backed out changeset 42d0181c117a (bug 1634785) Backed out changeset 32b940c88cca (bug 1634785) Backed out changeset f9b6ae065ffc (bug 1634785) Backed out changeset 2abc88b08f69 (bug 1634785) Backed out changeset bf73d2f240f1 (bug 1634785)
This commit is contained in:
parent
c7dfc168f3
commit
930a787958
@ -26,7 +26,7 @@
|
||||
|
||||
#include "EHABIStackWalk.h"
|
||||
|
||||
#include "SharedLibraries.h"
|
||||
#include "BaseProfilerSharedLibraries.h"
|
||||
#include "platform.h"
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
|
@ -70,7 +70,7 @@
|
||||
#include "ProfilerBacktrace.h"
|
||||
#include "ProfileBuffer.h"
|
||||
#include "RegisteredThread.h"
|
||||
#include "SharedLibraries.h"
|
||||
#include "BaseProfilerSharedLibraries.h"
|
||||
#include "ThreadInfo.h"
|
||||
#include "VTuneProfiler.h"
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* 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 "SharedLibraries.h"
|
||||
#include "BaseProfilerSharedLibraries.h"
|
||||
|
||||
#define PATH_MAX_TOSTRING(x) #x
|
||||
#define PATH_MAX_STRING(x) PATH_MAX_TOSTRING(x)
|
||||
@ -696,7 +696,7 @@ static SharedLibrary SharedLibraryAtPath(const char* path,
|
||||
unsigned long offset = 0) {
|
||||
std::string pathStr = path;
|
||||
|
||||
size_t pos = pathStr.rfind('/');
|
||||
size_t pos = pathStr.rfind('\\');
|
||||
std::string nameStr =
|
||||
(pos != std::string::npos) ? pathStr.substr(pos + 1) : pathStr;
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* 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 "SharedLibraries.h"
|
||||
#include "BaseProfilerSharedLibraries.h"
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
@ -161,7 +161,7 @@ static void addSharedLibrary(const platform_mach_header* header,
|
||||
|
||||
std::string pathStr = path;
|
||||
|
||||
size_t pos = pathStr.rfind('/');
|
||||
size_t pos = pathStr.rfind('\\');
|
||||
std::string nameStr =
|
||||
(pos != std::string::npos) ? pathStr.substr(pos + 1) : pathStr;
|
||||
|
||||
|
@ -5,12 +5,11 @@
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "SharedLibraries.h"
|
||||
#include "BaseProfilerSharedLibraries.h"
|
||||
|
||||
#include "mozilla/glue/WindowsUnicode.h"
|
||||
#include "mozilla/NativeNt.h"
|
||||
#include "mozilla/WindowsEnumProcessModules.h"
|
||||
#include "mozilla/WindowsProcessMitigations.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
@ -55,11 +54,11 @@ static void AppendHex(T aValue, std::string& aOut, bool aWithPadding,
|
||||
}
|
||||
}
|
||||
|
||||
bool LowerCaseEqualsLiteral(char aModuleChar, char aDetouredChar) {
|
||||
return std::tolower(aModuleChar) == aDetouredChar;
|
||||
}
|
||||
|
||||
static bool IsModuleUnsafeToLoad(const std::string& aModuleName) {
|
||||
auto LowerCaseEqualsLiteral = [](char aModuleChar, char aDetouredChar) {
|
||||
return std::tolower(aModuleChar) == aDetouredChar;
|
||||
};
|
||||
|
||||
// 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
|
||||
@ -74,9 +73,8 @@ static bool IsModuleUnsafeToLoad(const std::string& aModuleName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void AddSharedLibraryFromModuleInfo(SharedLibraryInfo& sharedLibraryInfo,
|
||||
const wchar_t* aModulePath,
|
||||
mozilla::Maybe<HMODULE> aModule) {
|
||||
void SharedLibraryInfo::AddSharedLibraryFromModuleInfo(
|
||||
const wchar_t* aModulePath, mozilla::Maybe<HMODULE> aModule) {
|
||||
mozilla::UniquePtr<char[]> utf8ModulePath(
|
||||
mozilla::glue::WideToUTF8(aModulePath));
|
||||
if (!utf8ModulePath) {
|
||||
@ -94,15 +92,6 @@ void AddSharedLibraryFromModuleInfo(SharedLibraryInfo& sharedLibraryInfo,
|
||||
return;
|
||||
}
|
||||
|
||||
// If EAF+ is enabled, parsing ntdll's PE header causes a crash.
|
||||
constexpr std::string_view ntdll_dll = "ntdll.dll";
|
||||
if (mozilla::IsEafPlusEnabled() &&
|
||||
std::equal(moduleNameStr.cbegin(), moduleNameStr.cend(),
|
||||
ntdll_dll.cbegin(), ntdll_dll.cend(),
|
||||
LowerCaseEqualsLiteral)) {
|
||||
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
|
||||
@ -183,7 +172,7 @@ void AddSharedLibraryFromModuleInfo(SharedLibraryInfo& sharedLibraryInfo,
|
||||
0, // DLLs are always mapped at offset 0 on Windows
|
||||
breakpadId, codeId, moduleNameStr, modulePathStr,
|
||||
pdbNameStr, pdbPathStr, versionStr, "");
|
||||
sharedLibraryInfo.AddSharedLibrary(shlib);
|
||||
AddSharedLibrary(shlib);
|
||||
}
|
||||
|
||||
SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() {
|
||||
@ -191,8 +180,8 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() {
|
||||
|
||||
auto addSharedLibraryFromModuleInfo =
|
||||
[&sharedLibraryInfo](const wchar_t* aModulePath, HMODULE aModule) {
|
||||
AddSharedLibraryFromModuleInfo(sharedLibraryInfo, aModulePath,
|
||||
mozilla::Some(aModule));
|
||||
sharedLibraryInfo.AddSharedLibraryFromModuleInfo(
|
||||
aModulePath, mozilla::Some(aModule));
|
||||
};
|
||||
|
||||
mozilla::EnumerateProcessModules(addSharedLibraryFromModuleInfo);
|
||||
@ -201,7 +190,7 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() {
|
||||
|
||||
SharedLibraryInfo SharedLibraryInfo::GetInfoFromPath(const wchar_t* aPath) {
|
||||
SharedLibraryInfo sharedLibraryInfo;
|
||||
AddSharedLibraryFromModuleInfo(sharedLibraryInfo, aPath, mozilla::Nothing());
|
||||
sharedLibraryInfo.AddSharedLibraryFromModuleInfo(aPath, mozilla::Nothing());
|
||||
return sharedLibraryInfo;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include "AutoObjectMapper.h"
|
||||
#include "BaseProfiler.h"
|
||||
#include "SharedLibraries.h"
|
||||
#include "BaseProfilerSharedLibraries.h"
|
||||
#include "platform.h"
|
||||
#include "PlatformMacros.h"
|
||||
#include "LulMain.h"
|
||||
|
@ -75,8 +75,8 @@ GeneratedFile(
|
||||
EXPORTS += [
|
||||
"!public/ProfilingCategoryList.h",
|
||||
"public/BaseProfiler.h",
|
||||
"public/BaseProfilerSharedLibraries.h",
|
||||
"public/BaseProfilingCategory.h",
|
||||
"public/SharedLibraries.h",
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
|
177
mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h
Normal file
177
mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h
Normal file
@ -0,0 +1,177 @@
|
||||
/* -*- 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 BASE_PROFILER_SHARED_LIBRARIES_H_
|
||||
#define BASE_PROFILER_SHARED_LIBRARIES_H_
|
||||
|
||||
#include "BaseProfiler.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class SharedLibrary {
|
||||
public:
|
||||
SharedLibrary(uintptr_t aStart, uintptr_t aEnd, uintptr_t aOffset,
|
||||
const std::string& aBreakpadId, const std::string& aCodeId,
|
||||
const std::string& aModuleName, const std::string& aModulePath,
|
||||
const std::string& aDebugName, const std::string& aDebugPath,
|
||||
const std::string& 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) {}
|
||||
|
||||
SharedLibrary(const SharedLibrary& aEntry)
|
||||
: mStart(aEntry.mStart),
|
||||
mEnd(aEntry.mEnd),
|
||||
mOffset(aEntry.mOffset),
|
||||
mBreakpadId(aEntry.mBreakpadId),
|
||||
mCodeId(aEntry.mCodeId),
|
||||
mModuleName(aEntry.mModuleName),
|
||||
mModulePath(aEntry.mModulePath),
|
||||
mDebugName(aEntry.mDebugName),
|
||||
mDebugPath(aEntry.mDebugPath),
|
||||
mVersion(aEntry.mVersion),
|
||||
mArch(aEntry.mArch) {}
|
||||
|
||||
SharedLibrary& operator=(const SharedLibrary& aEntry) {
|
||||
// Gracefully handle self assignment
|
||||
if (this == &aEntry) return *this;
|
||||
|
||||
mStart = aEntry.mStart;
|
||||
mEnd = aEntry.mEnd;
|
||||
mOffset = aEntry.mOffset;
|
||||
mBreakpadId = aEntry.mBreakpadId;
|
||||
mCodeId = aEntry.mCodeId;
|
||||
mModuleName = aEntry.mModuleName;
|
||||
mModulePath = aEntry.mModulePath;
|
||||
mDebugName = aEntry.mDebugName;
|
||||
mDebugPath = aEntry.mDebugPath;
|
||||
mVersion = aEntry.mVersion;
|
||||
mArch = aEntry.mArch;
|
||||
return *this;
|
||||
}
|
||||
|
||||
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 std::string& GetBreakpadId() const { return mBreakpadId; }
|
||||
const std::string& GetCodeId() const { return mCodeId; }
|
||||
const std::string& GetModuleName() const { return mModuleName; }
|
||||
const std::string& GetModulePath() const { return mModulePath; }
|
||||
const std::string& GetDebugName() const { return mDebugName; }
|
||||
const std::string& GetDebugPath() const { return mDebugPath; }
|
||||
const std::string& GetVersion() const { return mVersion; }
|
||||
const std::string& GetArch() const { return mArch; }
|
||||
|
||||
private:
|
||||
SharedLibrary() : mStart{0}, mEnd{0}, mOffset{0} {}
|
||||
|
||||
uintptr_t mStart;
|
||||
uintptr_t mEnd;
|
||||
uintptr_t mOffset;
|
||||
std::string 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.
|
||||
std::string mCodeId;
|
||||
std::string mModuleName;
|
||||
std::string mModulePath;
|
||||
std::string mDebugName;
|
||||
std::string mDebugPath;
|
||||
std::string mVersion;
|
||||
std::string mArch;
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
SharedLibraryInfo() {}
|
||||
|
||||
void AddSharedLibrary(SharedLibrary entry) { mEntries.push_back(entry); }
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void Clear() { mEntries.clear(); }
|
||||
|
||||
private:
|
||||
#ifdef XP_WIN
|
||||
void AddSharedLibraryFromModuleInfo(const wchar_t* aModulePath,
|
||||
mozilla::Maybe<HMODULE> aModule);
|
||||
#endif
|
||||
|
||||
std::vector<SharedLibrary> mEntries;
|
||||
};
|
||||
|
||||
#endif // BASE_PROFILER_SHARED_LIBRARIES_H_
|
@ -20,7 +20,7 @@
|
||||
#include "mozilla/GfxMessageUtils.h" // For ParamTraits<GeckoProcessType>
|
||||
#include "mozilla/ResultExtensions.h"
|
||||
#include "mozilla/Try.h"
|
||||
#include "SharedLibraries.h"
|
||||
#include "shared-libraries.h"
|
||||
|
||||
static const char MAGIC[] = "permahangsavev1";
|
||||
|
||||
@ -399,8 +399,7 @@ void ReadModuleInformation(HangStack& stack) {
|
||||
}
|
||||
|
||||
if (moduleReferenced) {
|
||||
HangModule module(NS_ConvertUTF8toUTF16(info.GetDebugName().c_str()),
|
||||
nsCString(info.GetBreakpadId().c_str()));
|
||||
HangModule module(info.GetDebugName(), info.GetBreakpadId());
|
||||
stack.modules().AppendElement(module);
|
||||
}
|
||||
}
|
||||
|
@ -723,9 +723,7 @@ class GetLoadedModulesResultRunnable final : public Runnable {
|
||||
|
||||
// Module name.
|
||||
JS::Rooted<JSString*> moduleName(
|
||||
cx,
|
||||
JS_NewUCStringCopyZ(
|
||||
cx, NS_ConvertUTF8toUTF16(info.GetModuleName().c_str()).get()));
|
||||
cx, JS_NewUCStringCopyZ(cx, info.GetModuleName().get()));
|
||||
if (!moduleName || !JS_DefineProperty(cx, moduleObj, "name", moduleName,
|
||||
JSPROP_ENUMERATE)) {
|
||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||
@ -735,11 +733,9 @@ class GetLoadedModulesResultRunnable final : public Runnable {
|
||||
// Module debug name.
|
||||
JS::Rooted<JS::Value> moduleDebugName(cx);
|
||||
|
||||
if (!info.GetDebugName().empty()) {
|
||||
if (!info.GetDebugName().IsEmpty()) {
|
||||
JS::Rooted<JSString*> str_moduleDebugName(
|
||||
cx,
|
||||
JS_NewUCStringCopyZ(
|
||||
cx, NS_ConvertUTF8toUTF16(info.GetDebugName().c_str()).get()));
|
||||
cx, JS_NewUCStringCopyZ(cx, info.GetDebugName().get()));
|
||||
if (!str_moduleDebugName) {
|
||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||
return NS_OK;
|
||||
@ -758,9 +754,9 @@ class GetLoadedModulesResultRunnable final : public Runnable {
|
||||
// Module Breakpad identifier.
|
||||
JS::Rooted<JS::Value> id(cx);
|
||||
|
||||
if (!info.GetBreakpadId().empty()) {
|
||||
if (!info.GetBreakpadId().IsEmpty()) {
|
||||
JS::Rooted<JSString*> str_id(
|
||||
cx, JS_NewStringCopyZ(cx, info.GetBreakpadId().c_str()));
|
||||
cx, JS_NewStringCopyZ(cx, info.GetBreakpadId().get()));
|
||||
if (!str_id) {
|
||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||
return NS_OK;
|
||||
@ -778,9 +774,9 @@ class GetLoadedModulesResultRunnable final : public Runnable {
|
||||
// Module version.
|
||||
JS::Rooted<JS::Value> version(cx);
|
||||
|
||||
if (!info.GetVersion().empty()) {
|
||||
if (!info.GetVersion().IsEmpty()) {
|
||||
JS::Rooted<JSString*> v(
|
||||
cx, JS_NewStringCopyZ(cx, info.GetVersion().c_str()));
|
||||
cx, JS_NewStringCopyZ(cx, info.GetVersion().BeginReading()));
|
||||
if (!v) {
|
||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||
return NS_OK;
|
||||
@ -798,8 +794,7 @@ class GetLoadedModulesResultRunnable final : public Runnable {
|
||||
|
||||
# if defined(XP_WIN)
|
||||
// Cert Subject.
|
||||
if (auto subject = mCertSubjects.Lookup(
|
||||
NS_ConvertUTF8toUTF16(info.GetModulePath().c_str()))) {
|
||||
if (auto subject = mCertSubjects.Lookup(info.GetModulePath())) {
|
||||
JS::Rooted<JSString*> jsOrg(cx, ToJSString(cx, *subject));
|
||||
if (!jsOrg) {
|
||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||
@ -839,12 +834,10 @@ class GetLoadedModulesResultRunnable final : public Runnable {
|
||||
for (unsigned int i = 0, n = mRawModules.GetSize(); i != n; i++) {
|
||||
const SharedLibrary& info = mRawModules.GetEntry(i);
|
||||
|
||||
auto orgName = dllSvc->GetBinaryOrgName(
|
||||
NS_ConvertUTF8toUTF16(info.GetModulePath().c_str()).get());
|
||||
auto orgName = dllSvc->GetBinaryOrgName(info.GetModulePath().get());
|
||||
if (orgName) {
|
||||
mCertSubjects.InsertOrUpdate(
|
||||
NS_ConvertUTF8toUTF16(info.GetModulePath().c_str()),
|
||||
nsDependentString(orgName.get()));
|
||||
mCertSubjects.InsertOrUpdate(info.GetModulePath(),
|
||||
nsDependentString(orgName.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,9 +141,8 @@ static ProcessedStack GetStackAndModulesInternal(
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
for (unsigned i = 0, n = rawModules.GetSize(); i != n; ++i) {
|
||||
const SharedLibrary& info = rawModules.GetEntry(i);
|
||||
mozilla::Telemetry::ProcessedStack::Module module = {
|
||||
NS_ConvertUTF8toUTF16(info.GetDebugName().c_str()),
|
||||
nsCString(info.GetBreakpadId().c_str())};
|
||||
mozilla::Telemetry::ProcessedStack::Module module = {info.GetDebugName(),
|
||||
info.GetBreakpadId()};
|
||||
Ret.AddModule(module);
|
||||
}
|
||||
#endif
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "mozilla/ipc/MessageChannel.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "SharedLibraries.h"
|
||||
#include "shared-libraries.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace Telemetry {
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "nsITelemetry.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "SharedLibraries.h"
|
||||
#include "shared-libraries.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace Telemetry {
|
||||
@ -173,9 +173,9 @@ static bool SerializeModule(JSContext* aCx,
|
||||
if (aModule->mResolvedDosName->GetPath(path) == NS_OK) {
|
||||
SharedLibraryInfo info = SharedLibraryInfo::GetInfoFromPath(path.Data());
|
||||
if (info.GetSize() > 0) {
|
||||
nsString breakpadId =
|
||||
NS_ConvertUTF8toUTF16(info.GetEntry(0).GetBreakpadId());
|
||||
if (!AddLengthLimitedStringProp(aCx, obj, "debugID", breakpadId)) {
|
||||
nsCString breakpadId = info.GetEntry(0).GetBreakpadId();
|
||||
if (!AddLengthLimitedStringProp(aCx, obj, "debugID",
|
||||
NS_ConvertASCIItoUTF16(breakpadId))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
#include "EHABIStackWalk.h"
|
||||
|
||||
#include "SharedLibraries.h"
|
||||
#include "shared-libraries.h"
|
||||
#include "platform.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
|
||||
// around by magic number checks in the EHTable constructor.
|
||||
EHTable tab(reinterpret_cast<const void*>(lib.GetStart()),
|
||||
lib.GetEnd() - lib.GetStart(), lib.DebugPath());
|
||||
lib.GetEnd() - lib.GetStart(), lib.GetNativeDebugPath());
|
||||
if (tab.isValid()) tables.push_back(tab);
|
||||
}
|
||||
space = new EHAddrSpace(tables);
|
||||
|
@ -40,22 +40,6 @@ void mozilla::ProfileGenerationAdditionalInformation::ToJSValue(
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template <>
|
||||
struct ParamTraits<SharedLibrary> {
|
||||
typedef SharedLibrary paramType;
|
||||
|
||||
static void Write(MessageWriter* aWriter, const paramType& aParam);
|
||||
static bool Read(MessageReader* aReader, paramType* aResult);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<SharedLibraryInfo> {
|
||||
typedef SharedLibraryInfo paramType;
|
||||
|
||||
static void Write(MessageWriter* aWriter, const paramType& aParam);
|
||||
static bool Read(MessageReader* aReader, paramType* aResult);
|
||||
};
|
||||
|
||||
void IPC::ParamTraits<SharedLibrary>::Write(MessageWriter* aWriter,
|
||||
const paramType& aParam) {
|
||||
WriteParam(aWriter, aParam.mStart);
|
||||
|
@ -53,7 +53,7 @@
|
||||
#include "nsDebug.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsXPCOM.h"
|
||||
#include "SharedLibraries.h"
|
||||
#include "shared-libraries.h"
|
||||
#include "VTuneProfiler.h"
|
||||
#include "ETWTools.h"
|
||||
|
||||
@ -3053,10 +3053,12 @@ static void AddSharedLibraryInfoToStream(JSONWriter& aWriter,
|
||||
aWriter.IntProperty("start", SafeJSInteger(aLib.GetStart()));
|
||||
aWriter.IntProperty("end", SafeJSInteger(aLib.GetEnd()));
|
||||
aWriter.IntProperty("offset", SafeJSInteger(aLib.GetOffset()));
|
||||
aWriter.StringProperty("name", aLib.GetModuleName());
|
||||
aWriter.StringProperty("path", aLib.GetModulePath());
|
||||
aWriter.StringProperty("debugName", aLib.GetDebugName());
|
||||
aWriter.StringProperty("debugPath", aLib.GetDebugPath());
|
||||
aWriter.StringProperty("name", NS_ConvertUTF16toUTF8(aLib.GetModuleName()));
|
||||
aWriter.StringProperty("path", NS_ConvertUTF16toUTF8(aLib.GetModulePath()));
|
||||
aWriter.StringProperty("debugName",
|
||||
NS_ConvertUTF16toUTF8(aLib.GetDebugName()));
|
||||
aWriter.StringProperty("debugPath",
|
||||
NS_ConvertUTF16toUTF8(aLib.GetDebugPath()));
|
||||
aWriter.StringProperty("breakpadId", aLib.GetBreakpadId());
|
||||
aWriter.StringProperty("codeId", aLib.GetCodeId());
|
||||
aWriter.StringProperty("arch", aLib.GetArch());
|
||||
|
@ -44,7 +44,7 @@
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "nsString.h"
|
||||
#include "SharedLibraries.h"
|
||||
#include "shared-libraries.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
280
tools/profiler/core/shared-libraries-linux.cc
Normal file
280
tools/profiler/core/shared-libraries-linux.cc
Normal file
@ -0,0 +1,280 @@
|
||||
/* -*- 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 */ }
|
211
tools/profiler/core/shared-libraries-macos.cc
Normal file
211
tools/profiler/core/shared-libraries-macos.cc
Normal file
@ -0,0 +1,211 @@
|
||||
/* -*- 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;
|
||||
}
|
145
tools/profiler/core/shared-libraries-win32.cc
Normal file
145
tools/profiler/core/shared-libraries-win32.cc
Normal file
@ -0,0 +1,145 @@
|
||||
/* -*- 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 "nsThreadUtils.h"
|
||||
#include "platform.h"
|
||||
#include "SharedLibraries.h"
|
||||
#include "shared-libraries.h"
|
||||
#include "zlib.h"
|
||||
|
||||
#ifndef ANDROID
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "platform.h"
|
||||
#include "PlatformMacros.h"
|
||||
#include "LulMain.h"
|
||||
#include "SharedLibraries.h"
|
||||
#include "shared-libraries.h"
|
||||
#include "AutoObjectMapper.h"
|
||||
|
||||
// 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++) {
|
||||
const SharedLibrary& lib = info.GetEntry(i);
|
||||
|
||||
std::string nativePath = lib.GetDebugPath();
|
||||
std::string nativePath = lib.GetNativeDebugPath();
|
||||
|
||||
// We can use the standard POSIX-based mapper.
|
||||
AutoObjectMapperPOSIX mapper(aLUL->mLog);
|
||||
@ -44,7 +44,7 @@ void read_procmaps(lul::LUL* aLUL) {
|
||||
if (ok && image && size > 0) {
|
||||
aLUL->NotifyAfterMap(lib.GetStart(), lib.GetEnd() - lib.GetStart(),
|
||||
nativePath.c_str(), image);
|
||||
} else if (!ok && lib.GetDebugName().empty()) {
|
||||
} else if (!ok && lib.GetDebugName().IsEmpty()) {
|
||||
// The object has no name and (as a consequence) the mapper failed to map
|
||||
// it. This happens on Linux, where GetInfoForSelf() produces such a
|
||||
// mapping for the VDSO. This is a problem on x86-{linux,android} because
|
||||
|
@ -66,6 +66,10 @@ if CONFIG["MOZ_GECKO_PROFILER"]:
|
||||
"lul/LulMain.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"]:
|
||||
SOURCES += [
|
||||
"/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc",
|
||||
@ -90,6 +94,9 @@ if CONFIG["MOZ_GECKO_PROFILER"]:
|
||||
"core/EHABIStackWalk.cpp",
|
||||
]
|
||||
elif CONFIG["OS_TARGET"] == "Darwin":
|
||||
UNIFIED_SOURCES += [
|
||||
"core/shared-libraries-macos.cc",
|
||||
]
|
||||
if CONFIG["TARGET_CPU"] == "aarch64":
|
||||
UNIFIED_SOURCES += [
|
||||
"core/PowerCounters-mac-arm64.cpp",
|
||||
@ -108,6 +115,7 @@ if CONFIG["MOZ_GECKO_PROFILER"]:
|
||||
}
|
||||
SOURCES += [
|
||||
"core/ProfilerCPUFreq-win.cpp",
|
||||
"core/shared-libraries-win32.cc",
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
@ -172,6 +180,7 @@ EXPORTS += [
|
||||
"public/ProfilerParent.h",
|
||||
"public/ProfilerRustBindings.h",
|
||||
"public/ProfilerStackWalk.h",
|
||||
"public/shared-libraries.h",
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
|
@ -14,7 +14,7 @@
|
||||
#ifndef ProfileAdditionalInformation_h
|
||||
#define ProfileAdditionalInformation_h
|
||||
|
||||
#include "SharedLibraries.h"
|
||||
#include "shared-libraries.h"
|
||||
#include "js/Value.h"
|
||||
#include "nsString.h"
|
||||
|
||||
|
@ -7,16 +7,19 @@
|
||||
#ifndef SHARED_LIBRARIES_H_
|
||||
#define SHARED_LIBRARIES_H_
|
||||
|
||||
#include "BaseProfiler.h"
|
||||
#include "nsNativeCharsetUtils.h"
|
||||
#include "nsString.h"
|
||||
#include <nsID.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
namespace IPC {
|
||||
class MessageReader;
|
||||
class MessageWriter;
|
||||
template <typename T>
|
||||
struct ParamTraits;
|
||||
} // namespace IPC
|
||||
@ -24,10 +27,10 @@ struct ParamTraits;
|
||||
class SharedLibrary {
|
||||
public:
|
||||
SharedLibrary(uintptr_t aStart, uintptr_t aEnd, uintptr_t aOffset,
|
||||
const std::string& aBreakpadId, const std::string& aCodeId,
|
||||
const std::string& aModuleName, const std::string& aModulePath,
|
||||
const std::string& aDebugName, const std::string& aDebugPath,
|
||||
const std::string& aVersion, const char* aArch)
|
||||
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),
|
||||
@ -53,19 +56,26 @@ class SharedLibrary {
|
||||
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 std::string& GetCodeId() const { return mCodeId; }
|
||||
const std::string& GetModuleName() const { return mModuleName; }
|
||||
const std::string& GetModulePath() const { return mModulePath; }
|
||||
const std::string& GetDebugName() const { return mDebugName; }
|
||||
const std::string& GetDebugPath() const { return mDebugPath; }
|
||||
const std::string& GetVersion() const { return mVersion; }
|
||||
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();
|
||||
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} {}
|
||||
@ -74,7 +84,7 @@ class SharedLibrary {
|
||||
uintptr_t mStart;
|
||||
uintptr_t mEnd;
|
||||
uintptr_t mOffset;
|
||||
std::string mBreakpadId;
|
||||
nsCString mBreakpadId;
|
||||
// A string carrying an identifier for a binary.
|
||||
//
|
||||
// All platforms have different formats:
|
||||
@ -85,12 +95,12 @@ class SharedLibrary {
|
||||
// breakpad ID.
|
||||
// - Linux/Android: The code ID for a Linux ELF file.
|
||||
// It's the complete build ID, as hex string.
|
||||
std::string mCodeId;
|
||||
std::string mModuleName;
|
||||
std::string mModulePath;
|
||||
std::string mDebugName;
|
||||
std::string mDebugPath;
|
||||
std::string mVersion;
|
||||
nsCString mCodeId;
|
||||
nsString mModuleName;
|
||||
nsString mModulePath;
|
||||
nsString mDebugName;
|
||||
nsString mDebugPath;
|
||||
nsCString mVersion;
|
||||
std::string mArch;
|
||||
|
||||
friend struct IPC::ParamTraits<SharedLibrary>;
|
||||
@ -104,12 +114,12 @@ static bool CompareAddresses(const SharedLibrary& first,
|
||||
class SharedLibraryInfo {
|
||||
public:
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
MFBT_API static SharedLibraryInfo GetInfoForSelf();
|
||||
static SharedLibraryInfo GetInfoForSelf();
|
||||
# ifdef XP_WIN
|
||||
MFBT_API static SharedLibraryInfo GetInfoFromPath(const wchar_t* aPath);
|
||||
static SharedLibraryInfo GetInfoFromPath(const wchar_t* aPath);
|
||||
# endif
|
||||
|
||||
MFBT_API static void Initialize();
|
||||
static void Initialize();
|
||||
#else
|
||||
static SharedLibraryInfo GetInfoForSelf() { return SharedLibraryInfo(); }
|
||||
# ifdef XP_WIN
|
||||
@ -189,4 +199,22 @@ class SharedLibraryInfo {
|
||||
friend struct IPC::ParamTraits<SharedLibraryInfo>;
|
||||
};
|
||||
|
||||
#endif // SHARED_LIBRARIES_H_
|
||||
namespace IPC {
|
||||
template <>
|
||||
struct ParamTraits<SharedLibrary> {
|
||||
typedef SharedLibrary paramType;
|
||||
|
||||
static void Write(MessageWriter* aWriter, const paramType& aParam);
|
||||
static bool Read(MessageReader* aReader, paramType* aResult);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<SharedLibraryInfo> {
|
||||
typedef SharedLibraryInfo paramType;
|
||||
|
||||
static void Write(MessageWriter* aWriter, const paramType& aParam);
|
||||
static bool Read(MessageReader* aReader, paramType* aResult);
|
||||
};
|
||||
} // namespace IPC
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user