Remove base/profiler, base/debug and base/third_party/symbolize
Change-Id: Ia46b0aea972a4931f8e45c8ee36fe1d784de47d3
Reviewed-on: https://gn-review.googlesource.com/1541
Commit-Queue: Scott Graham <scottmg@chromium.org>
Reviewed-by: Brett Wilson <brettw@chromium.org>
diff --git a/base/debug/OWNERS b/base/debug/OWNERS
deleted file mode 100644
index 6150257..0000000
--- a/base/debug/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# For activity tracking:
-per-file activity_*=bcwhite@chromium.org
diff --git a/base/debug/activity_analyzer.cc b/base/debug/activity_analyzer.cc
deleted file mode 100644
index d787829..0000000
--- a/base/debug/activity_analyzer.cc
+++ /dev/null
@@ -1,412 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/activity_analyzer.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "base/files/file.h"
-#include "base/files/file_path.h"
-#include "base/files/memory_mapped_file.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-
-namespace base {
-namespace debug {
-
-namespace {
-// An empty snapshot that can be returned when there otherwise is none.
-LazyInstance<ActivityUserData::Snapshot>::Leaky g_empty_user_data_snapshot;
-
-// DO NOT CHANGE VALUES. This is logged persistently in a histogram.
-enum AnalyzerCreationError {
- kInvalidMemoryMappedFile,
- kPmaBadFile,
- kPmaUninitialized,
- kPmaDeleted,
- kPmaCorrupt,
- kAnalyzerCreationErrorMax // Keep this last.
-};
-
-void LogAnalyzerCreationError(AnalyzerCreationError error) {
- UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Collect.AnalyzerCreationError",
- error, kAnalyzerCreationErrorMax);
-}
-
-} // namespace
-
-ThreadActivityAnalyzer::Snapshot::Snapshot() = default;
-ThreadActivityAnalyzer::Snapshot::~Snapshot() = default;
-
-ThreadActivityAnalyzer::ThreadActivityAnalyzer(
- const ThreadActivityTracker& tracker)
- : activity_snapshot_valid_(tracker.CreateSnapshot(&activity_snapshot_)) {}
-
-ThreadActivityAnalyzer::ThreadActivityAnalyzer(void* base, size_t size)
- : ThreadActivityAnalyzer(ThreadActivityTracker(base, size)) {}
-
-ThreadActivityAnalyzer::ThreadActivityAnalyzer(
- PersistentMemoryAllocator* allocator,
- PersistentMemoryAllocator::Reference reference)
- : ThreadActivityAnalyzer(allocator->GetAsArray<char>(
- reference,
- GlobalActivityTracker::kTypeIdActivityTracker,
- PersistentMemoryAllocator::kSizeAny),
- allocator->GetAllocSize(reference)) {}
-
-ThreadActivityAnalyzer::~ThreadActivityAnalyzer() = default;
-
-void ThreadActivityAnalyzer::AddGlobalInformation(
- GlobalActivityAnalyzer* global) {
- if (!IsValid())
- return;
-
- // User-data is held at the global scope even though it's referenced at the
- // thread scope.
- activity_snapshot_.user_data_stack.clear();
- for (auto& activity : activity_snapshot_.activity_stack) {
- // The global GetUserDataSnapshot will return an empty snapshot if the ref
- // or id is not valid.
- activity_snapshot_.user_data_stack.push_back(global->GetUserDataSnapshot(
- activity_snapshot_.process_id, activity.user_data_ref,
- activity.user_data_id));
- }
-}
-
-GlobalActivityAnalyzer::GlobalActivityAnalyzer(
- std::unique_ptr<PersistentMemoryAllocator> allocator)
- : allocator_(std::move(allocator)),
- analysis_stamp_(0LL),
- allocator_iterator_(allocator_.get()) {
- DCHECK(allocator_);
-}
-
-GlobalActivityAnalyzer::~GlobalActivityAnalyzer() = default;
-
-// static
-std::unique_ptr<GlobalActivityAnalyzer>
-GlobalActivityAnalyzer::CreateWithAllocator(
- std::unique_ptr<PersistentMemoryAllocator> allocator) {
- if (allocator->GetMemoryState() ==
- PersistentMemoryAllocator::MEMORY_UNINITIALIZED) {
- LogAnalyzerCreationError(kPmaUninitialized);
- return nullptr;
- }
- if (allocator->GetMemoryState() ==
- PersistentMemoryAllocator::MEMORY_DELETED) {
- LogAnalyzerCreationError(kPmaDeleted);
- return nullptr;
- }
- if (allocator->IsCorrupt()) {
- LogAnalyzerCreationError(kPmaCorrupt);
- return nullptr;
- }
-
- return WrapUnique(new GlobalActivityAnalyzer(std::move(allocator)));
-}
-
-#if !defined(OS_NACL)
-// static
-std::unique_ptr<GlobalActivityAnalyzer> GlobalActivityAnalyzer::CreateWithFile(
- const FilePath& file_path) {
- // Map the file read-write so it can guarantee consistency between
- // the analyzer and any trackers that my still be active.
- std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
- mmfile->Initialize(file_path, MemoryMappedFile::READ_WRITE);
- if (!mmfile->IsValid()) {
- LogAnalyzerCreationError(kInvalidMemoryMappedFile);
- return nullptr;
- }
-
- if (!FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true)) {
- LogAnalyzerCreationError(kPmaBadFile);
- return nullptr;
- }
-
- return CreateWithAllocator(std::make_unique<FilePersistentMemoryAllocator>(
- std::move(mmfile), 0, 0, StringPiece(), /*readonly=*/true));
-}
-#endif // !defined(OS_NACL)
-
-// static
-std::unique_ptr<GlobalActivityAnalyzer>
-GlobalActivityAnalyzer::CreateWithSharedMemory(
- std::unique_ptr<SharedMemory> shm) {
- if (shm->mapped_size() == 0 ||
- !SharedPersistentMemoryAllocator::IsSharedMemoryAcceptable(*shm)) {
- return nullptr;
- }
- return CreateWithAllocator(std::make_unique<SharedPersistentMemoryAllocator>(
- std::move(shm), 0, StringPiece(), /*readonly=*/true));
-}
-
-// static
-std::unique_ptr<GlobalActivityAnalyzer>
-GlobalActivityAnalyzer::CreateWithSharedMemoryHandle(
- const SharedMemoryHandle& handle,
- size_t size) {
- std::unique_ptr<SharedMemory> shm(
- new SharedMemory(handle, /*readonly=*/true));
- if (!shm->Map(size))
- return nullptr;
- return CreateWithSharedMemory(std::move(shm));
-}
-
-int64_t GlobalActivityAnalyzer::GetFirstProcess() {
- PrepareAllAnalyzers();
- return GetNextProcess();
-}
-
-int64_t GlobalActivityAnalyzer::GetNextProcess() {
- if (process_ids_.empty())
- return 0;
- int64_t pid = process_ids_.back();
- process_ids_.pop_back();
- return pid;
-}
-
-ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetFirstAnalyzer(int64_t pid) {
- analyzers_iterator_ = analyzers_.begin();
- analyzers_iterator_pid_ = pid;
- if (analyzers_iterator_ == analyzers_.end())
- return nullptr;
- int64_t create_stamp;
- if (analyzers_iterator_->second->GetProcessId(&create_stamp) == pid &&
- create_stamp <= analysis_stamp_) {
- return analyzers_iterator_->second.get();
- }
- return GetNextAnalyzer();
-}
-
-ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetNextAnalyzer() {
- DCHECK(analyzers_iterator_ != analyzers_.end());
- int64_t create_stamp;
- do {
- ++analyzers_iterator_;
- if (analyzers_iterator_ == analyzers_.end())
- return nullptr;
- } while (analyzers_iterator_->second->GetProcessId(&create_stamp) !=
- analyzers_iterator_pid_ ||
- create_stamp > analysis_stamp_);
- return analyzers_iterator_->second.get();
-}
-
-ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetAnalyzerForThread(
- const ThreadKey& key) {
- auto found = analyzers_.find(key);
- if (found == analyzers_.end())
- return nullptr;
- return found->second.get();
-}
-
-ActivityUserData::Snapshot GlobalActivityAnalyzer::GetUserDataSnapshot(
- int64_t pid,
- uint32_t ref,
- uint32_t id) {
- ActivityUserData::Snapshot snapshot;
-
- void* memory = allocator_->GetAsArray<char>(
- ref, GlobalActivityTracker::kTypeIdUserDataRecord,
- PersistentMemoryAllocator::kSizeAny);
- if (memory) {
- size_t size = allocator_->GetAllocSize(ref);
- const ActivityUserData user_data(memory, size);
- user_data.CreateSnapshot(&snapshot);
- int64_t process_id;
- int64_t create_stamp;
- if (!ActivityUserData::GetOwningProcessId(memory, &process_id,
- &create_stamp) ||
- process_id != pid || user_data.id() != id) {
- // This allocation has been overwritten since it was created. Return an
- // empty snapshot because whatever was captured is incorrect.
- snapshot.clear();
- }
- }
-
- return snapshot;
-}
-
-const ActivityUserData::Snapshot&
-GlobalActivityAnalyzer::GetProcessDataSnapshot(int64_t pid) {
- auto iter = process_data_.find(pid);
- if (iter == process_data_.end())
- return g_empty_user_data_snapshot.Get();
- if (iter->second.create_stamp > analysis_stamp_)
- return g_empty_user_data_snapshot.Get();
- DCHECK_EQ(pid, iter->second.process_id);
- return iter->second.data;
-}
-
-std::vector<std::string> GlobalActivityAnalyzer::GetLogMessages() {
- std::vector<std::string> messages;
- PersistentMemoryAllocator::Reference ref;
-
- PersistentMemoryAllocator::Iterator iter(allocator_.get());
- while ((ref = iter.GetNextOfType(
- GlobalActivityTracker::kTypeIdGlobalLogMessage)) != 0) {
- const char* message = allocator_->GetAsArray<char>(
- ref, GlobalActivityTracker::kTypeIdGlobalLogMessage,
- PersistentMemoryAllocator::kSizeAny);
- if (message)
- messages.push_back(message);
- }
-
- return messages;
-}
-
-std::vector<GlobalActivityTracker::ModuleInfo>
-GlobalActivityAnalyzer::GetModules(int64_t pid) {
- std::vector<GlobalActivityTracker::ModuleInfo> modules;
-
- PersistentMemoryAllocator::Iterator iter(allocator_.get());
- const GlobalActivityTracker::ModuleInfoRecord* record;
- while (
- (record =
- iter.GetNextOfObject<GlobalActivityTracker::ModuleInfoRecord>()) !=
- nullptr) {
- int64_t process_id;
- int64_t create_stamp;
- if (!OwningProcess::GetOwningProcessId(&record->owner, &process_id,
- &create_stamp) ||
- pid != process_id || create_stamp > analysis_stamp_) {
- continue;
- }
- GlobalActivityTracker::ModuleInfo info;
- if (record->DecodeTo(&info, allocator_->GetAllocSize(
- allocator_->GetAsReference(record)))) {
- modules.push_back(std::move(info));
- }
- }
-
- return modules;
-}
-
-GlobalActivityAnalyzer::ProgramLocation
-GlobalActivityAnalyzer::GetProgramLocationFromAddress(uint64_t address) {
- // TODO(bcwhite): Implement this.
- return { 0, 0 };
-}
-
-bool GlobalActivityAnalyzer::IsDataComplete() const {
- DCHECK(allocator_);
- return !allocator_->IsFull();
-}
-
-GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot() = default;
-GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
- const UserDataSnapshot& rhs) = default;
-GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
- UserDataSnapshot&& rhs) = default;
-GlobalActivityAnalyzer::UserDataSnapshot::~UserDataSnapshot() = default;
-
-void GlobalActivityAnalyzer::PrepareAllAnalyzers() {
- // Record the time when analysis started.
- analysis_stamp_ = base::Time::Now().ToInternalValue();
-
- // Fetch all the records. This will retrieve only ones created since the
- // last run since the PMA iterator will continue from where it left off.
- uint32_t type;
- PersistentMemoryAllocator::Reference ref;
- while ((ref = allocator_iterator_.GetNext(&type)) != 0) {
- switch (type) {
- case GlobalActivityTracker::kTypeIdActivityTracker:
- case GlobalActivityTracker::kTypeIdActivityTrackerFree:
- case GlobalActivityTracker::kTypeIdProcessDataRecord:
- case GlobalActivityTracker::kTypeIdProcessDataRecordFree:
- case PersistentMemoryAllocator::kTypeIdTransitioning:
- // Active, free, or transitioning: add it to the list of references
- // for later analysis.
- memory_references_.insert(ref);
- break;
- }
- }
-
- // Clear out any old information.
- analyzers_.clear();
- process_data_.clear();
- process_ids_.clear();
- std::set<int64_t> seen_pids;
-
- // Go through all the known references and create objects for them with
- // snapshots of the current state.
- for (PersistentMemoryAllocator::Reference memory_ref : memory_references_) {
- // Get the actual data segment for the tracker. Any type will do since it
- // is checked below.
- void* const base = allocator_->GetAsArray<char>(
- memory_ref, PersistentMemoryAllocator::kTypeIdAny,
- PersistentMemoryAllocator::kSizeAny);
- const size_t size = allocator_->GetAllocSize(memory_ref);
- if (!base)
- continue;
-
- switch (allocator_->GetType(memory_ref)) {
- case GlobalActivityTracker::kTypeIdActivityTracker: {
- // Create the analyzer on the data. This will capture a snapshot of the
- // tracker state. This can fail if the tracker is somehow corrupted or
- // is in the process of shutting down.
- std::unique_ptr<ThreadActivityAnalyzer> analyzer(
- new ThreadActivityAnalyzer(base, size));
- if (!analyzer->IsValid())
- continue;
- analyzer->AddGlobalInformation(this);
-
- // Track PIDs.
- int64_t pid = analyzer->GetProcessId();
- if (seen_pids.find(pid) == seen_pids.end()) {
- process_ids_.push_back(pid);
- seen_pids.insert(pid);
- }
-
- // Add this analyzer to the map of known ones, indexed by a unique
- // thread
- // identifier.
- DCHECK(!base::ContainsKey(analyzers_, analyzer->GetThreadKey()));
- analyzer->allocator_reference_ = ref;
- analyzers_[analyzer->GetThreadKey()] = std::move(analyzer);
- } break;
-
- case GlobalActivityTracker::kTypeIdProcessDataRecord: {
- // Get the PID associated with this data record.
- int64_t process_id;
- int64_t create_stamp;
- ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
- DCHECK(!base::ContainsKey(process_data_, process_id));
-
- // Create a snapshot of the data. This can fail if the data is somehow
- // corrupted or the process shutdown and the memory being released.
- UserDataSnapshot& snapshot = process_data_[process_id];
- snapshot.process_id = process_id;
- snapshot.create_stamp = create_stamp;
- const ActivityUserData process_data(base, size);
- if (!process_data.CreateSnapshot(&snapshot.data))
- break;
-
- // Check that nothing changed. If it did, forget what was recorded.
- ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
- if (process_id != snapshot.process_id ||
- create_stamp != snapshot.create_stamp) {
- process_data_.erase(process_id);
- break;
- }
-
- // Track PIDs.
- if (seen_pids.find(process_id) == seen_pids.end()) {
- process_ids_.push_back(process_id);
- seen_pids.insert(process_id);
- }
- } break;
- }
- }
-
- // Reverse the list of PIDs so that they get popped in the order found.
- std::reverse(process_ids_.begin(), process_ids_.end());
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/activity_analyzer.h b/base/debug/activity_analyzer.h
deleted file mode 100644
index 9add85a..0000000
--- a/base/debug/activity_analyzer.h
+++ /dev/null
@@ -1,262 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_DEBUG_ACTIVITY_ANALYZER_H_
-#define BASE_DEBUG_ACTIVITY_ANALYZER_H_
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/base_export.h"
-#include "base/debug/activity_tracker.h"
-
-namespace base {
-namespace debug {
-
-class GlobalActivityAnalyzer;
-
-// This class provides analysis of data captured from a ThreadActivityTracker.
-// When created, it takes a snapshot of the data held by the tracker and
-// makes that information available to other code.
-class BASE_EXPORT ThreadActivityAnalyzer {
- public:
- struct BASE_EXPORT Snapshot : ThreadActivityTracker::Snapshot {
- Snapshot();
- ~Snapshot();
-
- // The user-data snapshot for an activity, matching the |activity_stack|
- // of ThreadActivityTracker::Snapshot, if any.
- std::vector<ActivityUserData::Snapshot> user_data_stack;
- };
-
- // This class provides keys that uniquely identify a thread, even across
- // multiple processes.
- class ThreadKey {
- public:
- ThreadKey(int64_t pid, int64_t tid) : pid_(pid), tid_(tid) {}
-
- bool operator<(const ThreadKey& rhs) const {
- if (pid_ != rhs.pid_)
- return pid_ < rhs.pid_;
- return tid_ < rhs.tid_;
- }
-
- bool operator==(const ThreadKey& rhs) const {
- return (pid_ == rhs.pid_ && tid_ == rhs.tid_);
- }
-
- private:
- int64_t pid_;
- int64_t tid_;
- };
-
- // Creates an analyzer for an existing activity |tracker|. A snapshot is taken
- // immediately and the tracker is not referenced again.
- explicit ThreadActivityAnalyzer(const ThreadActivityTracker& tracker);
-
- // Creates an analyzer for a block of memory currently or previously in-use
- // by an activity-tracker. A snapshot is taken immediately and the memory
- // is not referenced again.
- ThreadActivityAnalyzer(void* base, size_t size);
-
- // Creates an analyzer for a block of memory held within a persistent-memory
- // |allocator| at the given |reference|. A snapshot is taken immediately and
- // the memory is not referenced again.
- ThreadActivityAnalyzer(PersistentMemoryAllocator* allocator,
- PersistentMemoryAllocator::Reference reference);
-
- ~ThreadActivityAnalyzer();
-
- // Adds information from the global analyzer.
- void AddGlobalInformation(GlobalActivityAnalyzer* global);
-
- // Returns true iff the contained data is valid. Results from all other
- // methods are undefined if this returns false.
- bool IsValid() { return activity_snapshot_valid_; }
-
- // Gets the process id and its creation stamp.
- int64_t GetProcessId(int64_t* out_stamp = nullptr) {
- if (out_stamp)
- *out_stamp = activity_snapshot_.create_stamp;
- return activity_snapshot_.process_id;
- }
-
- // Gets the name of the thread.
- const std::string& GetThreadName() {
- return activity_snapshot_.thread_name;
- }
-
- // Gets the TheadKey for this thread.
- ThreadKey GetThreadKey() {
- return ThreadKey(activity_snapshot_.process_id,
- activity_snapshot_.thread_id);
- }
-
- const Snapshot& activity_snapshot() { return activity_snapshot_; }
-
- private:
- friend class GlobalActivityAnalyzer;
-
- // The snapshot of the activity tracker taken at the moment of construction.
- Snapshot activity_snapshot_;
-
- // Flag indicating if the snapshot data is valid.
- bool activity_snapshot_valid_;
-
- // A reference into a persistent memory allocator, used by the global
- // analyzer to know where this tracker came from.
- PersistentMemoryAllocator::Reference allocator_reference_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(ThreadActivityAnalyzer);
-};
-
-
-// This class manages analyzers for all known processes and threads as stored
-// in a persistent memory allocator. It supports retrieval of them through
-// iteration and directly using a ThreadKey, which allows for cross-references
-// to be resolved.
-// Note that though atomic snapshots are used and everything has its snapshot
-// taken at the same time, the multi-snapshot itself is not atomic and thus may
-// show small inconsistencies between threads if attempted on a live system.
-class BASE_EXPORT GlobalActivityAnalyzer {
- public:
- struct ProgramLocation {
- int module;
- uintptr_t offset;
- };
-
- using ThreadKey = ThreadActivityAnalyzer::ThreadKey;
-
- // Creates a global analyzer from a persistent memory allocator.
- explicit GlobalActivityAnalyzer(
- std::unique_ptr<PersistentMemoryAllocator> allocator);
-
- ~GlobalActivityAnalyzer();
-
- // Creates a global analyzer using a given persistent-memory |allocator|.
- static std::unique_ptr<GlobalActivityAnalyzer> CreateWithAllocator(
- std::unique_ptr<PersistentMemoryAllocator> allocator);
-
-#if !defined(OS_NACL)
- // Creates a global analyzer using the contents of a file given in
- // |file_path|.
- static std::unique_ptr<GlobalActivityAnalyzer> CreateWithFile(
- const FilePath& file_path);
-#endif // !defined(OS_NACL)
-
- // Like above but accesses an allocator in a mapped shared-memory segment.
- static std::unique_ptr<GlobalActivityAnalyzer> CreateWithSharedMemory(
- std::unique_ptr<SharedMemory> shm);
-
- // Like above but takes a handle to an existing shared memory segment and
- // maps it before creating the tracker.
- static std::unique_ptr<GlobalActivityAnalyzer> CreateWithSharedMemoryHandle(
- const SharedMemoryHandle& handle,
- size_t size);
-
- // Iterates over all known valid processes and returns their PIDs or zero
- // if there are no more. Calls to GetFirstProcess() will perform a global
- // snapshot in order to provide a relatively consistent state across the
- // future calls to GetNextProcess() and GetFirst/NextAnalyzer(). PIDs are
- // returned in the order they're found meaning that a first-launched
- // controlling process will be found first. Note, however, that space
- // freed by an exiting process may be re-used by a later process.
- int64_t GetFirstProcess();
- int64_t GetNextProcess();
-
- // Iterates over all known valid analyzers for the a given process or returns
- // null if there are no more.
- //
- // GetFirstProcess() must be called first in order to capture a global
- // snapshot! Ownership stays with the global analyzer object and all existing
- // analyzer pointers are invalidated when GetFirstProcess() is called.
- ThreadActivityAnalyzer* GetFirstAnalyzer(int64_t pid);
- ThreadActivityAnalyzer* GetNextAnalyzer();
-
- // Gets the analyzer for a specific thread or null if there is none.
- // Ownership stays with the global analyzer object.
- ThreadActivityAnalyzer* GetAnalyzerForThread(const ThreadKey& key);
-
- // Extract user data based on a reference and its identifier.
- ActivityUserData::Snapshot GetUserDataSnapshot(int64_t pid,
- uint32_t ref,
- uint32_t id);
-
- // Extract the data for a specific process. An empty snapshot will be
- // returned if the process is not known.
- const ActivityUserData::Snapshot& GetProcessDataSnapshot(int64_t pid);
-
- // Gets all log messages stored within.
- std::vector<std::string> GetLogMessages();
-
- // Gets modules corresponding to a pid. This pid must come from a call to
- // GetFirst/NextProcess. Only modules that were first registered prior to
- // GetFirstProcess's snapshot are returned.
- std::vector<GlobalActivityTracker::ModuleInfo> GetModules(int64_t pid);
-
- // Gets the corresponding "program location" for a given "program counter".
- // This will return {0,0} if no mapping could be found.
- ProgramLocation GetProgramLocationFromAddress(uint64_t address);
-
- // Returns whether the data is complete. Data can be incomplete if the
- // recording size quota is hit.
- bool IsDataComplete() const;
-
- private:
- using AnalyzerMap =
- std::map<ThreadKey, std::unique_ptr<ThreadActivityAnalyzer>>;
-
- struct UserDataSnapshot {
- // Complex class needs out-of-line ctor/dtor.
- UserDataSnapshot();
- UserDataSnapshot(const UserDataSnapshot& rhs);
- UserDataSnapshot(UserDataSnapshot&& rhs);
- ~UserDataSnapshot();
-
- int64_t process_id;
- int64_t create_stamp;
- ActivityUserData::Snapshot data;
- };
-
- // Finds, creates, and indexes analyzers for all known processes and threads.
- void PrepareAllAnalyzers();
-
- // The persistent memory allocator holding all tracking data.
- std::unique_ptr<PersistentMemoryAllocator> allocator_;
-
- // The time stamp when analysis began. This is used to prevent looking into
- // process IDs that get reused when analyzing a live system.
- int64_t analysis_stamp_;
-
- // The iterator for finding tracking information in the allocator.
- PersistentMemoryAllocator::Iterator allocator_iterator_;
-
- // A set of all interesting memory references found within the allocator.
- std::set<PersistentMemoryAllocator::Reference> memory_references_;
-
- // A set of all process-data memory references found within the allocator.
- std::map<int64_t, UserDataSnapshot> process_data_;
-
- // A set of all process IDs collected during PrepareAllAnalyzers. These are
- // popped and returned one-by-one with calls to GetFirst/NextProcess().
- std::vector<int64_t> process_ids_;
-
- // A map, keyed by ThreadKey, of all valid activity analyzers.
- AnalyzerMap analyzers_;
-
- // The iterator within the analyzers_ map for returning analyzers through
- // first/next iteration.
- AnalyzerMap::iterator analyzers_iterator_;
- int64_t analyzers_iterator_pid_;
-
- DISALLOW_COPY_AND_ASSIGN(GlobalActivityAnalyzer);
-};
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_ACTIVITY_ANALYZER_H_
diff --git a/base/debug/alias.cc b/base/debug/alias.cc
deleted file mode 100644
index d93d495..0000000
--- a/base/debug/alias.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/alias.h"
-#include "build_config.h"
-
-namespace base {
-namespace debug {
-
-#if defined(COMPILER_MSVC)
-#pragma optimize("", off)
-#endif
-
-void Alias(const void* var) {
-}
-
-#if defined(COMPILER_MSVC)
-#pragma optimize("", on)
-#endif
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/alias.h b/base/debug/alias.h
deleted file mode 100644
index 128fdaa..0000000
--- a/base/debug/alias.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_DEBUG_ALIAS_H_
-#define BASE_DEBUG_ALIAS_H_
-
-#include "base/base_export.h"
-#include "base/strings/string_util.h"
-
-namespace base {
-namespace debug {
-
-// Make the optimizer think that var is aliased. This is to prevent it from
-// optimizing out local variables that would not otherwise be live at the point
-// of a potential crash.
-// base::debug::Alias should only be used for local variables, not globals,
-// object members, or function return values - these must be copied to locals if
-// you want to ensure they are recorded in crash dumps.
-// Note that if the local variable is a pointer then its value will be retained
-// but the memory that it points to will probably not be saved in the crash
-// dump - by default only stack memory is saved. Therefore the aliasing
-// technique is usually only worthwhile with non-pointer variables. If you have
-// a pointer to an object and you want to retain the object's state you need to
-// copy the object or its fields to local variables. Example usage:
-// int last_error = err_;
-// base::debug::Alias(&last_error);
-// DEBUG_ALIAS_FOR_CSTR(name_copy, p->name, 16);
-// CHECK(false);
-void BASE_EXPORT Alias(const void* var);
-
-} // namespace debug
-} // namespace base
-
-// Convenience macro that copies the null-terminated string from |c_str| into a
-// stack-allocated char array named |var_name| that holds up to |char_count|
-// characters and should be preserved in memory dumps.
-#define DEBUG_ALIAS_FOR_CSTR(var_name, c_str, char_count) \
- char var_name[char_count]; \
- ::base::strlcpy(var_name, (c_str), arraysize(var_name)); \
- ::base::debug::Alias(var_name);
-
-#endif // BASE_DEBUG_ALIAS_H_
diff --git a/base/debug/asan_invalid_access.cc b/base/debug/asan_invalid_access.cc
deleted file mode 100644
index d5d43d5..0000000
--- a/base/debug/asan_invalid_access.cc
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/asan_invalid_access.h"
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/debug/alias.h"
-#include "base/logging.h"
-#include "build_config.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-
-namespace base {
-namespace debug {
-
-namespace {
-
-#if defined(OS_WIN) && defined(ADDRESS_SANITIZER)
-// Corrupt a memory block and make sure that the corruption gets detected either
-// when we free it or when another crash happens (if |induce_crash| is set to
-// true).
-NOINLINE void CorruptMemoryBlock(bool induce_crash) {
- // NOTE(sebmarchand): We intentionally corrupt a memory block here in order to
- // trigger an Address Sanitizer (ASAN) error report.
- static const int kArraySize = 5;
- LONG* array = new LONG[kArraySize];
-
- // Explicitly call out to a kernel32 function to perform the memory access.
- // This way the underflow won't be detected but the corruption will (as the
- // allocator will still be hooked).
- auto InterlockedIncrementFn =
- reinterpret_cast<LONG (*)(LONG volatile * addend)>(
- GetProcAddress(GetModuleHandle(L"kernel32"), "InterlockedIncrement"));
- CHECK(InterlockedIncrementFn);
-
- LONG volatile dummy = InterlockedIncrementFn(array - 1);
- base::debug::Alias(const_cast<LONG*>(&dummy));
-
- if (induce_crash)
- CHECK(false);
- delete[] array;
-}
-#endif // OS_WIN && ADDRESS_SANITIZER
-
-} // namespace
-
-#if defined(ADDRESS_SANITIZER)
-// NOTE(sebmarchand): We intentionally perform some invalid heap access here in
-// order to trigger an AddressSanitizer (ASan) error report.
-
-static const size_t kArraySize = 5;
-
-void AsanHeapOverflow() {
- // Declares the array as volatile to make sure it doesn't get optimized away.
- std::unique_ptr<volatile int[]> array(
- const_cast<volatile int*>(new int[kArraySize]));
- int dummy = array[kArraySize];
- base::debug::Alias(&dummy);
-}
-
-void AsanHeapUnderflow() {
- // Declares the array as volatile to make sure it doesn't get optimized away.
- std::unique_ptr<volatile int[]> array(
- const_cast<volatile int*>(new int[kArraySize]));
- // We need to store the underflow address in a temporary variable as trying to
- // access array[-1] will trigger a warning C4245: "conversion from 'int' to
- // 'size_t', signed/unsigned mismatch".
- volatile int* underflow_address = &array[0] - 1;
- int dummy = *underflow_address;
- base::debug::Alias(&dummy);
-}
-
-void AsanHeapUseAfterFree() {
- // Declares the array as volatile to make sure it doesn't get optimized away.
- std::unique_ptr<volatile int[]> array(
- const_cast<volatile int*>(new int[kArraySize]));
- volatile int* dangling = array.get();
- array.reset();
- int dummy = dangling[kArraySize / 2];
- base::debug::Alias(&dummy);
-}
-
-#if defined(OS_WIN)
-void AsanCorruptHeapBlock() {
- CorruptMemoryBlock(false);
-}
-
-void AsanCorruptHeap() {
- CorruptMemoryBlock(true);
-}
-#endif // OS_WIN
-#endif // ADDRESS_SANITIZER
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/asan_invalid_access.h b/base/debug/asan_invalid_access.h
deleted file mode 100644
index f8b078a..0000000
--- a/base/debug/asan_invalid_access.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// Defines some functions that intentionally do an invalid memory access in
-// order to trigger an AddressSanitizer (ASan) error report.
-
-#ifndef BASE_DEBUG_ASAN_INVALID_ACCESS_H_
-#define BASE_DEBUG_ASAN_INVALID_ACCESS_H_
-
-#include "base/base_export.h"
-#include "base/compiler_specific.h"
-#include "build_config.h"
-
-namespace base {
-namespace debug {
-
-#if defined(ADDRESS_SANITIZER)
-
-// Generates an heap buffer overflow.
-BASE_EXPORT NOINLINE void AsanHeapOverflow();
-
-// Generates an heap buffer underflow.
-BASE_EXPORT NOINLINE void AsanHeapUnderflow();
-
-// Generates an use after free.
-BASE_EXPORT NOINLINE void AsanHeapUseAfterFree();
-
-// The "corrupt-block" and "corrupt-heap" classes of bugs is specific to
-// Windows.
-#if defined(OS_WIN)
-// Corrupts a memory block and makes sure that the corruption gets detected when
-// we try to free this block.
-BASE_EXPORT NOINLINE void AsanCorruptHeapBlock();
-
-// Corrupts the heap and makes sure that the corruption gets detected when a
-// crash occur.
-BASE_EXPORT NOINLINE void AsanCorruptHeap();
-
-#endif // OS_WIN
-#endif // ADDRESS_SANITIZER
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_ASAN_INVALID_ACCESS_H_
diff --git a/base/debug/close_handle_hook_win.cc b/base/debug/close_handle_hook_win.cc
deleted file mode 100644
index 35afdf5..0000000
--- a/base/debug/close_handle_hook_win.cc
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/close_handle_hook_win.h"
-
-#include <Windows.h>
-#include <psapi.h>
-#include <stddef.h>
-
-#include <algorithm>
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/win/iat_patch_function.h"
-#include "base/win/pe_image.h"
-#include "base/win/scoped_handle.h"
-#include "build_config.h"
-
-namespace {
-
-typedef BOOL (WINAPI* CloseHandleType) (HANDLE handle);
-
-typedef BOOL (WINAPI* DuplicateHandleType)(HANDLE source_process,
- HANDLE source_handle,
- HANDLE target_process,
- HANDLE* target_handle,
- DWORD desired_access,
- BOOL inherit_handle,
- DWORD options);
-
-CloseHandleType g_close_function = NULL;
-DuplicateHandleType g_duplicate_function = NULL;
-
-// The entry point for CloseHandle interception. This function notifies the
-// verifier about the handle that is being closed, and calls the original
-// function.
-BOOL WINAPI CloseHandleHook(HANDLE handle) {
- base::win::OnHandleBeingClosed(handle);
- return g_close_function(handle);
-}
-
-BOOL WINAPI DuplicateHandleHook(HANDLE source_process,
- HANDLE source_handle,
- HANDLE target_process,
- HANDLE* target_handle,
- DWORD desired_access,
- BOOL inherit_handle,
- DWORD options) {
- if ((options & DUPLICATE_CLOSE_SOURCE) &&
- (GetProcessId(source_process) == ::GetCurrentProcessId())) {
- base::win::OnHandleBeingClosed(source_handle);
- }
-
- return g_duplicate_function(source_process, source_handle, target_process,
- target_handle, desired_access, inherit_handle,
- options);
-}
-
-} // namespace
-
-namespace base {
-namespace debug {
-
-namespace {
-
-// Provides a simple way to temporarily change the protection of a memory page.
-class AutoProtectMemory {
- public:
- AutoProtectMemory()
- : changed_(false), address_(NULL), bytes_(0), old_protect_(0) {}
-
- ~AutoProtectMemory() {
- RevertProtection();
- }
-
- // Grants write access to a given memory range.
- bool ChangeProtection(void* address, size_t bytes);
-
- // Restores the original page protection.
- void RevertProtection();
-
- private:
- bool changed_;
- void* address_;
- size_t bytes_;
- DWORD old_protect_;
-
- DISALLOW_COPY_AND_ASSIGN(AutoProtectMemory);
-};
-
-bool AutoProtectMemory::ChangeProtection(void* address, size_t bytes) {
- DCHECK(!changed_);
- DCHECK(address);
-
- // Change the page protection so that we can write.
- MEMORY_BASIC_INFORMATION memory_info;
- if (!VirtualQuery(address, &memory_info, sizeof(memory_info)))
- return false;
-
- DWORD is_executable = (PAGE_EXECUTE | PAGE_EXECUTE_READ |
- PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) &
- memory_info.Protect;
-
- DWORD protect = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
- if (!VirtualProtect(address, bytes, protect, &old_protect_))
- return false;
-
- changed_ = true;
- address_ = address;
- bytes_ = bytes;
- return true;
-}
-
-void AutoProtectMemory::RevertProtection() {
- if (!changed_)
- return;
-
- DCHECK(address_);
- DCHECK(bytes_);
-
- VirtualProtect(address_, bytes_, old_protect_, &old_protect_);
- changed_ = false;
- address_ = NULL;
- bytes_ = 0;
- old_protect_ = 0;
-}
-
-// Performs an EAT interception.
-void EATPatch(HMODULE module, const char* function_name,
- void* new_function, void** old_function) {
- if (!module)
- return;
-
- base::win::PEImage pe(module);
- if (!pe.VerifyMagic())
- return;
-
- DWORD* eat_entry = pe.GetExportEntry(function_name);
- if (!eat_entry)
- return;
-
- if (!(*old_function))
- *old_function = pe.RVAToAddr(*eat_entry);
-
- AutoProtectMemory memory;
- if (!memory.ChangeProtection(eat_entry, sizeof(DWORD)))
- return;
-
- // Perform the patch.
-#pragma warning(push)
-#pragma warning(disable : 4311 4302)
- // These casts generate truncation warnings because they are 32 bit specific.
- *eat_entry = reinterpret_cast<DWORD>(new_function) -
- reinterpret_cast<DWORD>(module);
-#pragma warning(pop)
-}
-
-// Performs an IAT interception.
-base::win::IATPatchFunction* IATPatch(HMODULE module, const char* function_name,
- void* new_function, void** old_function) {
- if (!module)
- return NULL;
-
- base::win::IATPatchFunction* patch = new base::win::IATPatchFunction;
- __try {
- // There is no guarantee that |module| is still loaded at this point.
- if (patch->PatchFromModule(module, "kernel32.dll", function_name,
- new_function)) {
- delete patch;
- return NULL;
- }
- } __except((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ||
- GetExceptionCode() == EXCEPTION_GUARD_PAGE ||
- GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR) ?
- EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
- // Leak the patch.
- return NULL;
- }
-
- if (!(*old_function)) {
- // Things are probably messed up if each intercepted function points to
- // a different place, but we need only one function to call.
- *old_function = patch->original_function();
- }
- return patch;
-}
-
-// Keeps track of all the hooks needed to intercept functions which could
-// possibly close handles.
-class HandleHooks {
- public:
- HandleHooks() {}
- ~HandleHooks() {}
-
- void AddIATPatch(HMODULE module);
- void AddEATPatch();
-
- private:
- std::vector<base::win::IATPatchFunction*> hooks_;
- DISALLOW_COPY_AND_ASSIGN(HandleHooks);
-};
-
-void HandleHooks::AddIATPatch(HMODULE module) {
- if (!module)
- return;
-
- base::win::IATPatchFunction* patch = NULL;
- patch =
- IATPatch(module, "CloseHandle", reinterpret_cast<void*>(&CloseHandleHook),
- reinterpret_cast<void**>(&g_close_function));
- if (!patch)
- return;
- hooks_.push_back(patch);
-
- patch = IATPatch(module, "DuplicateHandle",
- reinterpret_cast<void*>(&DuplicateHandleHook),
- reinterpret_cast<void**>(&g_duplicate_function));
- if (!patch)
- return;
- hooks_.push_back(patch);
-}
-
-void HandleHooks::AddEATPatch() {
- // An attempt to restore the entry on the table at destruction is not safe.
- EATPatch(GetModuleHandleA("kernel32.dll"), "CloseHandle",
- reinterpret_cast<void*>(&CloseHandleHook),
- reinterpret_cast<void**>(&g_close_function));
- EATPatch(GetModuleHandleA("kernel32.dll"), "DuplicateHandle",
- reinterpret_cast<void*>(&DuplicateHandleHook),
- reinterpret_cast<void**>(&g_duplicate_function));
-}
-
-void PatchLoadedModules(HandleHooks* hooks) {
- const DWORD kSize = 256;
- DWORD returned;
- std::unique_ptr<HMODULE[]> modules(new HMODULE[kSize]);
- if (!EnumProcessModules(GetCurrentProcess(), modules.get(),
- kSize * sizeof(HMODULE), &returned)) {
- return;
- }
- returned /= sizeof(HMODULE);
- returned = std::min(kSize, returned);
-
- for (DWORD current = 0; current < returned; current++) {
- hooks->AddIATPatch(modules[current]);
- }
-}
-
-} // namespace
-
-void InstallHandleHooks() {
- static HandleHooks* hooks = new HandleHooks();
-
- // Performing EAT interception first is safer in the presence of other
- // threads attempting to call CloseHandle.
- hooks->AddEATPatch();
- PatchLoadedModules(hooks);
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/close_handle_hook_win.h b/base/debug/close_handle_hook_win.h
deleted file mode 100644
index c775d75..0000000
--- a/base/debug/close_handle_hook_win.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_DEBUG_CLOSE_HANDLE_HOOK_WIN_H_
-#define BASE_DEBUG_CLOSE_HANDLE_HOOK_WIN_H_
-
-#include "base/base_export.h"
-
-namespace base {
-namespace debug {
-
-// Installs the hooks required to debug use of improper handles.
-BASE_EXPORT void InstallHandleHooks();
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_CLOSE_HANDLE_HOOK_WIN_H_
diff --git a/base/debug/crash_logging.cc b/base/debug/crash_logging.cc
deleted file mode 100644
index 1dabb6b..0000000
--- a/base/debug/crash_logging.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/crash_logging.h"
-
-namespace base {
-namespace debug {
-
-namespace {
-
-CrashKeyImplementation* g_crash_key_impl = nullptr;
-
-} // namespace
-
-CrashKeyString* AllocateCrashKeyString(const char name[],
- CrashKeySize value_length) {
- if (!g_crash_key_impl)
- return nullptr;
-
- return g_crash_key_impl->Allocate(name, value_length);
-}
-
-void SetCrashKeyString(CrashKeyString* crash_key, base::StringPiece value) {
- if (!g_crash_key_impl || !crash_key)
- return;
-
- g_crash_key_impl->Set(crash_key, value);
-}
-
-void ClearCrashKeyString(CrashKeyString* crash_key) {
- if (!g_crash_key_impl || !crash_key)
- return;
-
- g_crash_key_impl->Clear(crash_key);
-}
-
-ScopedCrashKeyString::ScopedCrashKeyString(CrashKeyString* crash_key,
- base::StringPiece value)
- : crash_key_(crash_key) {
- SetCrashKeyString(crash_key_, value);
-}
-
-ScopedCrashKeyString::~ScopedCrashKeyString() {
- ClearCrashKeyString(crash_key_);
-}
-
-void SetCrashKeyImplementation(std::unique_ptr<CrashKeyImplementation> impl) {
- delete g_crash_key_impl;
- g_crash_key_impl = impl.release();
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/crash_logging.h b/base/debug/crash_logging.h
deleted file mode 100644
index 9c6cd75..0000000
--- a/base/debug/crash_logging.h
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_DEBUG_CRASH_LOGGING_H_
-#define BASE_DEBUG_CRASH_LOGGING_H_
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/base_export.h"
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-
-namespace base {
-namespace debug {
-
-// A crash key is an annotation that is carried along with a crash report, to
-// provide additional debugging information beyond a stack trace. Crash keys
-// have a name and a string value.
-//
-// The preferred API is //components/crash/core/common:crash_key, however not
-// all clients can hold a direct dependency on that target. The API provided
-// in this file indirects the dependency.
-//
-// Example usage:
-// static CrashKeyString* crash_key =
-// AllocateCrashKeyString("name", CrashKeySize::Size32);
-// SetCrashKeyString(crash_key, "value");
-// ClearCrashKeyString(crash_key);
-
-// The maximum length for a crash key's value must be one of the following
-// pre-determined values.
-enum class CrashKeySize {
- Size32 = 32,
- Size64 = 64,
- Size256 = 256,
-};
-
-struct CrashKeyString;
-
-// Allocates a new crash key with the specified |name| with storage for a
-// value up to length |size|. This will return null if the crash key system is
-// not initialized.
-BASE_EXPORT CrashKeyString* AllocateCrashKeyString(const char name[],
- CrashKeySize size);
-
-// Stores |value| into the specified |crash_key|. The |crash_key| may be null
-// if AllocateCrashKeyString() returned null. If |value| is longer than the
-// size with which the key was allocated, it will be truncated.
-BASE_EXPORT void SetCrashKeyString(CrashKeyString* crash_key,
- base::StringPiece value);
-
-// Clears any value that was stored in |crash_key|. The |crash_key| may be
-// null.
-BASE_EXPORT void ClearCrashKeyString(CrashKeyString* crash_key);
-
-// A scoper that sets the specified key to value for the lifetime of the
-// object, and clears it on destruction.
-class BASE_EXPORT ScopedCrashKeyString {
- public:
- ScopedCrashKeyString(CrashKeyString* crash_key, base::StringPiece value);
- ~ScopedCrashKeyString();
-
- private:
- CrashKeyString* const crash_key_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedCrashKeyString);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// The following declarations are used to initialize the crash key system
-// in //base by providing implementations for the above functions.
-
-// The virtual interface that provides the implementation for the crash key
-// API. This is implemented by a higher-layer component, and the instance is
-// set using the function below.
-class CrashKeyImplementation {
- public:
- virtual ~CrashKeyImplementation() = default;
-
- virtual CrashKeyString* Allocate(const char name[], CrashKeySize size) = 0;
- virtual void Set(CrashKeyString* crash_key, base::StringPiece value) = 0;
- virtual void Clear(CrashKeyString* crash_key) = 0;
-};
-
-// Initializes the crash key system in base by replacing the existing
-// implementation, if it exists, with |impl|. The |impl| is copied into base.
-BASE_EXPORT void SetCrashKeyImplementation(
- std::unique_ptr<CrashKeyImplementation> impl);
-
-// The base structure for a crash key, storing the allocation metadata.
-struct CrashKeyString {
- constexpr CrashKeyString(const char name[], CrashKeySize size)
- : name(name), size(size) {}
- const char* const name;
- const CrashKeySize size;
-};
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_CRASH_LOGGING_H_
diff --git a/base/debug/debugger.cc b/base/debug/debugger.cc
deleted file mode 100644
index 025bc54..0000000
--- a/base/debug/debugger.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/debugger.h"
-#include "base/logging.h"
-#include "base/threading/platform_thread.h"
-#include "build_config.h"
-
-namespace base {
-namespace debug {
-
-static bool is_debug_ui_suppressed = false;
-
-bool WaitForDebugger(int wait_seconds, bool silent) {
-#if defined(OS_ANDROID)
- // The pid from which we know which process to attach to are not output by
- // android ddms, so we have to print it out explicitly.
- DLOG(INFO) << "DebugUtil::WaitForDebugger(pid=" << static_cast<int>(getpid())
- << ")";
-#endif
- for (int i = 0; i < wait_seconds * 10; ++i) {
- if (BeingDebugged()) {
- if (!silent)
- BreakDebugger();
- return true;
- }
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
- }
- return false;
-}
-
-void SetSuppressDebugUI(bool suppress) {
- is_debug_ui_suppressed = suppress;
-}
-
-bool IsDebugUISuppressed() {
- return is_debug_ui_suppressed;
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/debugger.h b/base/debug/debugger.h
deleted file mode 100644
index 8680e28..0000000
--- a/base/debug/debugger.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This is a cross platform interface for helper functions related to
-// debuggers. You should use this to test if you're running under a debugger,
-// and if you would like to yield (breakpoint) into the debugger.
-
-#ifndef BASE_DEBUG_DEBUGGER_H_
-#define BASE_DEBUG_DEBUGGER_H_
-
-#include "base/base_export.h"
-
-namespace base {
-namespace debug {
-
-// Waits wait_seconds seconds for a debugger to attach to the current process.
-// When silent is false, an exception is thrown when a debugger is detected.
-BASE_EXPORT bool WaitForDebugger(int wait_seconds, bool silent);
-
-// Returns true if the given process is being run under a debugger.
-//
-// On OS X, the underlying mechanism doesn't work when the sandbox is enabled.
-// To get around this, this function caches its value.
-//
-// WARNING: Because of this, on OS X, a call MUST be made to this function
-// BEFORE the sandbox is enabled.
-BASE_EXPORT bool BeingDebugged();
-
-// Break into the debugger, assumes a debugger is present.
-BASE_EXPORT void BreakDebugger();
-
-// Used in test code, this controls whether showing dialogs and breaking into
-// the debugger is suppressed for debug errors, even in debug mode (normally
-// release mode doesn't do this stuff -- this is controlled separately).
-// Normally UI is not suppressed. This is normally used when running automated
-// tests where we want a crash rather than a dialog or a debugger.
-BASE_EXPORT void SetSuppressDebugUI(bool suppress);
-BASE_EXPORT bool IsDebugUISuppressed();
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_DEBUGGER_H_
diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc
deleted file mode 100644
index 63d9d52..0000000
--- a/base/debug/debugger_posix.cc
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/debugger.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/threading/platform_thread.h"
-#include "base/time/time.h"
-#include "build_config.h"
-
-#if defined(__GLIBCXX__)
-#include <cxxabi.h>
-#endif
-
-#if defined(OS_MACOSX)
-#include <AvailabilityMacros.h>
-#endif
-
-#if defined(OS_MACOSX) || defined(OS_BSD)
-#include <sys/sysctl.h>
-#endif
-
-#if defined(OS_FREEBSD)
-#include <sys/user.h>
-#endif
-
-#include <ostream>
-
-#include "base/debug/alias.h"
-#include "base/logging.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/strings/string_piece.h"
-
-#if defined(USE_SYMBOLIZE)
-#include "base/third_party/symbolize/symbolize.h"
-#endif
-
-#if defined(OS_ANDROID)
-#include "base/threading/platform_thread.h"
-#endif
-
-namespace base {
-namespace debug {
-
-#if defined(OS_MACOSX) || defined(OS_BSD)
-
-// Based on Apple's recommended method as described in
-// http://developer.apple.com/qa/qa2004/qa1361.html
-bool BeingDebugged() {
- // NOTE: This code MUST be async-signal safe (it's used by in-process
- // stack dumping signal handler). NO malloc or stdio is allowed here.
- //
- // While some code used below may be async-signal unsafe, note how
- // the result is cached (see |is_set| and |being_debugged| static variables
- // right below). If this code is properly warmed-up early
- // in the start-up process, it should be safe to use later.
-
- // If the process is sandboxed then we can't use the sysctl, so cache the
- // value.
- static bool is_set = false;
- static bool being_debugged = false;
-
- if (is_set)
- return being_debugged;
-
- // Initialize mib, which tells sysctl what info we want. In this case,
- // we're looking for information about a specific process ID.
- int mib[] = {
- CTL_KERN,
- KERN_PROC,
- KERN_PROC_PID,
- getpid()
-#if defined(OS_OPENBSD)
- , sizeof(struct kinfo_proc),
- 0
-#endif
- };
-
- // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE. The source and
- // binary interfaces may change.
- struct kinfo_proc info;
- size_t info_size = sizeof(info);
-
-#if defined(OS_OPENBSD)
- if (sysctl(mib, arraysize(mib), NULL, &info_size, NULL, 0) < 0)
- return -1;
-
- mib[5] = (info_size / sizeof(struct kinfo_proc));
-#endif
-
- int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0);
- DCHECK_EQ(sysctl_result, 0);
- if (sysctl_result != 0) {
- is_set = true;
- being_debugged = false;
- return being_debugged;
- }
-
- // This process is being debugged if the P_TRACED flag is set.
- is_set = true;
-#if defined(OS_FREEBSD)
- being_debugged = (info.ki_flag & P_TRACED) != 0;
-#elif defined(OS_BSD)
- being_debugged = (info.p_flag & P_TRACED) != 0;
-#else
- being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0;
-#endif
- return being_debugged;
-}
-
-#elif defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_AIX)
-
-// We can look in /proc/self/status for TracerPid. We are likely used in crash
-// handling, so we are careful not to use the heap or have side effects.
-// Another option that is common is to try to ptrace yourself, but then we
-// can't detach without forking(), and that's not so great.
-// static
-bool BeingDebugged() {
- // NOTE: This code MUST be async-signal safe (it's used by in-process
- // stack dumping signal handler). NO malloc or stdio is allowed here.
-
- int status_fd = open("/proc/self/status", O_RDONLY);
- if (status_fd == -1)
- return false;
-
- // We assume our line will be in the first 1024 characters and that we can
- // read this much all at once. In practice this will generally be true.
- // This simplifies and speeds up things considerably.
- char buf[1024];
-
- ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf)));
- if (IGNORE_EINTR(close(status_fd)) < 0)
- return false;
-
- if (num_read <= 0)
- return false;
-
- StringPiece status(buf, num_read);
- StringPiece tracer("TracerPid:\t");
-
- StringPiece::size_type pid_index = status.find(tracer);
- if (pid_index == StringPiece::npos)
- return false;
-
- // Our pid is 0 without a debugger, assume this for any pid starting with 0.
- pid_index += tracer.size();
- return pid_index < status.size() && status[pid_index] != '0';
-}
-
-#elif defined(OS_FUCHSIA)
-
-bool BeingDebugged() {
- // TODO(fuchsia): No gdb/gdbserver in the SDK yet.
- return false;
-}
-
-#else
-
-bool BeingDebugged() {
- NOTIMPLEMENTED();
- return false;
-}
-
-#endif
-
-// We want to break into the debugger in Debug mode, and cause a crash dump in
-// Release mode. Breakpad behaves as follows:
-//
-// +-------+-----------------+-----------------+
-// | OS | Dump on SIGTRAP | Dump on SIGABRT |
-// +-------+-----------------+-----------------+
-// | Linux | N | Y |
-// | Mac | Y | N |
-// +-------+-----------------+-----------------+
-//
-// Thus we do the following:
-// Linux: Debug mode if a debugger is attached, send SIGTRAP; otherwise send
-// SIGABRT
-// Mac: Always send SIGTRAP.
-
-#if defined(ARCH_CPU_ARMEL)
-#define DEBUG_BREAK_ASM() asm("bkpt 0")
-#elif defined(ARCH_CPU_ARM64)
-#define DEBUG_BREAK_ASM() asm("brk 0")
-#elif defined(ARCH_CPU_MIPS_FAMILY)
-#define DEBUG_BREAK_ASM() asm("break 2")
-#elif defined(ARCH_CPU_X86_FAMILY)
-#define DEBUG_BREAK_ASM() asm("int3")
-#endif
-
-#if defined(NDEBUG) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
-#define DEBUG_BREAK() abort()
-#elif defined(OS_NACL)
-// The NaCl verifier doesn't let use use int3. For now, we call abort(). We
-// should ask for advice from some NaCl experts about the optimum thing here.
-// http://code.google.com/p/nativeclient/issues/detail?id=645
-#define DEBUG_BREAK() abort()
-#elif !defined(OS_MACOSX)
-// Though Android has a "helpful" process called debuggerd to catch native
-// signals on the general assumption that they are fatal errors. If no debugger
-// is attached, we call abort since Breakpad needs SIGABRT to create a dump.
-// When debugger is attached, for ARM platform the bkpt instruction appears
-// to cause SIGBUS which is trapped by debuggerd, and we've had great
-// difficulty continuing in a debugger once we stop from SIG triggered by native
-// code, use GDB to set |go| to 1 to resume execution; for X86 platform, use
-// "int3" to setup breakpiont and raise SIGTRAP.
-//
-// On other POSIX architectures, except Mac OS X, we use the same logic to
-// ensure that breakpad creates a dump on crashes while it is still possible to
-// use a debugger.
-namespace {
-void DebugBreak() {
- if (!BeingDebugged()) {
- abort();
- } else {
-#if defined(DEBUG_BREAK_ASM)
- DEBUG_BREAK_ASM();
-#else
- volatile int go = 0;
- while (!go) {
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
- }
-#endif
- }
-}
-} // namespace
-#define DEBUG_BREAK() DebugBreak()
-#elif defined(DEBUG_BREAK_ASM)
-#define DEBUG_BREAK() DEBUG_BREAK_ASM()
-#else
-#error "Don't know how to debug break on this architecture/OS"
-#endif
-
-void BreakDebugger() {
- // NOTE: This code MUST be async-signal safe (it's used by in-process
- // stack dumping signal handler). NO malloc or stdio is allowed here.
-
- // Linker's ICF feature may merge this function with other functions with the
- // same definition (e.g. any function whose sole job is to call abort()) and
- // it may confuse the crash report processing system. http://crbug.com/508489
- static int static_variable_to_make_this_function_unique = 0;
- base::debug::Alias(&static_variable_to_make_this_function_unique);
-
- DEBUG_BREAK();
-#if defined(OS_ANDROID) && !defined(OFFICIAL_BUILD)
- // For Android development we always build release (debug builds are
- // unmanageably large), so the unofficial build is used for debugging. It is
- // helpful to be able to insert BreakDebugger() statements in the source,
- // attach the debugger, inspect the state of the program and then resume it by
- // setting the 'go' variable above.
-#elif defined(NDEBUG)
- // Terminate the program after signaling the debug break.
- _exit(1);
-#endif
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/debugger_win.cc b/base/debug/debugger_win.cc
deleted file mode 100644
index a1d86e4..0000000
--- a/base/debug/debugger_win.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/debugger.h"
-
-#include <stdlib.h>
-#include <windows.h>
-
-namespace base {
-namespace debug {
-
-bool BeingDebugged() {
- return ::IsDebuggerPresent() != 0;
-}
-
-void BreakDebugger() {
- if (IsDebugUISuppressed())
- _exit(1);
-
- __debugbreak();
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/dump_without_crashing.cc b/base/debug/dump_without_crashing.cc
deleted file mode 100644
index 1ab8c9c..0000000
--- a/base/debug/dump_without_crashing.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/dump_without_crashing.h"
-
-#include "base/logging.h"
-
-namespace {
-
-// Pointer to the function that's called by DumpWithoutCrashing() to dump the
-// process's memory.
-void(CDECL* dump_without_crashing_function_)() = nullptr;
-
-} // namespace
-
-namespace base {
-
-namespace debug {
-
-bool DumpWithoutCrashing() {
- if (dump_without_crashing_function_) {
- (*dump_without_crashing_function_)();
- return true;
- }
- return false;
-}
-
-void SetDumpWithoutCrashingFunction(void (CDECL *function)()) {
-#if !defined(COMPONENT_BUILD)
- // In component builds, the same base is shared between modules
- // so might be initialized several times. However in non-
- // component builds this should never happen.
- DCHECK(!dump_without_crashing_function_);
-#endif
- dump_without_crashing_function_ = function;
-}
-
-} // namespace debug
-
-} // namespace base
diff --git a/base/debug/dump_without_crashing.h b/base/debug/dump_without_crashing.h
deleted file mode 100644
index c36973f..0000000
--- a/base/debug/dump_without_crashing.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_DEBUG_DUMP_WITHOUT_CRASHING_H_
-#define BASE_DEBUG_DUMP_WITHOUT_CRASHING_H_
-
-#include "base/base_export.h"
-#include "base/compiler_specific.h"
-#include "build_config.h"
-
-namespace base {
-
-namespace debug {
-
-// Handler to silently dump the current process without crashing.
-// Before calling this function, call SetDumpWithoutCrashingFunction to pass a
-// function pointer.
-// Windows:
-// This must be done for each instance of base (i.e. module) and is normally
-// chrome_elf!DumpProcessWithoutCrash. See example code in chrome_main.cc that
-// does this for chrome.dll and chrome_child.dll. Note: Crashpad sets this up
-// for main chrome.exe as part of calling crash_reporter::InitializeCrashpad.
-// Mac/Linux:
-// Crashpad does this as part of crash_reporter::InitializeCrashpad.
-// Returns false if called before SetDumpWithoutCrashingFunction.
-BASE_EXPORT bool DumpWithoutCrashing();
-
-// Sets a function that'll be invoked to dump the current process when
-// DumpWithoutCrashing() is called.
-BASE_EXPORT void SetDumpWithoutCrashingFunction(void (CDECL *function)());
-
-} // namespace debug
-
-} // namespace base
-
-#endif // BASE_DEBUG_DUMP_WITHOUT_CRASHING_H_
diff --git a/base/debug/elf_reader_linux.cc b/base/debug/elf_reader_linux.cc
deleted file mode 100644
index cdf8193..0000000
--- a/base/debug/elf_reader_linux.cc
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/elf_reader_linux.h"
-
-#include <arpa/inet.h>
-#include <elf.h>
-
-#include <vector>
-
-#include "base/bits.h"
-#include "base/containers/span.h"
-#include "base/sha1.h"
-#include "base/strings/stringprintf.h"
-
-namespace base {
-namespace debug {
-
-namespace {
-
-#if __SIZEOF_POINTER__ == 4
-using Ehdr = Elf32_Ehdr;
-using Dyn = Elf32_Dyn;
-using Half = Elf32_Half;
-using Nhdr = Elf32_Nhdr;
-using Phdr = Elf32_Phdr;
-using Word = Elf32_Word;
-#else
-using Ehdr = Elf64_Ehdr;
-using Dyn = Elf64_Dyn;
-using Half = Elf64_Half;
-using Nhdr = Elf64_Nhdr;
-using Phdr = Elf64_Phdr;
-using Word = Elf64_Word;
-#endif
-
-using ElfSegment = span<const char>;
-
-Optional<std::string> ElfSegmentBuildIDNoteAsString(const ElfSegment& segment) {
- const void* section_end = segment.data() + segment.size_bytes();
- const Nhdr* note_header = reinterpret_cast<const Nhdr*>(segment.data());
- while (note_header < section_end) {
- if (note_header->n_type == NT_GNU_BUILD_ID)
- break;
- note_header = reinterpret_cast<const Nhdr*>(
- reinterpret_cast<const char*>(note_header) + sizeof(Nhdr) +
- bits::Align(note_header->n_namesz, 4) +
- bits::Align(note_header->n_descsz, 4));
- }
-
- if (note_header >= section_end || note_header->n_descsz != kSHA1Length)
- return nullopt;
-
- const uint8_t* guid = reinterpret_cast<const uint8_t*>(note_header) +
- sizeof(Nhdr) + bits::Align(note_header->n_namesz, 4);
-
- uint32_t dword = htonl(*reinterpret_cast<const int32_t*>(guid));
- uint16_t word1 = htons(*reinterpret_cast<const int16_t*>(guid + 4));
- uint16_t word2 = htons(*reinterpret_cast<const int16_t*>(guid + 6));
- std::string identifier;
- identifier.reserve(kSHA1Length * 2); // as hex string
- SStringPrintf(&identifier, "%08X%04X%04X", dword, word1, word2);
- for (size_t i = 8; i < note_header->n_descsz; ++i)
- StringAppendF(&identifier, "%02X", guid[i]);
-
- return identifier;
-}
-
-std::vector<ElfSegment> FindElfSegments(const void* elf_mapped_base,
- uint32_t segment_type) {
- const char* elf_base = reinterpret_cast<const char*>(elf_mapped_base);
- if (strncmp(elf_base, ELFMAG, SELFMAG) != 0)
- return std::vector<ElfSegment>();
-
- const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base);
- const Phdr* phdrs =
- reinterpret_cast<const Phdr*>(elf_base + elf_header->e_phoff);
- std::vector<ElfSegment> segments;
- for (Half i = 0; i < elf_header->e_phnum; ++i) {
- if (phdrs[i].p_type == segment_type)
- segments.push_back({elf_base + phdrs[i].p_offset, phdrs[i].p_filesz});
- }
- return segments;
-}
-
-} // namespace
-
-Optional<std::string> ReadElfBuildId(const void* elf_base) {
- // Elf program headers can have multiple PT_NOTE arrays.
- std::vector<ElfSegment> segs = FindElfSegments(elf_base, PT_NOTE);
- if (segs.empty())
- return nullopt;
- Optional<std::string> id;
- for (const ElfSegment& seg : segs) {
- id = ElfSegmentBuildIDNoteAsString(seg);
- if (id)
- return id;
- }
-
- return nullopt;
-}
-
-Optional<std::string> ReadElfLibraryName(const void* elf_base) {
- std::vector<ElfSegment> segs = FindElfSegments(elf_base, PT_DYNAMIC);
- if (segs.empty())
- return nullopt;
- DCHECK_EQ(1u, segs.size());
-
- const ElfSegment& dynamic_seg = segs.front();
- const Dyn* dynamic_start = reinterpret_cast<const Dyn*>(dynamic_seg.data());
- const Dyn* dynamic_end = reinterpret_cast<const Dyn*>(
- dynamic_seg.data() + dynamic_seg.size_bytes());
- Optional<std::string> soname;
- Word soname_strtab_offset = 0;
- const char* strtab_addr = 0;
- for (const Dyn* dynamic_iter = dynamic_start; dynamic_iter < dynamic_end;
- ++dynamic_iter) {
- if (dynamic_iter->d_tag == DT_STRTAB) {
- strtab_addr =
- dynamic_iter->d_un.d_ptr + reinterpret_cast<const char*>(elf_base);
- } else if (dynamic_iter->d_tag == DT_SONAME) {
- soname_strtab_offset = dynamic_iter->d_un.d_val;
- }
- }
- if (soname_strtab_offset && strtab_addr)
- return std::string(strtab_addr + soname_strtab_offset);
- return nullopt;
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/elf_reader_linux.h b/base/debug/elf_reader_linux.h
deleted file mode 100644
index 4086dfb..0000000
--- a/base/debug/elf_reader_linux.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_DEBUG_ELF_READER_LINUX_H_
-#define BASE_DEBUG_ELF_READER_LINUX_H_
-
-#include <string>
-
-#include "base/base_export.h"
-#include "base/optional.h"
-
-namespace base {
-namespace debug {
-
-// Returns the ELF section .note.gnu.build-id from the ELF file mapped at
-// |elf_base|, if present. The caller must ensure that the file is fully mapped
-// in memory.
-Optional<std::string> BASE_EXPORT ReadElfBuildId(const void* elf_base);
-
-// Returns the library name from the ELF file mapped at |elf_base|, if present.
-// The caller must ensure that the file is fully mapped in memory.
-Optional<std::string> BASE_EXPORT ReadElfLibraryName(const void* elf_base);
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_ELF_READER_LINUX_H_
diff --git a/base/debug/gdi_debug_util_win.cc b/base/debug/gdi_debug_util_win.cc
deleted file mode 100644
index bf9827c..0000000
--- a/base/debug/gdi_debug_util_win.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-#include "base/debug/gdi_debug_util_win.h"
-
-#include <algorithm>
-#include <cmath>
-
-#include <psapi.h>
-#include <stddef.h>
-#include <TlHelp32.h>
-
-#include "base/debug/alias.h"
-#include "base/logging.h"
-#include "base/win/scoped_handle.h"
-#include "base/win/win_util.h"
-
-namespace {
-
-void CollectChildGDIUsageAndDie(DWORD parent_pid) {
- HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- CHECK_NE(INVALID_HANDLE_VALUE, snapshot);
-
- int total_process_count = 0;
- base::debug::Alias(&total_process_count);
- int total_peak_gdi_count = 0;
- base::debug::Alias(&total_peak_gdi_count);
- int total_gdi_count = 0;
- base::debug::Alias(&total_gdi_count);
- int total_user_count = 0;
- base::debug::Alias(&total_user_count);
-
- int child_count = 0;
- base::debug::Alias(&child_count);
- int peak_gdi_count = 0;
- base::debug::Alias(&peak_gdi_count);
- int sum_gdi_count = 0;
- base::debug::Alias(&sum_gdi_count);
- int sum_user_count = 0;
- base::debug::Alias(&sum_user_count);
-
- PROCESSENTRY32 proc_entry = {0};
- proc_entry.dwSize = sizeof(PROCESSENTRY32);
- CHECK(Process32First(snapshot, &proc_entry));
-
- do {
- base::win::ScopedHandle process(
- OpenProcess(PROCESS_QUERY_INFORMATION,
- FALSE,
- proc_entry.th32ProcessID));
- if (!process.IsValid())
- continue;
-
- int num_gdi_handles = GetGuiResources(process.Get(), GR_GDIOBJECTS);
- int num_user_handles = GetGuiResources(process.Get(), GR_USEROBJECTS);
-
- // Compute sum and peak counts for all processes.
- ++total_process_count;
- total_user_count += num_user_handles;
- total_gdi_count += num_gdi_handles;
- total_peak_gdi_count = std::max(total_peak_gdi_count, num_gdi_handles);
-
- if (parent_pid != proc_entry.th32ParentProcessID)
- continue;
-
- // Compute sum and peak counts for child processes.
- ++child_count;
- sum_user_count += num_user_handles;
- sum_gdi_count += num_gdi_handles;
- peak_gdi_count = std::max(peak_gdi_count, num_gdi_handles);
-
- } while (Process32Next(snapshot, &proc_entry));
-
- CloseHandle(snapshot);
- CHECK(false);
-}
-
-} // namespace
-
-namespace base {
-namespace debug {
-
-void CollectGDIUsageAndDie(BITMAPINFOHEADER* header, HANDLE shared_section) {
- // Make sure parameters are saved in the minidump.
- DWORD last_error = GetLastError();
- bool is_gdi_available = base::win::IsUser32AndGdi32Available();
-
- LONG width = header ? header->biWidth : 0;
- LONG height = header ? header->biHeight : 0;
-
- base::debug::Alias(&last_error);
- base::debug::Alias(&is_gdi_available);
- base::debug::Alias(&width);
- base::debug::Alias(&height);
- base::debug::Alias(&shared_section);
-
- DWORD num_user_handles = GetGuiResources(GetCurrentProcess(), GR_USEROBJECTS);
-
- DWORD num_gdi_handles = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
- if (num_gdi_handles == 0) {
- DWORD get_gui_resources_error = GetLastError();
- base::debug::Alias(&get_gui_resources_error);
- CHECK(false);
- }
-
- base::debug::Alias(&num_gdi_handles);
- base::debug::Alias(&num_user_handles);
-
- const DWORD kLotsOfHandles = 9990;
- CHECK_LE(num_gdi_handles, kLotsOfHandles);
-
- PROCESS_MEMORY_COUNTERS_EX pmc;
- pmc.cb = sizeof(pmc);
- CHECK(GetProcessMemoryInfo(GetCurrentProcess(),
- reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmc),
- sizeof(pmc)));
- const size_t kLotsOfMemory = 1500 * 1024 * 1024; // 1.5GB
- CHECK_LE(pmc.PagefileUsage, kLotsOfMemory);
- CHECK_LE(pmc.PrivateUsage, kLotsOfMemory);
-
- void* small_data = nullptr;
- base::debug::Alias(&small_data);
-
- if (std::abs(height) * width > 100) {
- // Huh, that's weird. We don't have crazy handle count, we don't have
- // ridiculous memory usage. Try to allocate a small bitmap and see if that
- // fails too.
- header->biWidth = 5;
- header->biHeight = -5;
- HBITMAP small_bitmap = CreateDIBSection(
- nullptr, reinterpret_cast<BITMAPINFO*>(&header),
- 0, &small_data, shared_section, 0);
- CHECK(small_bitmap != nullptr);
- DeleteObject(small_bitmap);
- }
- // Maybe the child processes are the ones leaking GDI or USER resouces.
- CollectChildGDIUsageAndDie(GetCurrentProcessId());
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/gdi_debug_util_win.h b/base/debug/gdi_debug_util_win.h
deleted file mode 100644
index 3383a4d..0000000
--- a/base/debug/gdi_debug_util_win.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_DEBUG_GDI_DEBUG_UTIL_WIN_H_
-#define BASE_DEBUG_GDI_DEBUG_UTIL_WIN_H_
-
-#include <windows.h>
-
-#include "base/base_export.h"
-
-namespace base {
-namespace debug {
-
-// Crashes the process, using base::debug::Alias to leave valuable debugging
-// information in the crash dump. Pass values for |header| and |shared_section|
-// in the event of a bitmap allocation failure, to gather information about
-// those as well.
-void BASE_EXPORT CollectGDIUsageAndDie(BITMAPINFOHEADER* header = nullptr,
- HANDLE shared_section = nullptr);
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_GDI_DEBUG_UTIL_WIN_H_
diff --git a/base/debug/leak_annotations.h b/base/debug/leak_annotations.h
deleted file mode 100644
index f1a2d07..0000000
--- a/base/debug/leak_annotations.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_DEBUG_LEAK_ANNOTATIONS_H_
-#define BASE_DEBUG_LEAK_ANNOTATIONS_H_
-
-#include "base/macros.h"
-#include "build_config.h"
-
-// This file defines macros which can be used to annotate intentional memory
-// leaks. Support for annotations is implemented in LeakSanitizer. Annotated
-// objects will be treated as a source of live pointers, i.e. any heap objects
-// reachable by following pointers from an annotated object will not be
-// reported as leaks.
-//
-// ANNOTATE_SCOPED_MEMORY_LEAK: all allocations made in the current scope
-// will be annotated as leaks.
-// ANNOTATE_LEAKING_OBJECT_PTR(X): the heap object referenced by pointer X will
-// be annotated as a leak.
-
-#if defined(LEAK_SANITIZER) && !defined(OS_NACL)
-
-#include <sanitizer/lsan_interface.h>
-
-class ScopedLeakSanitizerDisabler {
- public:
- ScopedLeakSanitizerDisabler() { __lsan_disable(); }
- ~ScopedLeakSanitizerDisabler() { __lsan_enable(); }
- private:
- DISALLOW_COPY_AND_ASSIGN(ScopedLeakSanitizerDisabler);
-};
-
-#define ANNOTATE_SCOPED_MEMORY_LEAK \
- ScopedLeakSanitizerDisabler leak_sanitizer_disabler; static_cast<void>(0)
-
-#define ANNOTATE_LEAKING_OBJECT_PTR(X) __lsan_ignore_object(X);
-
-#else
-
-#define ANNOTATE_SCOPED_MEMORY_LEAK ((void)0)
-#define ANNOTATE_LEAKING_OBJECT_PTR(X) ((void)0)
-
-#endif
-
-#endif // BASE_DEBUG_LEAK_ANNOTATIONS_H_
diff --git a/base/debug/leak_tracker.h b/base/debug/leak_tracker.h
deleted file mode 100644
index 43f2102..0000000
--- a/base/debug/leak_tracker.h
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_DEBUG_LEAK_TRACKER_H_
-#define BASE_DEBUG_LEAK_TRACKER_H_
-
-#include <stddef.h>
-
-#include "build_config.h"
-
-// Only enable leak tracking in non-uClibc debug builds.
-#if !defined(NDEBUG) && !defined(__UCLIBC__)
-#define ENABLE_LEAK_TRACKER
-#endif
-
-#ifdef ENABLE_LEAK_TRACKER
-#include "base/containers/linked_list.h"
-#include "base/debug/stack_trace.h"
-#include "base/logging.h"
-#endif // ENABLE_LEAK_TRACKER
-
-// LeakTracker is a helper to verify that all instances of a class
-// have been destroyed.
-//
-// It is particularly useful for classes that are bound to a single thread --
-// before destroying that thread, one can check that there are no remaining
-// instances of that class.
-//
-// For example, to enable leak tracking for class net::URLRequest, start by
-// adding a member variable of type LeakTracker<net::URLRequest>.
-//
-// class URLRequest {
-// ...
-// private:
-// base::LeakTracker<URLRequest> leak_tracker_;
-// };
-//
-//
-// Next, when we believe all instances of net::URLRequest have been deleted:
-//
-// LeakTracker<net::URLRequest>::CheckForLeaks();
-//
-// Should the check fail (because there are live instances of net::URLRequest),
-// then the allocation callstack for each leaked instances is dumped to
-// the error log.
-//
-// If ENABLE_LEAK_TRACKER is not defined, then the check has no effect.
-
-namespace base {
-namespace debug {
-
-#ifndef ENABLE_LEAK_TRACKER
-
-// If leak tracking is disabled, do nothing.
-template<typename T>
-class LeakTracker {
- public:
- // This destructor suppresses warnings about instances of this class not being
- // used.
- ~LeakTracker() {}
- static void CheckForLeaks() {}
- static int NumLiveInstances() { return -1; }
-};
-
-#else
-
-// If leak tracking is enabled we track where the object was allocated from.
-
-template<typename T>
-class LeakTracker : public LinkNode<LeakTracker<T> > {
- public:
- LeakTracker() {
- instances()->Append(this);
- }
-
- ~LeakTracker() {
- this->RemoveFromList();
- }
-
- static void CheckForLeaks() {
- // Walk the allocation list and print each entry it contains.
- size_t count = 0;
-
- // Copy the first 3 leak allocation callstacks onto the stack.
- // This way if we hit the CHECK() in a release build, the leak
- // information will be available in mini-dump.
- const size_t kMaxStackTracesToCopyOntoStack = 3;
- StackTrace stacktraces[kMaxStackTracesToCopyOntoStack];
-
- for (LinkNode<LeakTracker<T> >* node = instances()->head();
- node != instances()->end();
- node = node->next()) {
- StackTrace& allocation_stack = node->value()->allocation_stack_;
-
- if (count < kMaxStackTracesToCopyOntoStack)
- stacktraces[count] = allocation_stack;
-
- ++count;
- if (LOG_IS_ON(ERROR)) {
- LOG_STREAM(ERROR) << "Leaked " << node << " which was allocated by:";
- allocation_stack.OutputToStream(&LOG_STREAM(ERROR));
- }
- }
-
- CHECK_EQ(0u, count);
-
- // Hack to keep |stacktraces| and |count| alive (so compiler
- // doesn't optimize it out, and it will appear in mini-dumps).
- if (count == 0x1234) {
- for (size_t i = 0; i < kMaxStackTracesToCopyOntoStack; ++i)
- stacktraces[i].Print();
- }
- }
-
- static int NumLiveInstances() {
- // Walk the allocation list and count how many entries it has.
- int count = 0;
- for (LinkNode<LeakTracker<T> >* node = instances()->head();
- node != instances()->end();
- node = node->next()) {
- ++count;
- }
- return count;
- }
-
- private:
- // Each specialization of LeakTracker gets its own static storage.
- static LinkedList<LeakTracker<T> >* instances() {
- static LinkedList<LeakTracker<T> > list;
- return &list;
- }
-
- StackTrace allocation_stack_;
-};
-
-#endif // ENABLE_LEAK_TRACKER
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_LEAK_TRACKER_H_
diff --git a/base/debug/proc_maps_linux.cc b/base/debug/proc_maps_linux.cc
deleted file mode 100644
index 1a9476f..0000000
--- a/base/debug/proc_maps_linux.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/proc_maps_linux.h"
-
-#include <fcntl.h>
-#include <stddef.h>
-
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/strings/string_split.h"
-#include "build_config.h"
-
-#if defined(OS_LINUX) || defined(OS_ANDROID)
-#include <inttypes.h>
-#endif
-
-#if defined(OS_ANDROID) && !defined(__LP64__)
-// In 32-bit mode, Bionic's inttypes.h defines PRI/SCNxPTR as an
-// unsigned long int, which is incompatible with Bionic's stdint.h
-// defining uintptr_t as an unsigned int:
-// https://code.google.com/p/android/issues/detail?id=57218
-#undef SCNxPTR
-#define SCNxPTR "x"
-#endif
-
-namespace base {
-namespace debug {
-
-// Scans |proc_maps| starting from |pos| returning true if the gate VMA was
-// found, otherwise returns false.
-static bool ContainsGateVMA(std::string* proc_maps, size_t pos) {
-#if defined(ARCH_CPU_ARM_FAMILY)
- // The gate VMA on ARM kernels is the interrupt vectors page.
- return proc_maps->find(" [vectors]\n", pos) != std::string::npos;
-#elif defined(ARCH_CPU_X86_64)
- // The gate VMA on x86 64-bit kernels is the virtual system call page.
- return proc_maps->find(" [vsyscall]\n", pos) != std::string::npos;
-#else
- // Otherwise assume there is no gate VMA in which case we shouldn't
- // get duplicate entires.
- return false;
-#endif
-}
-
-bool ReadProcMaps(std::string* proc_maps) {
- // seq_file only writes out a page-sized amount on each call. Refer to header
- // file for details.
- const long kReadSize = sysconf(_SC_PAGESIZE);
-
- base::ScopedFD fd(HANDLE_EINTR(open("/proc/self/maps", O_RDONLY)));
- if (!fd.is_valid()) {
- DPLOG(ERROR) << "Couldn't open /proc/self/maps";
- return false;
- }
- proc_maps->clear();
-
- while (true) {
- // To avoid a copy, resize |proc_maps| so read() can write directly into it.
- // Compute |buffer| afterwards since resize() may reallocate.
- size_t pos = proc_maps->size();
- proc_maps->resize(pos + kReadSize);
- void* buffer = &(*proc_maps)[pos];
-
- ssize_t bytes_read = HANDLE_EINTR(read(fd.get(), buffer, kReadSize));
- if (bytes_read < 0) {
- DPLOG(ERROR) << "Couldn't read /proc/self/maps";
- proc_maps->clear();
- return false;
- }
-
- // ... and don't forget to trim off excess bytes.
- proc_maps->resize(pos + bytes_read);
-
- if (bytes_read == 0)
- break;
-
- // The gate VMA is handled as a special case after seq_file has finished
- // iterating through all entries in the virtual memory table.
- //
- // Unfortunately, if additional entries are added at this point in time
- // seq_file gets confused and the next call to read() will return duplicate
- // entries including the gate VMA again.
- //
- // Avoid this by searching for the gate VMA and breaking early.
- if (ContainsGateVMA(proc_maps, pos))
- break;
- }
-
- return true;
-}
-
-bool ParseProcMaps(const std::string& input,
- std::vector<MappedMemoryRegion>* regions_out) {
- CHECK(regions_out);
- std::vector<MappedMemoryRegion> regions;
-
- // This isn't async safe nor terribly efficient, but it doesn't need to be at
- // this point in time.
- std::vector<std::string> lines = SplitString(
- input, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-
- for (size_t i = 0; i < lines.size(); ++i) {
- // Due to splitting on '\n' the last line should be empty.
- if (i == lines.size() - 1) {
- if (!lines[i].empty()) {
- DLOG(WARNING) << "Last line not empty";
- return false;
- }
- break;
- }
-
- MappedMemoryRegion region;
- const char* line = lines[i].c_str();
- char permissions[5] = {'\0'}; // Ensure NUL-terminated string.
- uint8_t dev_major = 0;
- uint8_t dev_minor = 0;
- long inode = 0;
- int path_index = 0;
-
- // Sample format from man 5 proc:
- //
- // address perms offset dev inode pathname
- // 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm
- //
- // The final %n term captures the offset in the input string, which is used
- // to determine the path name. It *does not* increment the return value.
- // Refer to man 3 sscanf for details.
- if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4c %llx %hhx:%hhx %ld %n",
- ®ion.start, ®ion.end, permissions, ®ion.offset,
- &dev_major, &dev_minor, &inode, &path_index) < 7) {
- DPLOG(WARNING) << "sscanf failed for line: " << line;
- return false;
- }
-
- region.permissions = 0;
-
- if (permissions[0] == 'r')
- region.permissions |= MappedMemoryRegion::READ;
- else if (permissions[0] != '-')
- return false;
-
- if (permissions[1] == 'w')
- region.permissions |= MappedMemoryRegion::WRITE;
- else if (permissions[1] != '-')
- return false;
-
- if (permissions[2] == 'x')
- region.permissions |= MappedMemoryRegion::EXECUTE;
- else if (permissions[2] != '-')
- return false;
-
- if (permissions[3] == 'p')
- region.permissions |= MappedMemoryRegion::PRIVATE;
- else if (permissions[3] != 's' && permissions[3] != 'S') // Shared memory.
- return false;
-
- // Pushing then assigning saves us a string copy.
- regions.push_back(region);
- regions.back().path.assign(line + path_index);
- }
-
- regions_out->swap(regions);
- return true;
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/proc_maps_linux.h b/base/debug/proc_maps_linux.h
deleted file mode 100644
index f5f8a59..0000000
--- a/base/debug/proc_maps_linux.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_DEBUG_PROC_MAPS_LINUX_H_
-#define BASE_DEBUG_PROC_MAPS_LINUX_H_
-
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include "base/base_export.h"
-
-namespace base {
-namespace debug {
-
-// Describes a region of mapped memory and the path of the file mapped.
-struct MappedMemoryRegion {
- enum Permission {
- READ = 1 << 0,
- WRITE = 1 << 1,
- EXECUTE = 1 << 2,
- PRIVATE = 1 << 3, // If set, region is private, otherwise it is shared.
- };
-
- // The address range [start,end) of mapped memory.
- uintptr_t start;
- uintptr_t end;
-
- // Byte offset into |path| of the range mapped into memory.
- unsigned long long offset;
-
- // Image base, if this mapping corresponds to an ELF image.
- uintptr_t base;
-
- // Bitmask of read/write/execute/private/shared permissions.
- uint8_t permissions;
-
- // Name of the file mapped into memory.
- //
- // NOTE: path names aren't guaranteed to point at valid files. For example,
- // "[heap]" and "[stack]" are used to represent the location of the process'
- // heap and stack, respectively.
- std::string path;
-};
-
-// Reads the data from /proc/self/maps and stores the result in |proc_maps|.
-// Returns true if successful, false otherwise.
-//
-// There is *NO* guarantee that the resulting contents will be free of
-// duplicates or even contain valid entries by time the method returns.
-//
-//
-// THE GORY DETAILS
-//
-// Did you know it's next-to-impossible to atomically read the whole contents
-// of /proc/<pid>/maps? You would think that if we passed in a large-enough
-// buffer to read() that It Should Just Work(tm), but sadly that's not the case.
-//
-// Linux's procfs uses seq_file [1] for handling iteration, text formatting,
-// and dealing with resulting data that is larger than the size of a page. That
-// last bit is especially important because it means that seq_file will never
-// return more than the size of a page in a single call to read().
-//
-// Unfortunately for a program like Chrome the size of /proc/self/maps is
-// larger than the size of page so we're forced to call read() multiple times.
-// If the virtual memory table changed in any way between calls to read() (e.g.,
-// a different thread calling mprotect()), it can make seq_file generate
-// duplicate entries or skip entries.
-//
-// Even if seq_file was changed to keep flushing the contents of its page-sized
-// buffer to the usermode buffer inside a single call to read(), it has to
-// release its lock on the virtual memory table to handle page faults while
-// copying data to usermode. This puts us in the same situation where the table
-// can change while we're copying data.
-//
-// Alternatives such as fork()-and-suspend-the-parent-while-child-reads were
-// attempted, but they present more subtle problems than it's worth. Depending
-// on your use case your best bet may be to read /proc/<pid>/maps prior to
-// starting other threads.
-//
-// [1] http://kernelnewbies.org/Documents/SeqFileHowTo
-BASE_EXPORT bool ReadProcMaps(std::string* proc_maps);
-
-// Parses /proc/<pid>/maps input data and stores in |regions|. Returns true
-// and updates |regions| if and only if all of |input| was successfully parsed.
-BASE_EXPORT bool ParseProcMaps(const std::string& input,
- std::vector<MappedMemoryRegion>* regions);
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_PROC_MAPS_LINUX_H_
diff --git a/base/debug/profiler.cc b/base/debug/profiler.cc
deleted file mode 100644
index 82e5229..0000000
--- a/base/debug/profiler.cc
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/profiler.h"
-
-#include <string>
-
-#include "base/process/process_handle.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "build_config.h"
-
-#if defined(OS_WIN)
-#include "base/win/current_module.h"
-#include "base/win/pe_image.h"
-#endif // defined(OS_WIN)
-
-namespace base {
-namespace debug {
-
-void StartProfiling(const std::string& name) {
-}
-
-void StopProfiling() {
-}
-
-void FlushProfiling() {
-}
-
-bool BeingProfiled() {
- return false;
-}
-
-void RestartProfilingAfterFork() {
-}
-
-bool IsProfilingSupported() {
- return false;
-}
-
-#if !defined(OS_WIN)
-
-ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
- return nullptr;
-}
-
-DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
- return nullptr;
-}
-
-AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
- return nullptr;
-}
-
-MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
- return nullptr;
-}
-
-#else // defined(OS_WIN)
-
-namespace {
-
-struct FunctionSearchContext {
- const char* name;
- FARPROC function;
-};
-
-// Callback function to PEImage::EnumImportChunks.
-bool FindResolutionFunctionInImports(
- const base::win::PEImage &image, const char* module_name,
- PIMAGE_THUNK_DATA unused_name_table, PIMAGE_THUNK_DATA import_address_table,
- PVOID cookie) {
- FunctionSearchContext* context =
- reinterpret_cast<FunctionSearchContext*>(cookie);
-
- DCHECK(context);
- DCHECK(!context->function);
-
- // Our import address table contains pointers to the functions we import
- // at this point. Let's retrieve the first such function and use it to
- // find the module this import was resolved to by the loader.
- const wchar_t* function_in_module =
- reinterpret_cast<const wchar_t*>(import_address_table->u1.Function);
-
- // Retrieve the module by a function in the module.
- const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
- GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
- HMODULE module = NULL;
- if (!::GetModuleHandleEx(kFlags, function_in_module, &module)) {
- // This can happen if someone IAT patches us to a thunk.
- return true;
- }
-
- // See whether this module exports the function we're looking for.
- FARPROC exported_func = ::GetProcAddress(module, context->name);
- if (exported_func != NULL) {
- // We found it, return the function and terminate the enumeration.
- context->function = exported_func;
- return false;
- }
-
- // Keep going.
- return true;
-}
-
-template <typename FunctionType>
-FunctionType FindFunctionInImports(const char* function_name) {
- base::win::PEImage image(CURRENT_MODULE());
-
- FunctionSearchContext ctx = { function_name, NULL };
- image.EnumImportChunks(FindResolutionFunctionInImports, &ctx);
-
- return reinterpret_cast<FunctionType>(ctx.function);
-}
-
-} // namespace
-
-ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
- return FindFunctionInImports<ReturnAddressLocationResolver>(
- "ResolveReturnAddressLocation");
-}
-
-DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
- return FindFunctionInImports<DynamicFunctionEntryHook>(
- "OnDynamicFunctionEntry");
-}
-
-AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
- return FindFunctionInImports<AddDynamicSymbol>(
- "AddDynamicSymbol");
-}
-
-MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
- return FindFunctionInImports<MoveDynamicSymbol>(
- "MoveDynamicSymbol");
-}
-
-#endif // defined(OS_WIN)
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/profiler.h b/base/debug/profiler.h
deleted file mode 100644
index f706a1a..0000000
--- a/base/debug/profiler.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_DEBUG_PROFILER_H_
-#define BASE_DEBUG_PROFILER_H_
-
-#include <stddef.h>
-
-#include <string>
-
-#include "base/base_export.h"
-
-// The Profiler functions allow usage of the underlying sampling based
-// profiler. If the application has not been built with the necessary
-// flags (-DENABLE_PROFILING and not -DNO_TCMALLOC) then these functions
-// are noops.
-namespace base {
-namespace debug {
-
-// Start profiling with the supplied name.
-// {pid} will be replaced by the process' pid and {count} will be replaced
-// by the count of the profile run (starts at 1 with each process).
-BASE_EXPORT void StartProfiling(const std::string& name);
-
-// Stop profiling and write out data.
-BASE_EXPORT void StopProfiling();
-
-// Force data to be written to file.
-BASE_EXPORT void FlushProfiling();
-
-// Returns true if process is being profiled.
-BASE_EXPORT bool BeingProfiled();
-
-// Reset profiling after a fork, which disables timers.
-BASE_EXPORT void RestartProfilingAfterFork();
-
-// Returns true iff this executable supports profiling.
-BASE_EXPORT bool IsProfilingSupported();
-
-// There's a class of profilers that use "return address swizzling" to get a
-// hook on function exits. This class of profilers uses some form of entry hook,
-// like e.g. binary instrumentation, or a compiler flag, that calls a hook each
-// time a function is invoked. The hook then switches the return address on the
-// stack for the address of an exit hook function, and pushes the original
-// return address to a shadow stack of some type. When in due course the CPU
-// executes a return to the exit hook, the exit hook will do whatever work it
-// does on function exit, then arrange to return to the original return address.
-// This class of profiler does not play well with programs that look at the
-// return address, as does e.g. V8. V8 uses the return address to certain
-// runtime functions to find the JIT code that called it, and from there finds
-// the V8 data structures associated to the JS function involved.
-// A return address resolution function is used to fix this. It allows such
-// programs to resolve a location on stack where a return address originally
-// resided, to the shadow stack location where the profiler stashed it.
-typedef uintptr_t (*ReturnAddressLocationResolver)(
- uintptr_t return_addr_location);
-
-// This type declaration must match V8's FunctionEntryHook.
-typedef void (*DynamicFunctionEntryHook)(uintptr_t function,
- uintptr_t return_addr_location);
-
-// The functions below here are to support profiling V8-generated code.
-// V8 has provisions for generating a call to an entry hook for newly generated
-// JIT code, and it can push symbol information on code generation and advise
-// when the garbage collector moves code. The functions declarations below here
-// make glue between V8's facilities and a profiler.
-
-// This type declaration must match V8's FunctionEntryHook.
-typedef void (*DynamicFunctionEntryHook)(uintptr_t function,
- uintptr_t return_addr_location);
-
-typedef void (*AddDynamicSymbol)(const void* address,
- size_t length,
- const char* name,
- size_t name_len);
-typedef void (*MoveDynamicSymbol)(const void* address, const void* new_address);
-
-
-// If this binary is instrumented and the instrumentation supplies a function
-// for each of those purposes, find and return the function in question.
-// Otherwise returns NULL.
-BASE_EXPORT ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc();
-BASE_EXPORT DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc();
-BASE_EXPORT AddDynamicSymbol GetProfilerAddDynamicSymbolFunc();
-BASE_EXPORT MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc();
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_PROFILER_H_
diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc
deleted file mode 100644
index 3a63dae..0000000
--- a/base/debug/stack_trace.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/stack_trace.h"
-
-#include <string.h>
-
-#include <algorithm>
-#include <sstream>
-
-#include "base/logging.h"
-#include "base/macros.h"
-
-namespace base {
-namespace debug {
-
-StackTrace::StackTrace() : StackTrace(arraysize(trace_)) {}
-
-StackTrace::StackTrace(const void* const* trace, size_t count) {
- count = std::min(count, arraysize(trace_));
- if (count)
- memcpy(trace_, trace, count * sizeof(trace_[0]));
- count_ = count;
-}
-
-const void *const *StackTrace::Addresses(size_t* count) const {
- *count = count_;
- if (count_)
- return trace_;
- return nullptr;
-}
-
-std::string StackTrace::ToString() const {
- std::stringstream stream;
-#if !defined(__UCLIBC__) && !defined(_AIX)
- OutputToStream(&stream);
-#endif
- return stream.str();
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/stack_trace.h b/base/debug/stack_trace.h
deleted file mode 100644
index 33023fe..0000000
--- a/base/debug/stack_trace.h
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_DEBUG_STACK_TRACE_H_
-#define BASE_DEBUG_STACK_TRACE_H_
-
-#include <stddef.h>
-
-#include <iosfwd>
-#include <string>
-
-#include "base/base_export.h"
-#include "base/macros.h"
-#include "build_config.h"
-
-#if defined(OS_POSIX)
-#include <unistd.h>
-#endif
-
-#if defined(OS_WIN)
-struct _EXCEPTION_POINTERS;
-struct _CONTEXT;
-#endif
-
-namespace base {
-namespace debug {
-
-// Enables stack dump to console output on exception and signals.
-// When enabled, the process will quit immediately. This is meant to be used in
-// unit_tests only! This is not thread-safe: only call from main thread.
-// In sandboxed processes, this has to be called before the sandbox is turned
-// on.
-// Calling this function on Linux opens /proc/self/maps and caches its
-// contents. In non-official builds, this function also opens the object files
-// that are loaded in memory and caches their file descriptors (this cannot be
-// done in official builds because it has security implications).
-BASE_EXPORT bool EnableInProcessStackDumping();
-
-#if defined(OS_POSIX)
-BASE_EXPORT void SetStackDumpFirstChanceCallback(bool (*handler)(int,
- void*,
- void*));
-#endif
-
-// A stacktrace can be helpful in debugging. For example, you can include a
-// stacktrace member in a object (probably around #ifndef NDEBUG) so that you
-// can later see where the given object was created from.
-class BASE_EXPORT StackTrace {
- public:
- // Creates a stacktrace from the current location.
- StackTrace();
-
- // Creates a stacktrace from the current location, of up to |count| entries.
- // |count| will be limited to at most |kMaxTraces|.
- explicit StackTrace(size_t count);
-
- // Creates a stacktrace from an existing array of instruction
- // pointers (such as returned by Addresses()). |count| will be
- // limited to at most |kMaxTraces|.
- StackTrace(const void* const* trace, size_t count);
-
-#if defined(OS_WIN)
- // Creates a stacktrace for an exception.
- // Note: this function will throw an import not found (StackWalk64) exception
- // on system without dbghelp 5.1.
- StackTrace(_EXCEPTION_POINTERS* exception_pointers);
- StackTrace(const _CONTEXT* context);
-#endif
-
- // Copying and assignment are allowed with the default functions.
-
- // Gets an array of instruction pointer values. |*count| will be set to the
- // number of elements in the returned array.
- const void* const* Addresses(size_t* count) const;
-
- // Prints the stack trace to stderr.
- void Print() const;
-
-#if !defined(__UCLIBC__) & !defined(_AIX)
- // Resolves backtrace to symbols and write to stream.
- void OutputToStream(std::ostream* os) const;
-#endif
-
- // Resolves backtrace to symbols and returns as string.
- std::string ToString() const;
-
- private:
-#if defined(OS_WIN)
- void InitTrace(const _CONTEXT* context_record);
-#endif
-
- // From http://msdn.microsoft.com/en-us/library/bb204633.aspx,
- // the sum of FramesToSkip and FramesToCapture must be less than 63,
- // so set it to 62. Even if on POSIX it could be a larger value, it usually
- // doesn't give much more information.
- static const int kMaxTraces = 62;
-
- void* trace_[kMaxTraces];
-
- // The number of valid frames in |trace_|.
- size_t count_;
-};
-
-namespace internal {
-
-#if defined(OS_POSIX) && !defined(OS_ANDROID)
-// POSIX doesn't define any async-signal safe function for converting
-// an integer to ASCII. We'll have to define our own version.
-// itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
-// conversion was successful or NULL otherwise. It never writes more than "sz"
-// bytes. Output will be truncated as needed, and a NUL character is always
-// appended.
-BASE_EXPORT char *itoa_r(intptr_t i,
- char *buf,
- size_t sz,
- int base,
- size_t padding);
-#endif // defined(OS_POSIX) && !defined(OS_ANDROID)
-
-} // namespace internal
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_STACK_TRACE_H_
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc
deleted file mode 100644
index c67fd62..0000000
--- a/base/debug/stack_trace_posix.cc
+++ /dev/null
@@ -1,887 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/stack_trace.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <map>
-#include <memory>
-#include <ostream>
-#include <string>
-#include <vector>
-
-#if !defined(USE_SYMBOLIZE)
-#include <cxxabi.h>
-#endif
-#if !defined(__UCLIBC__) && !defined(_AIX)
-#include <execinfo.h>
-#endif
-
-#if defined(OS_MACOSX)
-#include <AvailabilityMacros.h>
-#endif
-
-#if defined(OS_LINUX)
-#include "base/debug/proc_maps_linux.h"
-#endif
-
-#include "base/debug/debugger.h"
-#include "base/files/scoped_file.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/free_deleter.h"
-#include "base/memory/singleton.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/strings/string_number_conversions.h"
-#include "build_config.h"
-
-#if defined(USE_SYMBOLIZE)
-#include "base/third_party/symbolize/symbolize.h"
-#endif
-
-namespace base {
-namespace debug {
-
-namespace {
-
-volatile sig_atomic_t in_signal_handler = 0;
-
-bool (*try_handle_signal)(int, void*, void*) = nullptr;
-
-#if !defined(USE_SYMBOLIZE)
-// The prefix used for mangled symbols, per the Itanium C++ ABI:
-// http://www.codesourcery.com/cxx-abi/abi.html#mangling
-const char kMangledSymbolPrefix[] = "_Z";
-
-// Characters that can be used for symbols, generated by Ruby:
-// (('a'..'z').to_a+('A'..'Z').to_a+('0'..'9').to_a + ['_']).join
-const char kSymbolCharacters[] =
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
-#endif // !defined(USE_SYMBOLIZE)
-
-#if !defined(USE_SYMBOLIZE)
-// Demangles C++ symbols in the given text. Example:
-//
-// "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]"
-// =>
-// "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]"
-void DemangleSymbols(std::string* text) {
- // Note: code in this function is NOT async-signal safe (std::string uses
- // malloc internally).
-
-#if !defined(__UCLIBC__) && !defined(_AIX)
- std::string::size_type search_from = 0;
- while (search_from < text->size()) {
- // Look for the start of a mangled symbol, from search_from.
- std::string::size_type mangled_start =
- text->find(kMangledSymbolPrefix, search_from);
- if (mangled_start == std::string::npos) {
- break; // Mangled symbol not found.
- }
-
- // Look for the end of the mangled symbol.
- std::string::size_type mangled_end =
- text->find_first_not_of(kSymbolCharacters, mangled_start);
- if (mangled_end == std::string::npos) {
- mangled_end = text->size();
- }
- std::string mangled_symbol =
- text->substr(mangled_start, mangled_end - mangled_start);
-
- // Try to demangle the mangled symbol candidate.
- int status = 0;
- std::unique_ptr<char, base::FreeDeleter> demangled_symbol(
- abi::__cxa_demangle(mangled_symbol.c_str(), nullptr, 0, &status));
- if (status == 0) { // Demangling is successful.
- // Remove the mangled symbol.
- text->erase(mangled_start, mangled_end - mangled_start);
- // Insert the demangled symbol.
- text->insert(mangled_start, demangled_symbol.get());
- // Next time, we'll start right after the demangled symbol we inserted.
- search_from = mangled_start + strlen(demangled_symbol.get());
- } else {
- // Failed to demangle. Retry after the "_Z" we just found.
- search_from = mangled_start + 2;
- }
- }
-#endif // !defined(__UCLIBC__) && !defined(_AIX)
-}
-#endif // !defined(USE_SYMBOLIZE)
-
-class BacktraceOutputHandler {
- public:
- virtual void HandleOutput(const char* output) = 0;
-
- protected:
- virtual ~BacktraceOutputHandler() = default;
-};
-
-#if !defined(__UCLIBC__) && !defined(_AIX)
-void OutputPointer(void* pointer, BacktraceOutputHandler* handler) {
- // This should be more than enough to store a 64-bit number in hex:
- // 16 hex digits + 1 for null-terminator.
- char buf[17] = { '\0' };
- handler->HandleOutput("0x");
- internal::itoa_r(reinterpret_cast<intptr_t>(pointer),
- buf, sizeof(buf), 16, 12);
- handler->HandleOutput(buf);
-}
-
-#if defined(USE_SYMBOLIZE)
-void OutputFrameId(intptr_t frame_id, BacktraceOutputHandler* handler) {
- // Max unsigned 64-bit number in decimal has 20 digits (18446744073709551615).
- // Hence, 30 digits should be more than enough to represent it in decimal
- // (including the null-terminator).
- char buf[30] = { '\0' };
- handler->HandleOutput("#");
- internal::itoa_r(frame_id, buf, sizeof(buf), 10, 1);
- handler->HandleOutput(buf);
-}
-#endif // defined(USE_SYMBOLIZE)
-
-void ProcessBacktrace(void *const *trace,
- size_t size,
- BacktraceOutputHandler* handler) {
- // NOTE: This code MUST be async-signal safe (it's used by in-process
- // stack dumping signal handler). NO malloc or stdio is allowed here.
-
-#if defined(USE_SYMBOLIZE)
- for (size_t i = 0; i < size; ++i) {
- OutputFrameId(i, handler);
- handler->HandleOutput(" ");
- OutputPointer(trace[i], handler);
- handler->HandleOutput(" ");
-
- char buf[1024] = { '\0' };
-
- // Subtract by one as return address of function may be in the next
- // function when a function is annotated as noreturn.
- void* address = static_cast<char*>(trace[i]) - 1;
- if (google::Symbolize(address, buf, sizeof(buf)))
- handler->HandleOutput(buf);
- else
- handler->HandleOutput("<unknown>");
-
- handler->HandleOutput("\n");
- }
-#else
- bool printed = false;
-
- // Below part is async-signal unsafe (uses malloc), so execute it only
- // when we are not executing the signal handler.
- if (in_signal_handler == 0) {
- std::unique_ptr<char*, FreeDeleter> trace_symbols(
- backtrace_symbols(trace, size));
- if (trace_symbols.get()) {
- for (size_t i = 0; i < size; ++i) {
- std::string trace_symbol = trace_symbols.get()[i];
- DemangleSymbols(&trace_symbol);
- handler->HandleOutput(trace_symbol.c_str());
- handler->HandleOutput("\n");
- }
-
- printed = true;
- }
- }
-
- if (!printed) {
- for (size_t i = 0; i < size; ++i) {
- handler->HandleOutput(" [");
- OutputPointer(trace[i], handler);
- handler->HandleOutput("]\n");
- }
- }
-#endif // defined(USE_SYMBOLIZE)
-}
-#endif // !defined(__UCLIBC__) && !defined(_AIX)
-
-void PrintToStderr(const char* output) {
- // NOTE: This code MUST be async-signal safe (it's used by in-process
- // stack dumping signal handler). NO malloc or stdio is allowed here.
- ignore_result(HANDLE_EINTR(write(STDERR_FILENO, output, strlen(output))));
-}
-
-void StackDumpSignalHandler(int signal, siginfo_t* info, void* void_context) {
- // NOTE: This code MUST be async-signal safe.
- // NO malloc or stdio is allowed here.
-
- // Give a registered callback a chance to recover from this signal
- //
- // V8 uses guard regions to guarantee memory safety in WebAssembly. This means
- // some signals might be expected if they originate from Wasm code while
- // accessing the guard region. We give V8 the chance to handle and recover
- // from these signals first.
- if (try_handle_signal != nullptr &&
- try_handle_signal(signal, info, void_context)) {
- // The first chance handler took care of this. The SA_RESETHAND flag
- // replaced this signal handler upon entry, but we want to stay
- // installed. Thus, we reinstall ourselves before returning.
- struct sigaction action;
- memset(&action, 0, sizeof(action));
- action.sa_flags = SA_RESETHAND | SA_SIGINFO;
- action.sa_sigaction = &StackDumpSignalHandler;
- sigemptyset(&action.sa_mask);
-
- sigaction(signal, &action, nullptr);
- return;
- }
-
-// Do not take the "in signal handler" code path on Mac in a DCHECK-enabled
-// build, as this prevents seeing a useful (symbolized) stack trace on a crash
-// or DCHECK() failure. While it may not be fully safe to run the stack symbol
-// printing code, in practice it's better to provide meaningful stack traces -
-// and the risk is low given we're likely crashing already.
-#if !defined(OS_MACOSX) || !DCHECK_IS_ON()
- // Record the fact that we are in the signal handler now, so that the rest
- // of StackTrace can behave in an async-signal-safe manner.
- in_signal_handler = 1;
-#endif
-
- if (BeingDebugged())
- BreakDebugger();
-
- PrintToStderr("Received signal ");
- char buf[1024] = { 0 };
- internal::itoa_r(signal, buf, sizeof(buf), 10, 0);
- PrintToStderr(buf);
- if (signal == SIGBUS) {
- if (info->si_code == BUS_ADRALN)
- PrintToStderr(" BUS_ADRALN ");
- else if (info->si_code == BUS_ADRERR)
- PrintToStderr(" BUS_ADRERR ");
- else if (info->si_code == BUS_OBJERR)
- PrintToStderr(" BUS_OBJERR ");
- else
- PrintToStderr(" <unknown> ");
- } else if (signal == SIGFPE) {
- if (info->si_code == FPE_FLTDIV)
- PrintToStderr(" FPE_FLTDIV ");
- else if (info->si_code == FPE_FLTINV)
- PrintToStderr(" FPE_FLTINV ");
- else if (info->si_code == FPE_FLTOVF)
- PrintToStderr(" FPE_FLTOVF ");
- else if (info->si_code == FPE_FLTRES)
- PrintToStderr(" FPE_FLTRES ");
- else if (info->si_code == FPE_FLTSUB)
- PrintToStderr(" FPE_FLTSUB ");
- else if (info->si_code == FPE_FLTUND)
- PrintToStderr(" FPE_FLTUND ");
- else if (info->si_code == FPE_INTDIV)
- PrintToStderr(" FPE_INTDIV ");
- else if (info->si_code == FPE_INTOVF)
- PrintToStderr(" FPE_INTOVF ");
- else
- PrintToStderr(" <unknown> ");
- } else if (signal == SIGILL) {
- if (info->si_code == ILL_BADSTK)
- PrintToStderr(" ILL_BADSTK ");
- else if (info->si_code == ILL_COPROC)
- PrintToStderr(" ILL_COPROC ");
- else if (info->si_code == ILL_ILLOPN)
- PrintToStderr(" ILL_ILLOPN ");
- else if (info->si_code == ILL_ILLADR)
- PrintToStderr(" ILL_ILLADR ");
- else if (info->si_code == ILL_ILLTRP)
- PrintToStderr(" ILL_ILLTRP ");
- else if (info->si_code == ILL_PRVOPC)
- PrintToStderr(" ILL_PRVOPC ");
- else if (info->si_code == ILL_PRVREG)
- PrintToStderr(" ILL_PRVREG ");
- else
- PrintToStderr(" <unknown> ");
- } else if (signal == SIGSEGV) {
- if (info->si_code == SEGV_MAPERR)
- PrintToStderr(" SEGV_MAPERR ");
- else if (info->si_code == SEGV_ACCERR)
- PrintToStderr(" SEGV_ACCERR ");
- else
- PrintToStderr(" <unknown> ");
- }
- if (signal == SIGBUS || signal == SIGFPE ||
- signal == SIGILL || signal == SIGSEGV) {
- internal::itoa_r(reinterpret_cast<intptr_t>(info->si_addr),
- buf, sizeof(buf), 16, 12);
- PrintToStderr(buf);
- }
- PrintToStderr("\n");
-
- debug::StackTrace().Print();
-
-#if defined(OS_LINUX)
-#if ARCH_CPU_X86_FAMILY
- ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context);
- const struct {
- const char* label;
- greg_t value;
- } registers[] = {
-#if ARCH_CPU_32_BITS
- { " gs: ", context->uc_mcontext.gregs[REG_GS] },
- { " fs: ", context->uc_mcontext.gregs[REG_FS] },
- { " es: ", context->uc_mcontext.gregs[REG_ES] },
- { " ds: ", context->uc_mcontext.gregs[REG_DS] },
- { " edi: ", context->uc_mcontext.gregs[REG_EDI] },
- { " esi: ", context->uc_mcontext.gregs[REG_ESI] },
- { " ebp: ", context->uc_mcontext.gregs[REG_EBP] },
- { " esp: ", context->uc_mcontext.gregs[REG_ESP] },
- { " ebx: ", context->uc_mcontext.gregs[REG_EBX] },
- { " edx: ", context->uc_mcontext.gregs[REG_EDX] },
- { " ecx: ", context->uc_mcontext.gregs[REG_ECX] },
- { " eax: ", context->uc_mcontext.gregs[REG_EAX] },
- { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
- { " err: ", context->uc_mcontext.gregs[REG_ERR] },
- { " ip: ", context->uc_mcontext.gregs[REG_EIP] },
- { " cs: ", context->uc_mcontext.gregs[REG_CS] },
- { " efl: ", context->uc_mcontext.gregs[REG_EFL] },
- { " usp: ", context->uc_mcontext.gregs[REG_UESP] },
- { " ss: ", context->uc_mcontext.gregs[REG_SS] },
-#elif ARCH_CPU_64_BITS
- { " r8: ", context->uc_mcontext.gregs[REG_R8] },
- { " r9: ", context->uc_mcontext.gregs[REG_R9] },
- { " r10: ", context->uc_mcontext.gregs[REG_R10] },
- { " r11: ", context->uc_mcontext.gregs[REG_R11] },
- { " r12: ", context->uc_mcontext.gregs[REG_R12] },
- { " r13: ", context->uc_mcontext.gregs[REG_R13] },
- { " r14: ", context->uc_mcontext.gregs[REG_R14] },
- { " r15: ", context->uc_mcontext.gregs[REG_R15] },
- { " di: ", context->uc_mcontext.gregs[REG_RDI] },
- { " si: ", context->uc_mcontext.gregs[REG_RSI] },
- { " bp: ", context->uc_mcontext.gregs[REG_RBP] },
- { " bx: ", context->uc_mcontext.gregs[REG_RBX] },
- { " dx: ", context->uc_mcontext.gregs[REG_RDX] },
- { " ax: ", context->uc_mcontext.gregs[REG_RAX] },
- { " cx: ", context->uc_mcontext.gregs[REG_RCX] },
- { " sp: ", context->uc_mcontext.gregs[REG_RSP] },
- { " ip: ", context->uc_mcontext.gregs[REG_RIP] },
- { " efl: ", context->uc_mcontext.gregs[REG_EFL] },
- { " cgf: ", context->uc_mcontext.gregs[REG_CSGSFS] },
- { " erf: ", context->uc_mcontext.gregs[REG_ERR] },
- { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
- { " msk: ", context->uc_mcontext.gregs[REG_OLDMASK] },
- { " cr2: ", context->uc_mcontext.gregs[REG_CR2] },
-#endif // ARCH_CPU_32_BITS
- };
-
-#if ARCH_CPU_32_BITS
- const int kRegisterPadding = 8;
-#elif ARCH_CPU_64_BITS
- const int kRegisterPadding = 16;
-#endif
-
- for (size_t i = 0; i < arraysize(registers); i++) {
- PrintToStderr(registers[i].label);
- internal::itoa_r(registers[i].value, buf, sizeof(buf),
- 16, kRegisterPadding);
- PrintToStderr(buf);
-
- if ((i + 1) % 4 == 0)
- PrintToStderr("\n");
- }
- PrintToStderr("\n");
-#endif // ARCH_CPU_X86_FAMILY
-#endif // defined(OS_LINUX)
-
- PrintToStderr("[end of stack trace]\n");
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- if (::signal(signal, SIG_DFL) == SIG_ERR)
- _exit(1);
-#else
- // Non-Mac OSes should probably reraise the signal as well, but the Linux
- // sandbox tests break on CrOS devices.
- // https://code.google.com/p/chromium/issues/detail?id=551681
- PrintToStderr("Calling _exit(1). Core file will not be generated.\n");
- _exit(1);
-#endif // defined(OS_MACOSX) && !defined(OS_IOS)
-}
-
-class PrintBacktraceOutputHandler : public BacktraceOutputHandler {
- public:
- PrintBacktraceOutputHandler() = default;
-
- void HandleOutput(const char* output) override {
- // NOTE: This code MUST be async-signal safe (it's used by in-process
- // stack dumping signal handler). NO malloc or stdio is allowed here.
- PrintToStderr(output);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PrintBacktraceOutputHandler);
-};
-
-class StreamBacktraceOutputHandler : public BacktraceOutputHandler {
- public:
- explicit StreamBacktraceOutputHandler(std::ostream* os) : os_(os) {
- }
-
- void HandleOutput(const char* output) override { (*os_) << output; }
-
- private:
- std::ostream* os_;
-
- DISALLOW_COPY_AND_ASSIGN(StreamBacktraceOutputHandler);
-};
-
-void WarmUpBacktrace() {
- // Warm up stack trace infrastructure. It turns out that on the first
- // call glibc initializes some internal data structures using pthread_once,
- // and even backtrace() can call malloc(), leading to hangs.
- //
- // Example stack trace snippet (with tcmalloc):
- //
- // #8 0x0000000000a173b5 in tc_malloc
- // at ./third_party/tcmalloc/chromium/src/debugallocation.cc:1161
- // #9 0x00007ffff7de7900 in _dl_map_object_deps at dl-deps.c:517
- // #10 0x00007ffff7ded8a9 in dl_open_worker at dl-open.c:262
- // #11 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
- // #12 0x00007ffff7ded31a in _dl_open (file=0x7ffff625e298 "libgcc_s.so.1")
- // at dl-open.c:639
- // #13 0x00007ffff6215602 in do_dlopen at dl-libc.c:89
- // #14 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
- // #15 0x00007ffff62156c4 in dlerror_run at dl-libc.c:48
- // #16 __GI___libc_dlopen_mode at dl-libc.c:165
- // #17 0x00007ffff61ef8f5 in init
- // at ../sysdeps/x86_64/../ia64/backtrace.c:53
- // #18 0x00007ffff6aad400 in pthread_once
- // at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:104
- // #19 0x00007ffff61efa14 in __GI___backtrace
- // at ../sysdeps/x86_64/../ia64/backtrace.c:104
- // #20 0x0000000000752a54 in base::debug::StackTrace::StackTrace
- // at base/debug/stack_trace_posix.cc:175
- // #21 0x00000000007a4ae5 in
- // base::(anonymous namespace)::StackDumpSignalHandler
- // at base/process_util_posix.cc:172
- // #22 <signal handler called>
- StackTrace stack_trace;
-}
-
-#if defined(USE_SYMBOLIZE)
-
-// class SandboxSymbolizeHelper.
-//
-// The purpose of this class is to prepare and install a "file open" callback
-// needed by the stack trace symbolization code
-// (base/third_party/symbolize/symbolize.h) so that it can function properly
-// in a sandboxed process. The caveat is that this class must be instantiated
-// before the sandboxing is enabled so that it can get the chance to open all
-// the object files that are loaded in the virtual address space of the current
-// process.
-class SandboxSymbolizeHelper {
- public:
- // Returns the singleton instance.
- static SandboxSymbolizeHelper* GetInstance() {
- return Singleton<SandboxSymbolizeHelper,
- LeakySingletonTraits<SandboxSymbolizeHelper>>::get();
- }
-
- private:
- friend struct DefaultSingletonTraits<SandboxSymbolizeHelper>;
-
- SandboxSymbolizeHelper()
- : is_initialized_(false) {
- Init();
- }
-
- ~SandboxSymbolizeHelper() {
- UnregisterCallback();
- CloseObjectFiles();
- }
-
- // Returns a O_RDONLY file descriptor for |file_path| if it was opened
- // successfully during the initialization. The file is repositioned at
- // offset 0.
- // IMPORTANT: This function must be async-signal-safe because it can be
- // called from a signal handler (symbolizing stack frames for a crash).
- int GetFileDescriptor(const char* file_path) {
- int fd = -1;
-
-#if !defined(OFFICIAL_BUILD)
- if (file_path) {
- // The assumption here is that iterating over std::map<std::string, int>
- // using a const_iterator does not allocate dynamic memory, hense it is
- // async-signal-safe.
- std::map<std::string, int>::const_iterator it;
- for (it = modules_.begin(); it != modules_.end(); ++it) {
- if (strcmp((it->first).c_str(), file_path) == 0) {
- // POSIX.1-2004 requires an implementation to guarantee that dup()
- // is async-signal-safe.
- fd = HANDLE_EINTR(dup(it->second));
- break;
- }
- }
- // POSIX.1-2004 requires an implementation to guarantee that lseek()
- // is async-signal-safe.
- if (fd >= 0 && lseek(fd, 0, SEEK_SET) < 0) {
- // Failed to seek.
- fd = -1;
- }
- }
-#endif // !defined(OFFICIAL_BUILD)
-
- return fd;
- }
-
- // Searches for the object file (from /proc/self/maps) that contains
- // the specified pc. If found, sets |start_address| to the start address
- // of where this object file is mapped in memory, sets the module base
- // address into |base_address|, copies the object file name into
- // |out_file_name|, and attempts to open the object file. If the object
- // file is opened successfully, returns the file descriptor. Otherwise,
- // returns -1. |out_file_name_size| is the size of the file name buffer
- // (including the null terminator).
- // IMPORTANT: This function must be async-signal-safe because it can be
- // called from a signal handler (symbolizing stack frames for a crash).
- static int OpenObjectFileContainingPc(uint64_t pc, uint64_t& start_address,
- uint64_t& base_address, char* file_path,
- int file_path_size) {
- // This method can only be called after the singleton is instantiated.
- // This is ensured by the following facts:
- // * This is the only static method in this class, it is private, and
- // the class has no friends (except for the DefaultSingletonTraits).
- // The compiler guarantees that it can only be called after the
- // singleton is instantiated.
- // * This method is used as a callback for the stack tracing code and
- // the callback registration is done in the constructor, so logically
- // it cannot be called before the singleton is created.
- SandboxSymbolizeHelper* instance = GetInstance();
-
- // The assumption here is that iterating over
- // std::vector<MappedMemoryRegion> using a const_iterator does not allocate
- // dynamic memory, hence it is async-signal-safe.
- for (const MappedMemoryRegion& region : instance->regions_) {
- if (region.start <= pc && pc < region.end) {
- start_address = region.start;
- base_address = region.base;
- if (file_path && file_path_size > 0) {
- strncpy(file_path, region.path.c_str(), file_path_size);
- // Ensure null termination.
- file_path[file_path_size - 1] = '\0';
- }
- return instance->GetFileDescriptor(region.path.c_str());
- }
- }
- return -1;
- }
-
- // Set the base address for each memory region by reading ELF headers in
- // process memory.
- void SetBaseAddressesForMemoryRegions() {
- base::ScopedFD mem_fd(
- HANDLE_EINTR(open("/proc/self/mem", O_RDONLY | O_CLOEXEC)));
- if (!mem_fd.is_valid())
- return;
-
- auto safe_memcpy = [&mem_fd](void* dst, uintptr_t src, size_t size) {
- return HANDLE_EINTR(pread(mem_fd.get(), dst, size, src)) == ssize_t(size);
- };
-
- uintptr_t cur_base = 0;
- for (auto& r : regions_) {
- ElfW(Ehdr) ehdr;
- static_assert(SELFMAG <= sizeof(ElfW(Ehdr)), "SELFMAG too large");
- if ((r.permissions & MappedMemoryRegion::READ) &&
- safe_memcpy(&ehdr, r.start, sizeof(ElfW(Ehdr))) &&
- memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {
- switch (ehdr.e_type) {
- case ET_EXEC:
- cur_base = 0;
- break;
- case ET_DYN:
- // Find the segment containing file offset 0. This will correspond
- // to the ELF header that we just read. Normally this will have
- // virtual address 0, but this is not guaranteed. We must subtract
- // the virtual address from the address where the ELF header was
- // mapped to get the base address.
- //
- // If we fail to find a segment for file offset 0, use the address
- // of the ELF header as the base address.
- cur_base = r.start;
- for (unsigned i = 0; i != ehdr.e_phnum; ++i) {
- ElfW(Phdr) phdr;
- if (safe_memcpy(&phdr, r.start + ehdr.e_phoff + i * sizeof(phdr),
- sizeof(phdr)) &&
- phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
- cur_base = r.start - phdr.p_vaddr;
- break;
- }
- }
- break;
- default:
- // ET_REL or ET_CORE. These aren't directly executable, so they
- // don't affect the base address.
- break;
- }
- }
-
- r.base = cur_base;
- }
- }
-
- // Parses /proc/self/maps in order to compile a list of all object file names
- // for the modules that are loaded in the current process.
- // Returns true on success.
- bool CacheMemoryRegions() {
- // Reads /proc/self/maps.
- std::string contents;
- if (!ReadProcMaps(&contents)) {
- LOG(ERROR) << "Failed to read /proc/self/maps";
- return false;
- }
-
- // Parses /proc/self/maps.
- if (!ParseProcMaps(contents, ®ions_)) {
- LOG(ERROR) << "Failed to parse the contents of /proc/self/maps";
- return false;
- }
-
- SetBaseAddressesForMemoryRegions();
-
- is_initialized_ = true;
- return true;
- }
-
- // Opens all object files and caches their file descriptors.
- void OpenSymbolFiles() {
- // Pre-opening and caching the file descriptors of all loaded modules is
- // not safe for production builds. Hence it is only done in non-official
- // builds. For more details, take a look at: http://crbug.com/341966.
-#if !defined(OFFICIAL_BUILD)
- // Open the object files for all read-only executable regions and cache
- // their file descriptors.
- std::vector<MappedMemoryRegion>::const_iterator it;
- for (it = regions_.begin(); it != regions_.end(); ++it) {
- const MappedMemoryRegion& region = *it;
- // Only interesed in read-only executable regions.
- if ((region.permissions & MappedMemoryRegion::READ) ==
- MappedMemoryRegion::READ &&
- (region.permissions & MappedMemoryRegion::WRITE) == 0 &&
- (region.permissions & MappedMemoryRegion::EXECUTE) ==
- MappedMemoryRegion::EXECUTE) {
- if (region.path.empty()) {
- // Skip regions with empty file names.
- continue;
- }
- if (region.path[0] == '[') {
- // Skip pseudo-paths, like [stack], [vdso], [heap], etc ...
- continue;
- }
- // Avoid duplicates.
- if (modules_.find(region.path) == modules_.end()) {
- int fd = open(region.path.c_str(), O_RDONLY | O_CLOEXEC);
- if (fd >= 0) {
- modules_.insert(std::make_pair(region.path, fd));
- } else {
- LOG(WARNING) << "Failed to open file: " << region.path
- << "\n Error: " << strerror(errno);
- }
- }
- }
- }
-#endif // !defined(OFFICIAL_BUILD)
- }
-
- // Initializes and installs the symbolization callback.
- void Init() {
- if (CacheMemoryRegions()) {
- OpenSymbolFiles();
- google::InstallSymbolizeOpenObjectFileCallback(
- &OpenObjectFileContainingPc);
- }
- }
-
- // Unregister symbolization callback.
- void UnregisterCallback() {
- if (is_initialized_) {
- google::InstallSymbolizeOpenObjectFileCallback(nullptr);
- is_initialized_ = false;
- }
- }
-
- // Closes all file descriptors owned by this instance.
- void CloseObjectFiles() {
-#if !defined(OFFICIAL_BUILD)
- std::map<std::string, int>::iterator it;
- for (it = modules_.begin(); it != modules_.end(); ++it) {
- int ret = IGNORE_EINTR(close(it->second));
- DCHECK(!ret);
- it->second = -1;
- }
- modules_.clear();
-#endif // !defined(OFFICIAL_BUILD)
- }
-
- // Set to true upon successful initialization.
- bool is_initialized_;
-
-#if !defined(OFFICIAL_BUILD)
- // Mapping from file name to file descriptor. Includes file descriptors
- // for all successfully opened object files and the file descriptor for
- // /proc/self/maps. This code is not safe for production builds.
- std::map<std::string, int> modules_;
-#endif // !defined(OFFICIAL_BUILD)
-
- // Cache for the process memory regions. Produced by parsing the contents
- // of /proc/self/maps cache.
- std::vector<MappedMemoryRegion> regions_;
-
- DISALLOW_COPY_AND_ASSIGN(SandboxSymbolizeHelper);
-};
-#endif // USE_SYMBOLIZE
-
-} // namespace
-
-bool EnableInProcessStackDumping() {
-#if defined(USE_SYMBOLIZE)
- SandboxSymbolizeHelper::GetInstance();
-#endif // USE_SYMBOLIZE
-
- // When running in an application, our code typically expects SIGPIPE
- // to be ignored. Therefore, when testing that same code, it should run
- // with SIGPIPE ignored as well.
- struct sigaction sigpipe_action;
- memset(&sigpipe_action, 0, sizeof(sigpipe_action));
- sigpipe_action.sa_handler = SIG_IGN;
- sigemptyset(&sigpipe_action.sa_mask);
- bool success = (sigaction(SIGPIPE, &sigpipe_action, nullptr) == 0);
-
- // Avoid hangs during backtrace initialization, see above.
- WarmUpBacktrace();
-
- struct sigaction action;
- memset(&action, 0, sizeof(action));
- action.sa_flags = SA_RESETHAND | SA_SIGINFO;
- action.sa_sigaction = &StackDumpSignalHandler;
- sigemptyset(&action.sa_mask);
-
- success &= (sigaction(SIGILL, &action, nullptr) == 0);
- success &= (sigaction(SIGABRT, &action, nullptr) == 0);
- success &= (sigaction(SIGFPE, &action, nullptr) == 0);
- success &= (sigaction(SIGBUS, &action, nullptr) == 0);
- success &= (sigaction(SIGSEGV, &action, nullptr) == 0);
-// On Linux, SIGSYS is reserved by the kernel for seccomp-bpf sandboxing.
-#if !defined(OS_LINUX)
- success &= (sigaction(SIGSYS, &action, nullptr) == 0);
-#endif // !defined(OS_LINUX)
-
- return success;
-}
-
-void SetStackDumpFirstChanceCallback(bool (*handler)(int, void*, void*)) {
- DCHECK(try_handle_signal == nullptr || handler == nullptr);
- try_handle_signal = handler;
-}
-
-StackTrace::StackTrace(size_t count) {
-// NOTE: This code MUST be async-signal safe (it's used by in-process
-// stack dumping signal handler). NO malloc or stdio is allowed here.
-
-#if !defined(__UCLIBC__) && !defined(_AIX)
- count = std::min(arraysize(trace_), count);
-
- // Though the backtrace API man page does not list any possible negative
- // return values, we take no chance.
- count_ = base::saturated_cast<size_t>(backtrace(trace_, count));
-#else
- count_ = 0;
-#endif
-}
-
-void StackTrace::Print() const {
- // NOTE: This code MUST be async-signal safe (it's used by in-process
- // stack dumping signal handler). NO malloc or stdio is allowed here.
-
-#if !defined(__UCLIBC__) && !defined(_AIX)
- PrintBacktraceOutputHandler handler;
- ProcessBacktrace(trace_, count_, &handler);
-#endif
-}
-
-#if !defined(__UCLIBC__) && !defined(_AIX)
-void StackTrace::OutputToStream(std::ostream* os) const {
- StreamBacktraceOutputHandler handler(os);
- ProcessBacktrace(trace_, count_, &handler);
-}
-#endif
-
-namespace internal {
-
-// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
-char* itoa_r(intptr_t i, char* buf, size_t sz, int base, size_t padding) {
- // Make sure we can write at least one NUL byte.
- size_t n = 1;
- if (n > sz)
- return nullptr;
-
- if (base < 2 || base > 16) {
- buf[0] = '\000';
- return nullptr;
- }
-
- char* start = buf;
-
- uintptr_t j = i;
-
- // Handle negative numbers (only for base 10).
- if (i < 0 && base == 10) {
- // This does "j = -i" while avoiding integer overflow.
- j = static_cast<uintptr_t>(-(i + 1)) + 1;
-
- // Make sure we can write the '-' character.
- if (++n > sz) {
- buf[0] = '\000';
- return nullptr;
- }
- *start++ = '-';
- }
-
- // Loop until we have converted the entire number. Output at least one
- // character (i.e. '0').
- char* ptr = start;
- do {
- // Make sure there is still enough space left in our output buffer.
- if (++n > sz) {
- buf[0] = '\000';
- return nullptr;
- }
-
- // Output the next digit.
- *ptr++ = "0123456789abcdef"[j % base];
- j /= base;
-
- if (padding > 0)
- padding--;
- } while (j > 0 || padding > 0);
-
- // Terminate the output with a NUL character.
- *ptr = '\000';
-
- // Conversion to ASCII actually resulted in the digits being in reverse
- // order. We can't easily generate them in forward order, as we can't tell
- // the number of characters needed until we are done converting.
- // So, now, we reverse the string (except for the possible "-" sign).
- while (--ptr > start) {
- char ch = *ptr;
- *ptr = *start;
- *start++ = ch;
- }
- return buf;
-}
-
-} // namespace internal
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/stack_trace_win.cc b/base/debug/stack_trace_win.cc
deleted file mode 100644
index 1ef2a06..0000000
--- a/base/debug/stack_trace_win.cc
+++ /dev/null
@@ -1,365 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/stack_trace.h"
-
-#include <windows.h>
-#include <dbghelp.h>
-#include <stddef.h>
-
-#include <algorithm>
-#include <iostream>
-#include <memory>
-
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "base/synchronization/lock.h"
-
-namespace base {
-namespace debug {
-
-namespace {
-
-// Previous unhandled filter. Will be called if not NULL when we intercept an
-// exception. Only used in unit tests.
-LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL;
-
-bool g_initialized_symbols = false;
-DWORD g_init_error = ERROR_SUCCESS;
-
-// Prints the exception call stack.
-// This is the unit tests exception filter.
-long WINAPI StackDumpExceptionFilter(EXCEPTION_POINTERS* info) {
- DWORD exc_code = info->ExceptionRecord->ExceptionCode;
- std::cerr << "Received fatal exception ";
- switch (exc_code) {
- case EXCEPTION_ACCESS_VIOLATION:
- std::cerr << "EXCEPTION_ACCESS_VIOLATION";
- break;
- case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- std::cerr << "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
- break;
- case EXCEPTION_BREAKPOINT:
- std::cerr << "EXCEPTION_BREAKPOINT";
- break;
- case EXCEPTION_DATATYPE_MISALIGNMENT:
- std::cerr << "EXCEPTION_DATATYPE_MISALIGNMENT";
- break;
- case EXCEPTION_FLT_DENORMAL_OPERAND:
- std::cerr << "EXCEPTION_FLT_DENORMAL_OPERAND";
- break;
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- std::cerr << "EXCEPTION_FLT_DIVIDE_BY_ZERO";
- break;
- case EXCEPTION_FLT_INEXACT_RESULT:
- std::cerr << "EXCEPTION_FLT_INEXACT_RESULT";
- break;
- case EXCEPTION_FLT_INVALID_OPERATION:
- std::cerr << "EXCEPTION_FLT_INVALID_OPERATION";
- break;
- case EXCEPTION_FLT_OVERFLOW:
- std::cerr << "EXCEPTION_FLT_OVERFLOW";
- break;
- case EXCEPTION_FLT_STACK_CHECK:
- std::cerr << "EXCEPTION_FLT_STACK_CHECK";
- break;
- case EXCEPTION_FLT_UNDERFLOW:
- std::cerr << "EXCEPTION_FLT_UNDERFLOW";
- break;
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- std::cerr << "EXCEPTION_ILLEGAL_INSTRUCTION";
- break;
- case EXCEPTION_IN_PAGE_ERROR:
- std::cerr << "EXCEPTION_IN_PAGE_ERROR";
- break;
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- std::cerr << "EXCEPTION_INT_DIVIDE_BY_ZERO";
- break;
- case EXCEPTION_INT_OVERFLOW:
- std::cerr << "EXCEPTION_INT_OVERFLOW";
- break;
- case EXCEPTION_INVALID_DISPOSITION:
- std::cerr << "EXCEPTION_INVALID_DISPOSITION";
- break;
- case EXCEPTION_NONCONTINUABLE_EXCEPTION:
- std::cerr << "EXCEPTION_NONCONTINUABLE_EXCEPTION";
- break;
- case EXCEPTION_PRIV_INSTRUCTION:
- std::cerr << "EXCEPTION_PRIV_INSTRUCTION";
- break;
- case EXCEPTION_SINGLE_STEP:
- std::cerr << "EXCEPTION_SINGLE_STEP";
- break;
- case EXCEPTION_STACK_OVERFLOW:
- std::cerr << "EXCEPTION_STACK_OVERFLOW";
- break;
- default:
- std::cerr << "0x" << std::hex << exc_code;
- break;
- }
- std::cerr << "\n";
-
- debug::StackTrace(info).Print();
- if (g_previous_filter)
- return g_previous_filter(info);
- return EXCEPTION_CONTINUE_SEARCH;
-}
-
-FilePath GetExePath() {
- wchar_t system_buffer[MAX_PATH];
- GetModuleFileName(NULL, system_buffer, MAX_PATH);
- system_buffer[MAX_PATH - 1] = L'\0';
- return FilePath(system_buffer);
-}
-
-bool InitializeSymbols() {
- if (g_initialized_symbols)
- return g_init_error == ERROR_SUCCESS;
- g_initialized_symbols = true;
- // Defer symbol load until they're needed, use undecorated names, and get line
- // numbers.
- SymSetOptions(SYMOPT_DEFERRED_LOADS |
- SYMOPT_UNDNAME |
- SYMOPT_LOAD_LINES);
- if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) {
- g_init_error = GetLastError();
- // TODO(awong): Handle error: SymInitialize can fail with
- // ERROR_INVALID_PARAMETER.
- // When it fails, we should not call debugbreak since it kills the current
- // process (prevents future tests from running or kills the browser
- // process).
- DLOG(ERROR) << "SymInitialize failed: " << g_init_error;
- return false;
- }
-
- // When transferring the binaries e.g. between bots, path put
- // into the executable will get off. To still retrieve symbols correctly,
- // add the directory of the executable to symbol search path.
- // All following errors are non-fatal.
- const size_t kSymbolsArraySize = 1024;
- std::unique_ptr<wchar_t[]> symbols_path(new wchar_t[kSymbolsArraySize]);
-
- // Note: The below function takes buffer size as number of characters,
- // not number of bytes!
- if (!SymGetSearchPathW(GetCurrentProcess(),
- symbols_path.get(),
- kSymbolsArraySize)) {
- g_init_error = GetLastError();
- DLOG(WARNING) << "SymGetSearchPath failed: " << g_init_error;
- return false;
- }
-
- std::wstring new_path(std::wstring(symbols_path.get()) +
- L";" + GetExePath().DirName().value());
- if (!SymSetSearchPathW(GetCurrentProcess(), new_path.c_str())) {
- g_init_error = GetLastError();
- DLOG(WARNING) << "SymSetSearchPath failed." << g_init_error;
- return false;
- }
-
- g_init_error = ERROR_SUCCESS;
- return true;
-}
-
-// SymbolContext is a threadsafe singleton that wraps the DbgHelp Sym* family
-// of functions. The Sym* family of functions may only be invoked by one
-// thread at a time. SymbolContext code may access a symbol server over the
-// network while holding the lock for this singleton. In the case of high
-// latency, this code will adversely affect performance.
-//
-// There is also a known issue where this backtrace code can interact
-// badly with breakpad if breakpad is invoked in a separate thread while
-// we are using the Sym* functions. This is because breakpad does now
-// share a lock with this function. See this related bug:
-//
-// https://crbug.com/google-breakpad/311
-//
-// This is a very unlikely edge case, and the current solution is to
-// just ignore it.
-class SymbolContext {
- public:
- static SymbolContext* GetInstance() {
- // We use a leaky singleton because code may call this during process
- // termination.
- return
- Singleton<SymbolContext, LeakySingletonTraits<SymbolContext> >::get();
- }
-
- // For the given trace, attempts to resolve the symbols, and output a trace
- // to the ostream os. The format for each line of the backtrace is:
- //
- // <tab>SymbolName[0xAddress+Offset] (FileName:LineNo)
- //
- // This function should only be called if Init() has been called. We do not
- // LOG(FATAL) here because this code is called might be triggered by a
- // LOG(FATAL) itself. Also, it should not be calling complex code that is
- // extensible like PathService since that can in turn fire CHECKs.
- void OutputTraceToStream(const void* const* trace,
- size_t count,
- std::ostream* os) {
- base::AutoLock lock(lock_);
-
- for (size_t i = 0; (i < count) && os->good(); ++i) {
- const int kMaxNameLength = 256;
- DWORD_PTR frame = reinterpret_cast<DWORD_PTR>(trace[i]);
-
- // Code adapted from MSDN example:
- // http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
- ULONG64 buffer[
- (sizeof(SYMBOL_INFO) +
- kMaxNameLength * sizeof(wchar_t) +
- sizeof(ULONG64) - 1) /
- sizeof(ULONG64)];
- memset(buffer, 0, sizeof(buffer));
-
- // Initialize symbol information retrieval structures.
- DWORD64 sym_displacement = 0;
- PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(&buffer[0]);
- symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
- symbol->MaxNameLen = kMaxNameLength - 1;
- BOOL has_symbol = SymFromAddr(GetCurrentProcess(), frame,
- &sym_displacement, symbol);
-
- // Attempt to retrieve line number information.
- DWORD line_displacement = 0;
- IMAGEHLP_LINE64 line = {};
- line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
- BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame,
- &line_displacement, &line);
-
- // Output the backtrace line.
- (*os) << "\t";
- if (has_symbol) {
- (*os) << symbol->Name << " [0x" << trace[i] << "+"
- << sym_displacement << "]";
- } else {
- // If there is no symbol information, add a spacer.
- (*os) << "(No symbol) [0x" << trace[i] << "]";
- }
- if (has_line) {
- (*os) << " (" << line.FileName << ":" << line.LineNumber << ")";
- }
- (*os) << "\n";
- }
- }
-
- private:
- friend struct DefaultSingletonTraits<SymbolContext>;
-
- SymbolContext() {
- InitializeSymbols();
- }
-
- base::Lock lock_;
- DISALLOW_COPY_AND_ASSIGN(SymbolContext);
-};
-
-} // namespace
-
-bool EnableInProcessStackDumping() {
- // Add stack dumping support on exception on windows. Similar to OS_POSIX
- // signal() handling in process_util_posix.cc.
- g_previous_filter = SetUnhandledExceptionFilter(&StackDumpExceptionFilter);
-
- // Need to initialize symbols early in the process or else this fails on
- // swarming (since symbols are in different directory than in the exes) and
- // also release x64.
- return InitializeSymbols();
-}
-
-// Disable optimizations for the StackTrace::StackTrace function. It is
-// important to disable at least frame pointer optimization ("y"), since
-// that breaks CaptureStackBackTrace() and prevents StackTrace from working
-// in Release builds (it may still be janky if other frames are using FPO,
-// but at least it will make it further).
-#if defined(COMPILER_MSVC)
-#pragma optimize("", off)
-#endif
-
-StackTrace::StackTrace(size_t count) {
- count = std::min(arraysize(trace_), count);
-
- // When walking our own stack, use CaptureStackBackTrace().
- count_ = CaptureStackBackTrace(0, count, trace_, NULL);
-}
-
-#if defined(COMPILER_MSVC)
-#pragma optimize("", on)
-#endif
-
-StackTrace::StackTrace(EXCEPTION_POINTERS* exception_pointers) {
- InitTrace(exception_pointers->ContextRecord);
-}
-
-StackTrace::StackTrace(const CONTEXT* context) {
- InitTrace(context);
-}
-
-void StackTrace::InitTrace(const CONTEXT* context_record) {
- // StackWalk64 modifies the register context in place, so we have to copy it
- // so that downstream exception handlers get the right context. The incoming
- // context may have had more register state (YMM, etc) than we need to unwind
- // the stack. Typically StackWalk64 only needs integer and control registers.
- CONTEXT context_copy;
- memcpy(&context_copy, context_record, sizeof(context_copy));
- context_copy.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
-
- // When walking an exception stack, we need to use StackWalk64().
- count_ = 0;
- // Initialize stack walking.
- STACKFRAME64 stack_frame;
- memset(&stack_frame, 0, sizeof(stack_frame));
-#if defined(_WIN64)
- int machine_type = IMAGE_FILE_MACHINE_AMD64;
- stack_frame.AddrPC.Offset = context_record->Rip;
- stack_frame.AddrFrame.Offset = context_record->Rbp;
- stack_frame.AddrStack.Offset = context_record->Rsp;
-#else
- int machine_type = IMAGE_FILE_MACHINE_I386;
- stack_frame.AddrPC.Offset = context_record->Eip;
- stack_frame.AddrFrame.Offset = context_record->Ebp;
- stack_frame.AddrStack.Offset = context_record->Esp;
-#endif
- stack_frame.AddrPC.Mode = AddrModeFlat;
- stack_frame.AddrFrame.Mode = AddrModeFlat;
- stack_frame.AddrStack.Mode = AddrModeFlat;
- while (StackWalk64(machine_type,
- GetCurrentProcess(),
- GetCurrentThread(),
- &stack_frame,
- &context_copy,
- NULL,
- &SymFunctionTableAccess64,
- &SymGetModuleBase64,
- NULL) &&
- count_ < arraysize(trace_)) {
- trace_[count_++] = reinterpret_cast<void*>(stack_frame.AddrPC.Offset);
- }
-
- for (size_t i = count_; i < arraysize(trace_); ++i)
- trace_[i] = NULL;
-}
-
-void StackTrace::Print() const {
- OutputToStream(&std::cerr);
-}
-
-void StackTrace::OutputToStream(std::ostream* os) const {
- SymbolContext* context = SymbolContext::GetInstance();
- if (g_init_error != ERROR_SUCCESS) {
- (*os) << "Error initializing symbols (" << g_init_error
- << "). Dumping unresolved backtrace:\n";
- for (size_t i = 0; (i < count_) && os->good(); ++i) {
- (*os) << "\t" << trace_[i] << "\n";
- }
- } else {
- (*os) << "Backtrace:\n";
- context->OutputTraceToStream(trace_, count_, os);
- }
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/task_annotator.cc b/base/debug/task_annotator.cc
deleted file mode 100644
index 69b9c04..0000000
--- a/base/debug/task_annotator.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/debug/task_annotator.h"
-
-#include <array>
-
-#include "base/debug/alias.h"
-#include "base/no_destructor.h"
-#include "base/pending_task.h"
-#include "base/threading/thread_local.h"
-
-namespace base {
-namespace debug {
-
-namespace {
-
-TaskAnnotator::ObserverForTesting* g_task_annotator_observer = nullptr;
-
-// Returns the TLS slot that stores the PendingTask currently in progress on
-// each thread. Used to allow creating a breadcrumb of program counters on the
-// stack to help identify a task's origin in crashes.
-ThreadLocalPointer<const PendingTask>* GetTLSForCurrentPendingTask() {
- static NoDestructor<ThreadLocalPointer<const PendingTask>>
- tls_for_current_pending_task;
- return tls_for_current_pending_task.get();
-}
-
-} // namespace
-
-TaskAnnotator::TaskAnnotator() = default;
-
-TaskAnnotator::~TaskAnnotator() = default;
-
-void TaskAnnotator::DidQueueTask(const char* queue_function,
- const PendingTask& pending_task) {
- // TODO(https://crbug.com/826902): Fix callers that invoke DidQueueTask()
- // twice for the same PendingTask.
- // DCHECK(!pending_task.task_backtrace[0])
- // << "Task backtrace was already set, task posted twice??";
- if (!pending_task.task_backtrace[0]) {
- const PendingTask* parent_task = GetTLSForCurrentPendingTask()->Get();
- if (parent_task) {
- pending_task.task_backtrace[0] =
- parent_task->posted_from.program_counter();
- std::copy(parent_task->task_backtrace.begin(),
- parent_task->task_backtrace.end() - 1,
- pending_task.task_backtrace.begin() + 1);
- }
- }
-}
-
-void TaskAnnotator::RunTask(const char* queue_function,
- PendingTask* pending_task) {
- // Before running the task, store the task backtrace with the chain of
- // PostTasks that resulted in this call and deliberately alias it to ensure
- // it is on the stack if the task crashes. Be careful not to assume that the
- // variable itself will have the expected value when displayed by the
- // optimizer in an optimized build. Look at a memory dump of the stack.
- static constexpr int kStackTaskTraceSnapshotSize =
- std::tuple_size<decltype(pending_task->task_backtrace)>::value + 3;
- std::array<const void*, kStackTaskTraceSnapshotSize> task_backtrace;
-
- // Store a marker to locate |task_backtrace| content easily on a memory
- // dump.
- task_backtrace.front() = reinterpret_cast<void*>(0xefefefefefefefef);
- task_backtrace.back() = reinterpret_cast<void*>(0xfefefefefefefefe);
-
- task_backtrace[1] = pending_task->posted_from.program_counter();
- std::copy(pending_task->task_backtrace.begin(),
- pending_task->task_backtrace.end(), task_backtrace.begin() + 2);
- debug::Alias(&task_backtrace);
-
- ThreadLocalPointer<const PendingTask>* tls_for_current_pending_task =
- GetTLSForCurrentPendingTask();
- const PendingTask* previous_pending_task =
- tls_for_current_pending_task->Get();
- tls_for_current_pending_task->Set(pending_task);
-
- if (g_task_annotator_observer)
- g_task_annotator_observer->BeforeRunTask(pending_task);
- std::move(pending_task->task).Run();
-
- tls_for_current_pending_task->Set(previous_pending_task);
-}
-
-uint64_t TaskAnnotator::GetTaskTraceID(const PendingTask& task) const {
- return (static_cast<uint64_t>(task.sequence_num) << 32) |
- ((static_cast<uint64_t>(reinterpret_cast<intptr_t>(this)) << 32) >>
- 32);
-}
-
-// static
-void TaskAnnotator::RegisterObserverForTesting(ObserverForTesting* observer) {
- DCHECK(!g_task_annotator_observer);
- g_task_annotator_observer = observer;
-}
-
-// static
-void TaskAnnotator::ClearObserverForTesting() {
- g_task_annotator_observer = nullptr;
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/task_annotator.h b/base/debug/task_annotator.h
deleted file mode 100644
index f53d02c..0000000
--- a/base/debug/task_annotator.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_DEBUG_TASK_ANNOTATOR_H_
-#define BASE_DEBUG_TASK_ANNOTATOR_H_
-
-#include <stdint.h>
-
-#include "base/base_export.h"
-#include "base/macros.h"
-
-namespace base {
-struct PendingTask;
-namespace debug {
-
-// Implements common debug annotations for posted tasks. This includes data
-// such as task origins, queueing durations and memory usage.
-class BASE_EXPORT TaskAnnotator {
- public:
- class ObserverForTesting {
- public:
- // Invoked just before RunTask() in the scope in which the task is about to
- // be executed.
- virtual void BeforeRunTask(const PendingTask* pending_task) = 0;
- };
-
- TaskAnnotator();
- ~TaskAnnotator();
-
- // Called to indicate that a task has been queued to run in the future.
- // |queue_function| is used as the trace flow event name. |queue_function| can
- // be null if the caller doesn't want trace flow events logged to
- // toplevel.flow.
- void DidQueueTask(const char* queue_function,
- const PendingTask& pending_task);
-
- // Run a previously queued task. |queue_function| should match what was
- // passed into |DidQueueTask| for this task.
- void RunTask(const char* queue_function, PendingTask* pending_task);
-
- // Creates a process-wide unique ID to represent this task in trace events.
- // This will be mangled with a Process ID hash to reduce the likelyhood of
- // colliding with TaskAnnotator pointers on other processes. Callers may use
- // this when generating their own flow events (i.e. when passing
- // |queue_function == nullptr| in above methods).
- uint64_t GetTaskTraceID(const PendingTask& task) const;
-
- private:
- friend class TaskAnnotatorBacktraceIntegrationTest;
-
- // Registers an ObserverForTesting that will be invoked by all TaskAnnotators'
- // RunTask(). This registration and the implementation of BeforeRunTask() are
- // responsible to ensure thread-safety.
- static void RegisterObserverForTesting(ObserverForTesting* observer);
- static void ClearObserverForTesting();
-
- DISALLOW_COPY_AND_ASSIGN(TaskAnnotator);
-};
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_TASK_ANNOTATOR_H_
diff --git a/base/lazy_instance.h b/base/lazy_instance.h
index 36d3158..456b431 100644
--- a/base/lazy_instance.h
+++ b/base/lazy_instance.h
@@ -48,7 +48,6 @@
#include <new> // For placement new.
#include "base/atomicops.h"
-#include "base/debug/leak_annotations.h"
#include "base/lazy_instance_helpers.h"
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
@@ -113,7 +112,6 @@
#endif
static Type* New(void* instance) {
- ANNOTATE_SCOPED_MEMORY_LEAK;
return LazyInstanceTraitsBase<Type>::New(instance);
}
static void Delete(Type* instance) {
diff --git a/base/logging.cc b/base/logging.cc
index 72ca87a..78f1aa0 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -88,9 +88,6 @@
#include "base/callback.h"
#include "base/command_line.h"
#include "base/containers/stack.h"
-#include "base/debug/alias.h"
-#include "base/debug/debugger.h"
-#include "base/debug/stack_trace.h"
#include "base/lazy_instance.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_piece.h"
@@ -586,11 +583,8 @@
size_t stack_start = stream_.tellp();
#if !defined(OFFICIAL_BUILD) && !defined(OS_NACL) && !defined(__UCLIBC__) && \
!defined(OS_AIX)
- if (severity_ == LOG_FATAL && !base::debug::BeingDebugged()) {
- // Include a stack trace on a fatal, unless a debugger is attached.
- base::debug::StackTrace trace;
+ if (severity_ == LOG_FATAL) {
stream_ << std::endl; // Newline to separate from log message.
- trace.OutputToStream(&stream_);
}
#endif
stream_ << std::endl;
@@ -815,10 +809,6 @@
}
if (severity_ == LOG_FATAL) {
- // Ensure the first characters of the string are on the stack so they
- // are contained in minidumps for diagnostic purposes.
- DEBUG_ALIAS_FOR_CSTR(str_stack, str_newline.c_str(), 1024);
-
if (log_assert_handler_stack.IsCreated() &&
!log_assert_handler_stack.Get().empty()) {
LogAssertHandlerFunction log_assert_handler =
@@ -838,14 +828,12 @@
// information, and displaying message boxes when the application is
// hosed can cause additional problems.
#ifndef NDEBUG
- if (!base::debug::BeingDebugged()) {
- // Displaying a dialog is unnecessary when debugging and can complicate
- // debugging.
- DisplayDebugMessageInDialog(stream_.str());
- }
+ // Displaying a dialog is unnecessary when debugging and can complicate
+ // debugging.
+ DisplayDebugMessageInDialog(stream_.str());
#endif
// Crash the process to generate a dump.
- base::debug::BreakDebugger();
+ abort();
}
}
}
@@ -959,10 +947,6 @@
Win32ErrorLogMessage::~Win32ErrorLogMessage() {
stream() << ": " << SystemErrorCodeToString(err_);
- // We're about to crash (CHECK). Put |err_| on the stack (by placing it in a
- // field) and use Alias in hopes that it makes it into crash dumps.
- DWORD last_error = err_;
- base::debug::Alias(&last_error);
}
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
ErrnoLogMessage::ErrnoLogMessage(const char* file,
@@ -975,10 +959,6 @@
ErrnoLogMessage::~ErrnoLogMessage() {
stream() << ": " << SystemErrorCodeToString(err_);
- // We're about to crash (CHECK). Put |err_| on the stack (by placing it in a
- // field) and use Alias in hopes that it makes it into crash dumps.
- int last_error = err_;
- base::debug::Alias(&last_error);
}
#endif // defined(OS_WIN)
@@ -1017,7 +997,7 @@
}
if (level == LOG_FATAL)
- base::debug::BreakDebugger();
+ abort();
}
// This was defined at the beginning of this file.
diff --git a/base/logging.h b/base/logging.h
index 39b17ff..59e2fcf 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -17,7 +17,6 @@
#include "base/base_export.h"
#include "base/callback_forward.h"
#include "base/compiler_specific.h"
-#include "base/debug/debugger.h"
#include "base/macros.h"
#include "base/strings/string_piece_forward.h"
#include "base/template_util.h"
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc
index 0dd1272..7a43e92 100644
--- a/base/message_loop/incoming_task_queue.cc
+++ b/base/message_loop/incoming_task_queue.cc
@@ -121,7 +121,7 @@
void IncomingTaskQueue::RunTask(PendingTask* pending_task) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- task_annotator_.RunTask("MessageLoop::PostTask", pending_task);
+ std::move(pending_task->task).Run();
}
IncomingTaskQueue::TriageQueue::TriageQueue(IncomingTaskQueue* outer)
@@ -329,8 +329,6 @@
// delayed_run_time value) and for identifying the task in about:tracing.
pending_task->sequence_num = next_sequence_num_++;
- task_annotator_.DidQueueTask("MessageLoop::PostTask", *pending_task);
-
bool was_empty = incoming_queue_.empty();
incoming_queue_.push(std::move(*pending_task));
diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h
index f158d2a..b4d8185 100644
--- a/base/message_loop/incoming_task_queue.h
+++ b/base/message_loop/incoming_task_queue.h
@@ -7,7 +7,6 @@
#include "base/base_export.h"
#include "base/callback.h"
-#include "base/debug/task_annotator.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/pending_task.h"
@@ -206,8 +205,6 @@
// Checks calls made only on the MessageLoop thread.
SEQUENCE_CHECKER(sequence_checker_);
- debug::TaskAnnotator task_annotator_;
-
// True if we always need to call ScheduleWork when receiving a new task, even
// if the incoming queue was not empty.
const bool always_schedule_work_;
diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc
index 47cf477..af0c7db 100644
--- a/base/message_loop/message_pump_win.cc
+++ b/base/message_loop/message_pump_win.cc
@@ -9,7 +9,6 @@
#include <limits>
-#include "base/debug/alias.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
@@ -209,8 +208,6 @@
delay = INFINITE;
// Tell the optimizer to retain these values to simplify analyzing hangs.
- base::debug::Alias(&delay);
- base::debug::Alias(&wait_flags);
DWORD result = MsgWaitForMultipleObjectsEx(0, nullptr, delay, QS_ALLINPUT,
wait_flags);
@@ -313,8 +310,6 @@
if (delay_msec < USER_TIMER_MINIMUM)
delay_msec = USER_TIMER_MINIMUM;
- // Tell the optimizer to retain these values to simplify analyzing hangs.
- base::debug::Alias(&delay_msec);
// Create a WM_TIMER event that will wake us up to check for any pending
// timers (in case we are running within a nested, external sub-pump).
UINT_PTR ret = SetTimer(message_window_.hwnd(), 0, delay_msec, nullptr);
@@ -510,8 +505,6 @@
if (timeout < 0) // Negative value means no timers waiting.
timeout = INFINITE;
- // Tell the optimizer to retain these values to simplify analyzing hangs.
- base::debug::Alias(&timeout);
WaitForIOCompletion(timeout, nullptr);
}
diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc
index 1004012..fc9d188 100644
--- a/base/process/launch_posix.cc
+++ b/base/process/launch_posix.cc
@@ -27,8 +27,6 @@
#include "base/command_line.h"
#include "base/compiler_specific.h"
-#include "base/debug/debugger.h"
-#include "base/debug/stack_trace.h"
#include "base/files/dir_reader_posix.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc
index 0ae6820..3ee81b1 100644
--- a/base/process/launch_win.cc
+++ b/base/process/launch_win.cc
@@ -17,8 +17,6 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
-#include "base/debug/activity_tracker.h"
-#include "base/debug/stack_trace.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/process/kill.h"
diff --git a/base/process/memory.cc b/base/process/memory.cc
index a98e309..84305e0 100644
--- a/base/process/memory.cc
+++ b/base/process/memory.cc
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/alias.h"
#include "base/logging.h"
#include "base/process/memory.h"
#include "build_config.h"
@@ -17,9 +16,7 @@
// Breakpad server classifies base::`anonymous namespace'::OnNoMemory as
// out-of-memory crash.
NOINLINE void OnNoMemory(size_t size) {
- size_t tmp_size = size;
- base::debug::Alias(&tmp_size);
- LOG(FATAL) << "Out of memory. size=" << tmp_size;
+ LOG(FATAL) << "Out of memory. size=" << size;
}
} // namespace
diff --git a/base/process/process_win.cc b/base/process/process_win.cc
index a2e614c..2ef4daf 100644
--- a/base/process/process_win.cc
+++ b/base/process/process_win.cc
@@ -4,7 +4,6 @@
#include "base/process/process.h"
-#include "base/debug/activity_tracker.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/process/kill.h"
diff --git a/base/profiler/OWNERS b/base/profiler/OWNERS
deleted file mode 100644
index 81ff9fa..0000000
--- a/base/profiler/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Stack sampling profiler
-per-file native_stack_sampler*=wittman@chromium.org
-per-file stack_sampling_profiler*=wittman@chromium.org
-per-file test_support_library*=wittman@chromium.org
-per-file win32_stack_frame_unwinder*=wittman@chromium.org
diff --git a/base/profiler/native_stack_sampler.cc b/base/profiler/native_stack_sampler.cc
deleted file mode 100644
index 6eed54f..0000000
--- a/base/profiler/native_stack_sampler.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/profiler/native_stack_sampler.h"
-
-#include "base/memory/ptr_util.h"
-
-namespace base {
-
-NativeStackSampler::StackBuffer::StackBuffer(size_t buffer_size)
- : buffer_(new uintptr_t[(buffer_size + sizeof(uintptr_t) - 1) /
- sizeof(uintptr_t)]),
- size_(buffer_size) {}
-
-NativeStackSampler::StackBuffer::~StackBuffer() = default;
-
-NativeStackSampler::NativeStackSampler() = default;
-
-NativeStackSampler::~NativeStackSampler() = default;
-
-std::unique_ptr<NativeStackSampler::StackBuffer>
-NativeStackSampler::CreateStackBuffer() {
- size_t size = GetStackBufferSize();
- if (size == 0)
- return nullptr;
- return std::make_unique<StackBuffer>(size);
-}
-
-NativeStackSamplerTestDelegate::~NativeStackSamplerTestDelegate() = default;
-
-NativeStackSamplerTestDelegate::NativeStackSamplerTestDelegate() = default;
-
-} // namespace base
diff --git a/base/profiler/native_stack_sampler.h b/base/profiler/native_stack_sampler.h
deleted file mode 100644
index ebd7c3c..0000000
--- a/base/profiler/native_stack_sampler.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
-#define BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
-
-#include <memory>
-
-#include "base/base_export.h"
-#include "base/macros.h"
-#include "base/profiler/stack_sampling_profiler.h"
-#include "base/threading/platform_thread.h"
-
-namespace base {
-
-class NativeStackSamplerTestDelegate;
-
-// NativeStackSampler is an implementation detail of StackSamplingProfiler. It
-// abstracts the native implementation required to record a stack sample for a
-// given thread.
-class NativeStackSampler {
- public:
- // This class contains a buffer for stack copies that can be shared across
- // multiple instances of NativeStackSampler.
- class StackBuffer {
- public:
- StackBuffer(size_t buffer_size);
- ~StackBuffer();
-
- void* buffer() const { return buffer_.get(); }
- size_t size() const { return size_; }
-
- private:
- // The word-aligned buffer.
- const std::unique_ptr<uintptr_t[]> buffer_;
-
- // The size of the buffer.
- const size_t size_;
-
- DISALLOW_COPY_AND_ASSIGN(StackBuffer);
- };
-
- // The callback type used to add annotations to a sample during collection.
- // This is passed to the native sampler to be applied at the most appropriate
- // time. It is a simple function-pointer because the generated code must be
- // completely predictable and do nothing that could acquire a mutex; a
- // Callback object is code outside the control of this object and could,
- // for example, acquire a mutex as part of allocating memory for a LOG
- // message.
- using AnnotateCallback = void (*)(StackSamplingProfiler::Sample*);
-
- virtual ~NativeStackSampler();
-
- // Creates a stack sampler that records samples for |thread_handle|. Returns
- // null if this platform does not support stack sampling.
- static std::unique_ptr<NativeStackSampler> Create(
- PlatformThreadId thread_id,
- AnnotateCallback annotator,
- NativeStackSamplerTestDelegate* test_delegate);
-
- // Gets the required size of the stack buffer.
- static size_t GetStackBufferSize();
-
- // Creates an instance of the a stack buffer that can be used for calls to
- // any NativeStackSampler object.
- static std::unique_ptr<StackBuffer> CreateStackBuffer();
-
- // The following functions are all called on the SamplingThread (not the
- // thread being sampled).
-
- // Notifies the sampler that we're starting to record a new profile. Modules
- // shared across samples in the profile should be recorded in |modules|.
- virtual void ProfileRecordingStarting(
- std::vector<StackSamplingProfiler::Module>* modules) = 0;
-
- // Records a stack sample to |sample|.
- virtual void RecordStackSample(StackBuffer* stackbuffer,
- StackSamplingProfiler::Sample* sample) = 0;
-
- // Notifies the sampler that we've stopped recording the current
- // profile.
- virtual void ProfileRecordingStopped(StackBuffer* stackbuffer) = 0;
-
- protected:
- NativeStackSampler();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(NativeStackSampler);
-};
-
-// NativeStackSamplerTestDelegate provides seams for test code to execute during
-// stack collection.
-class BASE_EXPORT NativeStackSamplerTestDelegate {
- public:
- virtual ~NativeStackSamplerTestDelegate();
-
- // Called after copying the stack and resuming the target thread, but prior to
- // walking the stack. Invoked on the SamplingThread.
- virtual void OnPreStackWalk() = 0;
-
- protected:
- NativeStackSamplerTestDelegate();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerTestDelegate);
-};
-
-} // namespace base
-
-#endif // BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
-
diff --git a/base/profiler/native_stack_sampler_mac.cc b/base/profiler/native_stack_sampler_mac.cc
deleted file mode 100644
index a161173..0000000
--- a/base/profiler/native_stack_sampler_mac.cc
+++ /dev/null
@@ -1,666 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/profiler/native_stack_sampler.h"
-
-#include <dlfcn.h>
-#include <libkern/OSByteOrder.h>
-#include <libunwind.h>
-#include <mach-o/compact_unwind_encoding.h>
-#include <mach-o/getsect.h>
-#include <mach-o/swap.h>
-#include <mach/kern_return.h>
-#include <mach/mach.h>
-#include <mach/thread_act.h>
-#include <mach/vm_map.h>
-#include <pthread.h>
-#include <sys/resource.h>
-#include <sys/syslimits.h>
-
-#include <algorithm>
-#include <map>
-#include <memory>
-
-#include "base/logging.h"
-#include "base/mac/mach_logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/string_number_conversions.h"
-
-extern "C" {
-void _sigtramp(int, int, struct sigset*);
-}
-
-namespace base {
-
-namespace {
-
-// Maps a module's address range (half-open) in memory to an index in a separate
-// data structure.
-struct ModuleIndex {
- ModuleIndex(uintptr_t start, uintptr_t end, size_t idx)
- : base_address(start), end_address(end), index(idx){};
- // Base address of the represented module.
- uintptr_t base_address;
- // First address off the end of the represented module.
- uintptr_t end_address;
- // An index to the represented module in a separate container.
- size_t index;
-};
-
-// Module identifiers ---------------------------------------------------------
-
-// Returns the unique build ID for a module loaded at |module_addr|. Returns the
-// empty string if the function fails to get the build ID.
-//
-// Build IDs are created by the concatenation of the module's GUID (Windows) /
-// UUID (Mac) and an "age" field that indicates how many times that GUID/UUID
-// has been reused. In Windows binaries, the "age" field is present in the
-// module header, but on the Mac, UUIDs are never reused and so the "age" value
-// appended to the UUID is always 0.
-std::string GetUniqueId(const void* module_addr) {
- const mach_header_64* mach_header =
- reinterpret_cast<const mach_header_64*>(module_addr);
- DCHECK_EQ(MH_MAGIC_64, mach_header->magic);
-
- size_t offset = sizeof(mach_header_64);
- size_t offset_limit = sizeof(mach_header_64) + mach_header->sizeofcmds;
- for (uint32_t i = 0; (i < mach_header->ncmds) &&
- (offset + sizeof(load_command) < offset_limit);
- ++i) {
- const load_command* current_cmd = reinterpret_cast<const load_command*>(
- reinterpret_cast<const uint8_t*>(mach_header) + offset);
-
- if (offset + current_cmd->cmdsize > offset_limit) {
- // This command runs off the end of the command list. This is malformed.
- return std::string();
- }
-
- if (current_cmd->cmd == LC_UUID) {
- if (current_cmd->cmdsize < sizeof(uuid_command)) {
- // This "UUID command" is too small. This is malformed.
- return std::string();
- }
-
- const uuid_command* uuid_cmd =
- reinterpret_cast<const uuid_command*>(current_cmd);
- static_assert(sizeof(uuid_cmd->uuid) == sizeof(uuid_t),
- "UUID field of UUID command should be 16 bytes.");
- // The ID is comprised of the UUID concatenated with the Mac's "age" value
- // which is always 0.
- return HexEncode(&uuid_cmd->uuid, sizeof(uuid_cmd->uuid)) + "0";
- }
- offset += current_cmd->cmdsize;
- }
- return std::string();
-}
-
-// Returns the size of the _TEXT segment of the module loaded at |module_addr|.
-size_t GetModuleTextSize(const void* module_addr) {
- const mach_header_64* mach_header =
- reinterpret_cast<const mach_header_64*>(module_addr);
- DCHECK_EQ(MH_MAGIC_64, mach_header->magic);
-
- unsigned long module_size;
- getsegmentdata(mach_header, SEG_TEXT, &module_size);
-
- return module_size;
-}
-
-// Gets the index for the Module containing |instruction_pointer| in
-// |modules|, adding it if it's not already present. Returns
-// StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be
-// determined for |module|.
-size_t GetModuleIndex(const uintptr_t instruction_pointer,
- std::vector<StackSamplingProfiler::Module>* modules,
- std::vector<ModuleIndex>* profile_module_index) {
- // Check if |instruction_pointer| is in the address range of a module we've
- // already seen.
- auto module_index =
- std::find_if(profile_module_index->begin(), profile_module_index->end(),
- [instruction_pointer](const ModuleIndex& index) {
- return instruction_pointer >= index.base_address &&
- instruction_pointer < index.end_address;
- });
- if (module_index != profile_module_index->end()) {
- return module_index->index;
- }
- Dl_info inf;
- if (!dladdr(reinterpret_cast<const void*>(instruction_pointer), &inf))
- return StackSamplingProfiler::Frame::kUnknownModuleIndex;
-
- StackSamplingProfiler::Module module(
- reinterpret_cast<uintptr_t>(inf.dli_fbase), GetUniqueId(inf.dli_fbase),
- base::FilePath(inf.dli_fname));
- modules->push_back(module);
-
- uintptr_t base_module_address = reinterpret_cast<uintptr_t>(inf.dli_fbase);
- size_t index = modules->size() - 1;
- profile_module_index->emplace_back(
- base_module_address,
- base_module_address + GetModuleTextSize(inf.dli_fbase), index);
- return index;
-}
-
-// Stack walking --------------------------------------------------------------
-
-// Fills |state| with |target_thread|'s context.
-//
-// Note that this is called while a thread is suspended. Make very very sure
-// that no shared resources (e.g. memory allocators) are used for the duration
-// of this function.
-bool GetThreadState(thread_act_t target_thread, x86_thread_state64_t* state) {
- mach_msg_type_number_t count =
- static_cast<mach_msg_type_number_t>(x86_THREAD_STATE64_COUNT);
- return thread_get_state(target_thread, x86_THREAD_STATE64,
- reinterpret_cast<thread_state_t>(state),
- &count) == KERN_SUCCESS;
-}
-
-// If the value at |pointer| points to the original stack, rewrites it to point
-// to the corresponding location in the copied stack.
-//
-// Note that this is called while a thread is suspended. Make very very sure
-// that no shared resources (e.g. memory allocators) are used for the duration
-// of this function.
-uintptr_t RewritePointerIfInOriginalStack(
- const uintptr_t* original_stack_bottom,
- const uintptr_t* original_stack_top,
- uintptr_t* stack_copy_bottom,
- uintptr_t pointer) {
- uintptr_t original_stack_bottom_int =
- reinterpret_cast<uintptr_t>(original_stack_bottom);
- uintptr_t original_stack_top_int =
- reinterpret_cast<uintptr_t>(original_stack_top);
- uintptr_t stack_copy_bottom_int =
- reinterpret_cast<uintptr_t>(stack_copy_bottom);
-
- if ((pointer < original_stack_bottom_int) ||
- (pointer >= original_stack_top_int)) {
- return pointer;
- }
-
- return stack_copy_bottom_int + (pointer - original_stack_bottom_int);
-}
-
-// Copies the stack to a buffer while rewriting possible pointers to locations
-// within the stack to point to the corresponding locations in the copy. This is
-// necessary to handle stack frames with dynamic stack allocation, where a
-// pointer to the beginning of the dynamic allocation area is stored on the
-// stack and/or in a non-volatile register.
-//
-// Eager rewriting of anything that looks like a pointer to the stack, as done
-// in this function, does not adversely affect the stack unwinding. The only
-// other values on the stack the unwinding depends on are return addresses,
-// which should not point within the stack memory. The rewriting is guaranteed
-// to catch all pointers because the stacks are guaranteed by the ABI to be
-// sizeof(void*) aligned.
-//
-// Note that this is called while a thread is suspended. Make very very sure
-// that no shared resources (e.g. memory allocators) are used for the duration
-// of this function.
-void CopyStackAndRewritePointers(uintptr_t* stack_copy_bottom,
- const uintptr_t* original_stack_bottom,
- const uintptr_t* original_stack_top,
- x86_thread_state64_t* thread_state)
- NO_SANITIZE("address") {
- size_t count = original_stack_top - original_stack_bottom;
- for (size_t pos = 0; pos < count; ++pos) {
- stack_copy_bottom[pos] = RewritePointerIfInOriginalStack(
- original_stack_bottom, original_stack_top, stack_copy_bottom,
- original_stack_bottom[pos]);
- }
-
- uint64_t* rewrite_registers[] = {&thread_state->__rbx, &thread_state->__rbp,
- &thread_state->__rsp, &thread_state->__r12,
- &thread_state->__r13, &thread_state->__r14,
- &thread_state->__r15};
- for (auto* reg : rewrite_registers) {
- *reg = RewritePointerIfInOriginalStack(
- original_stack_bottom, original_stack_top, stack_copy_bottom, *reg);
- }
-}
-
-// Extracts the "frame offset" for a given frame from the compact unwind info.
-// A frame offset indicates the location of saved non-volatile registers in
-// relation to the frame pointer. See |mach-o/compact_unwind_encoding.h| for
-// details.
-uint32_t GetFrameOffset(int compact_unwind_info) {
- // The frame offset lives in bytes 16-23. This shifts it down by the number of
- // leading zeroes in the mask, then masks with (1 << number of one bits in the
- // mask) - 1, turning 0x00FF0000 into 0x000000FF. Adapted from |EXTRACT_BITS|
- // in libunwind's CompactUnwinder.hpp.
- return (
- (compact_unwind_info >> __builtin_ctz(UNWIND_X86_64_RBP_FRAME_OFFSET)) &
- (((1 << __builtin_popcount(UNWIND_X86_64_RBP_FRAME_OFFSET))) - 1));
-}
-
-// True if the unwind from |leaf_frame_rip| may trigger a crash bug in
-// unw_init_local. If so, the stack walk should be aborted at the leaf frame.
-bool MayTriggerUnwInitLocalCrash(uint64_t leaf_frame_rip) {
- // The issue here is a bug in unw_init_local that, in some unwinds, results in
- // attempts to access memory at the address immediately following the address
- // range of the library. When the library is the last of the mapped libraries
- // that address is in a different memory region. Starting with 10.13.4 beta
- // releases it appears that this region is sometimes either unmapped or mapped
- // without read access, resulting in crashes on the attempted access. It's not
- // clear what circumstances result in this situation; attempts to reproduce on
- // a 10.13.4 beta did not trigger the issue.
- //
- // The workaround is to check if the memory address that would be accessed is
- // readable, and if not, abort the stack walk before calling unw_init_local.
- // As of 2018/03/19 about 0.1% of non-idle stacks on the UI and GPU main
- // threads have a leaf frame in the last library. Since the issue appears to
- // only occur some of the time it's expected that the quantity of lost samples
- // will be lower than 0.1%, possibly significantly lower.
- //
- // TODO(lgrey): Add references above to LLVM/Radar bugs on unw_init_local once
- // filed.
- Dl_info info;
- if (dladdr(reinterpret_cast<const void*>(leaf_frame_rip), &info) == 0)
- return false;
- uint64_t unused;
- vm_size_t size = sizeof(unused);
- return vm_read_overwrite(current_task(),
- reinterpret_cast<vm_address_t>(info.dli_fbase) +
- GetModuleTextSize(info.dli_fbase),
- sizeof(unused),
- reinterpret_cast<vm_address_t>(&unused), &size) != 0;
-}
-
-// Check if the cursor contains a valid-looking frame pointer for frame pointer
-// unwinds. If the stack frame has a frame pointer, stepping the cursor will
-// involve indexing memory access off of that pointer. In that case,
-// sanity-check the frame pointer register to ensure it's within bounds.
-//
-// Additionally, the stack frame might be in a prologue or epilogue, which can
-// cause a crash when the unwinder attempts to access non-volatile registers
-// that have not yet been pushed, or have already been popped from the
-// stack. libwunwind will try to restore those registers using an offset from
-// the frame pointer. However, since we copy the stack from RSP up, any
-// locations below the stack pointer are before the beginning of the stack
-// buffer. Account for this by checking that the expected location is above the
-// stack pointer, and rejecting the sample if it isn't.
-bool HasValidRbp(unw_cursor_t* unwind_cursor, uintptr_t stack_top) {
- unw_proc_info_t proc_info;
- unw_get_proc_info(unwind_cursor, &proc_info);
- if ((proc_info.format & UNWIND_X86_64_MODE_MASK) ==
- UNWIND_X86_64_MODE_RBP_FRAME) {
- unw_word_t rsp, rbp;
- unw_get_reg(unwind_cursor, UNW_X86_64_RSP, &rsp);
- unw_get_reg(unwind_cursor, UNW_X86_64_RBP, &rbp);
- uint32_t offset = GetFrameOffset(proc_info.format) * sizeof(unw_word_t);
- if (rbp < offset || (rbp - offset) < rsp || rbp > stack_top) {
- return false;
- }
- }
- return true;
-}
-
-// Walks the stack represented by |unwind_context|, calling back to the provided
-// lambda for each frame. Returns false if an error occurred, otherwise returns
-// true.
-template <typename StackFrameCallback, typename ContinueUnwindPredicate>
-bool WalkStackFromContext(
- unw_context_t* unwind_context,
- size_t* frame_count,
- std::vector<StackSamplingProfiler::Module>* current_modules,
- std::vector<ModuleIndex>* profile_module_index,
- const StackFrameCallback& callback,
- const ContinueUnwindPredicate& continue_unwind) {
- unw_cursor_t unwind_cursor;
- unw_init_local(&unwind_cursor, unwind_context);
-
- int step_result;
- unw_word_t rip;
- do {
- ++(*frame_count);
- unw_get_reg(&unwind_cursor, UNW_REG_IP, &rip);
-
- // Ensure IP is in a module.
- //
- // Frameless unwinding (non-DWARF) works by fetching the function's
- // stack size from the unwind encoding or stack, and adding it to the
- // stack pointer to determine the function's return address.
- //
- // If we're in a function prologue or epilogue, the actual stack size
- // may be smaller than it will be during the normal course of execution.
- // When libunwind adds the expected stack size, it will look for the
- // return address in the wrong place. This check should ensure that we
- // bail before trying to deref a bad IP obtained this way in the previous
- // frame.
- size_t module_index =
- GetModuleIndex(rip, current_modules, profile_module_index);
- if (module_index == StackSamplingProfiler::Frame::kUnknownModuleIndex) {
- return false;
- }
-
- callback(static_cast<uintptr_t>(rip), module_index);
-
- if (!continue_unwind(&unwind_cursor))
- return false;
-
- step_result = unw_step(&unwind_cursor);
- } while (step_result > 0);
-
- if (step_result != 0)
- return false;
-
- return true;
-}
-
-const char* LibSystemKernelName() {
- static char path[PATH_MAX];
- static char* name = nullptr;
- if (name)
- return name;
-
- Dl_info info;
- dladdr(reinterpret_cast<void*>(_exit), &info);
- strlcpy(path, info.dli_fname, PATH_MAX);
- name = path;
-
-#if !defined(ADDRESS_SANITIZER)
- DCHECK_EQ(std::string(name),
- std::string("/usr/lib/system/libsystem_kernel.dylib"));
-#endif
- return name;
-}
-
-void GetSigtrampRange(uintptr_t* start, uintptr_t* end) {
- uintptr_t address = reinterpret_cast<uintptr_t>(&_sigtramp);
- DCHECK(address != 0);
-
- *start = address;
-
- unw_context_t context;
- unw_cursor_t cursor;
- unw_proc_info_t info;
-
- unw_getcontext(&context);
- // Set the context's RIP to the beginning of sigtramp,
- // +1 byte to work around a bug in 10.11 (crbug.com/764468).
- context.data[16] = address + 1;
- unw_init_local(&cursor, &context);
- unw_get_proc_info(&cursor, &info);
-
- DCHECK_EQ(info.start_ip, address);
- *end = info.end_ip;
-}
-
-// Walks the stack represented by |thread_state|, calling back to the provided
-// lambda for each frame.
-template <typename StackFrameCallback, typename ContinueUnwindPredicate>
-void WalkStack(const x86_thread_state64_t& thread_state,
- std::vector<StackSamplingProfiler::Module>* current_modules,
- std::vector<ModuleIndex>* profile_module_index,
- const StackFrameCallback& callback,
- const ContinueUnwindPredicate& continue_unwind) {
- size_t frame_count = 0;
- // This uses libunwind to walk the stack. libunwind is designed to be used for
- // a thread to walk its own stack. This creates two problems.
-
- // Problem 1: There is no official way to create a unw_context other than to
- // create it from the current state of the current thread's stack. To get
- // around this, forge a context. A unw_context is just a copy of the 16 main
- // registers followed by the instruction pointer, nothing more.
- // Coincidentally, the first 17 items of the x86_thread_state64_t type are
- // exactly those registers in exactly the same order, so just bulk copy them
- // over.
- unw_context_t unwind_context;
- memcpy(&unwind_context, &thread_state, sizeof(uintptr_t) * 17);
- bool result =
- WalkStackFromContext(&unwind_context, &frame_count, current_modules,
- profile_module_index, callback, continue_unwind);
-
- if (!result)
- return;
-
- if (frame_count == 1) {
- // Problem 2: Because libunwind is designed to be triggered by user code on
- // their own thread, if it hits a library that has no unwind info for the
- // function that is being executed, it just stops. This isn't a problem in
- // the normal case, but in this case, it's quite possible that the stack
- // being walked is stopped in a function that bridges to the kernel and thus
- // is missing the unwind info.
-
- // For now, just unwind the single case where the thread is stopped in a
- // function in libsystem_kernel.
- uint64_t& rsp = unwind_context.data[7];
- uint64_t& rip = unwind_context.data[16];
- Dl_info info;
- if (dladdr(reinterpret_cast<void*>(rip), &info) != 0 &&
- strcmp(info.dli_fname, LibSystemKernelName()) == 0) {
- rip = *reinterpret_cast<uint64_t*>(rsp);
- rsp += 8;
- WalkStackFromContext(&unwind_context, &frame_count, current_modules,
- profile_module_index, callback, continue_unwind);
- }
- }
-}
-
-// ScopedSuspendThread --------------------------------------------------------
-
-// Suspends a thread for the lifetime of the object.
-class ScopedSuspendThread {
- public:
- explicit ScopedSuspendThread(mach_port_t thread_port)
- : thread_port_(thread_suspend(thread_port) == KERN_SUCCESS
- ? thread_port
- : MACH_PORT_NULL) {}
-
- ~ScopedSuspendThread() {
- if (!was_successful())
- return;
-
- kern_return_t kr = thread_resume(thread_port_);
- MACH_CHECK(kr == KERN_SUCCESS, kr) << "thread_resume";
- }
-
- bool was_successful() const { return thread_port_ != MACH_PORT_NULL; }
-
- private:
- mach_port_t thread_port_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedSuspendThread);
-};
-
-// NativeStackSamplerMac ------------------------------------------------------
-
-class NativeStackSamplerMac : public NativeStackSampler {
- public:
- NativeStackSamplerMac(mach_port_t thread_port,
- AnnotateCallback annotator,
- NativeStackSamplerTestDelegate* test_delegate);
- ~NativeStackSamplerMac() override;
-
- // StackSamplingProfiler::NativeStackSampler:
- void ProfileRecordingStarting(
- std::vector<StackSamplingProfiler::Module>* modules) override;
- void RecordStackSample(StackBuffer* stack_buffer,
- StackSamplingProfiler::Sample* sample) override;
- void ProfileRecordingStopped(StackBuffer* stack_buffer) override;
-
- private:
- // Suspends the thread with |thread_port_|, copies its stack and resumes the
- // thread, then records the stack frames and associated modules into |sample|.
- void SuspendThreadAndRecordStack(StackBuffer* stack_buffer,
- StackSamplingProfiler::Sample* sample);
-
- // Weak reference: Mach port for thread being profiled.
- mach_port_t thread_port_;
-
- const AnnotateCallback annotator_;
-
- NativeStackSamplerTestDelegate* const test_delegate_;
-
- // The stack base address corresponding to |thread_handle_|.
- const void* const thread_stack_base_address_;
-
- // Weak. Points to the modules associated with the profile being recorded
- // between ProfileRecordingStarting() and ProfileRecordingStopped().
- std::vector<StackSamplingProfiler::Module>* current_modules_ = nullptr;
-
- // Maps a module's address range to the corresponding Module's index within
- // current_modules_.
- std::vector<ModuleIndex> profile_module_index_;
-
- // The address range of |_sigtramp|, the signal trampoline function.
- uintptr_t sigtramp_start_;
- uintptr_t sigtramp_end_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerMac);
-};
-
-NativeStackSamplerMac::NativeStackSamplerMac(
- mach_port_t thread_port,
- AnnotateCallback annotator,
- NativeStackSamplerTestDelegate* test_delegate)
- : thread_port_(thread_port),
- annotator_(annotator),
- test_delegate_(test_delegate),
- thread_stack_base_address_(
- pthread_get_stackaddr_np(pthread_from_mach_thread_np(thread_port))) {
- DCHECK(annotator_);
-
- GetSigtrampRange(&sigtramp_start_, &sigtramp_end_);
- // This class suspends threads, and those threads might be suspended in dyld.
- // Therefore, for all the system functions that might be linked in dynamically
- // that are used while threads are suspended, make calls to them to make sure
- // that they are linked up.
- x86_thread_state64_t thread_state;
- GetThreadState(thread_port_, &thread_state);
-}
-
-NativeStackSamplerMac::~NativeStackSamplerMac() {}
-
-void NativeStackSamplerMac::ProfileRecordingStarting(
- std::vector<StackSamplingProfiler::Module>* modules) {
- current_modules_ = modules;
- profile_module_index_.clear();
-}
-
-void NativeStackSamplerMac::RecordStackSample(
- StackBuffer* stack_buffer,
- StackSamplingProfiler::Sample* sample) {
- DCHECK(current_modules_);
-
- SuspendThreadAndRecordStack(stack_buffer, sample);
-}
-
-void NativeStackSamplerMac::ProfileRecordingStopped(StackBuffer* stack_buffer) {
- current_modules_ = nullptr;
-}
-
-void NativeStackSamplerMac::SuspendThreadAndRecordStack(
- StackBuffer* stack_buffer,
- StackSamplingProfiler::Sample* sample) {
- x86_thread_state64_t thread_state;
-
- // Copy the stack.
-
- uintptr_t new_stack_top = 0;
- {
- // IMPORTANT NOTE: Do not do ANYTHING in this in this scope that might
- // allocate memory, including indirectly via use of DCHECK/CHECK or other
- // logging statements. Otherwise this code can deadlock on heap locks in the
- // default heap acquired by the target thread before it was suspended.
- ScopedSuspendThread suspend_thread(thread_port_);
- if (!suspend_thread.was_successful())
- return;
-
- if (!GetThreadState(thread_port_, &thread_state))
- return;
- uintptr_t stack_top =
- reinterpret_cast<uintptr_t>(thread_stack_base_address_);
- uintptr_t stack_bottom = thread_state.__rsp;
- if (stack_bottom >= stack_top)
- return;
- uintptr_t stack_size = stack_top - stack_bottom;
-
- if (stack_size > stack_buffer->size())
- return;
-
- (*annotator_)(sample);
-
- CopyStackAndRewritePointers(
- reinterpret_cast<uintptr_t*>(stack_buffer->buffer()),
- reinterpret_cast<uintptr_t*>(stack_bottom),
- reinterpret_cast<uintptr_t*>(stack_top), &thread_state);
-
- new_stack_top =
- reinterpret_cast<uintptr_t>(stack_buffer->buffer()) + stack_size;
- } // ScopedSuspendThread
-
- if (test_delegate_)
- test_delegate_->OnPreStackWalk();
-
- // Walk the stack and record it.
-
- // Reserve enough memory for most stacks, to avoid repeated allocations.
- // Approximately 99.9% of recorded stacks are 128 frames or fewer.
- sample->frames.reserve(128);
-
- auto* current_modules = current_modules_;
- auto* profile_module_index = &profile_module_index_;
-
- // Avoid an out-of-bounds read bug in libunwind that can crash us in some
- // circumstances. If we're subject to that case, just record the first frame
- // and bail. See MayTriggerUnwInitLocalCrash for details.
- uintptr_t rip = thread_state.__rip;
- if (MayTriggerUnwInitLocalCrash(rip)) {
- sample->frames.emplace_back(
- rip, GetModuleIndex(rip, current_modules, profile_module_index));
- return;
- }
-
- const auto continue_predicate = [this,
- new_stack_top](unw_cursor_t* unwind_cursor) {
- // Don't continue if we're in sigtramp. Unwinding this from another thread
- // is very fragile. It's a complex DWARF unwind that needs to restore the
- // entire thread context which was saved by the kernel when the interrupt
- // occurred.
- unw_word_t rip;
- unw_get_reg(unwind_cursor, UNW_REG_IP, &rip);
- if (rip >= sigtramp_start_ && rip < sigtramp_end_)
- return false;
-
- // Don't continue if rbp appears to be invalid (due to a previous bad
- // unwind).
- return HasValidRbp(unwind_cursor, new_stack_top);
- };
-
- WalkStack(thread_state, current_modules, profile_module_index,
- [sample, current_modules, profile_module_index](
- uintptr_t frame_ip, size_t module_index) {
- sample->frames.emplace_back(frame_ip, module_index);
- },
- continue_predicate);
-}
-
-} // namespace
-
-std::unique_ptr<NativeStackSampler> NativeStackSampler::Create(
- PlatformThreadId thread_id,
- AnnotateCallback annotator,
- NativeStackSamplerTestDelegate* test_delegate) {
- return std::make_unique<NativeStackSamplerMac>(thread_id, annotator,
- test_delegate);
-}
-
-size_t NativeStackSampler::GetStackBufferSize() {
- // In platform_thread_mac's GetDefaultThreadStackSize(), RLIMIT_STACK is used
- // for all stacks, not just the main thread's, so it is good for use here.
- struct rlimit stack_rlimit;
- if (getrlimit(RLIMIT_STACK, &stack_rlimit) == 0 &&
- stack_rlimit.rlim_cur != RLIM_INFINITY) {
- return stack_rlimit.rlim_cur;
- }
-
- // If getrlimit somehow fails, return the default macOS main thread stack size
- // of 8 MB (DFLSSIZ in <i386/vmparam.h>) with extra wiggle room.
- return 12 * 1024 * 1024;
-}
-
-} // namespace base
diff --git a/base/profiler/native_stack_sampler_posix.cc b/base/profiler/native_stack_sampler_posix.cc
deleted file mode 100644
index 1055d44..0000000
--- a/base/profiler/native_stack_sampler_posix.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/profiler/native_stack_sampler.h"
-
-namespace base {
-
-std::unique_ptr<NativeStackSampler> NativeStackSampler::Create(
- PlatformThreadId thread_id,
- AnnotateCallback annotator,
- NativeStackSamplerTestDelegate* test_delegate) {
- return std::unique_ptr<NativeStackSampler>();
-}
-
-size_t NativeStackSampler::GetStackBufferSize() {
- return 0;
-}
-
-} // namespace base
diff --git a/base/profiler/native_stack_sampler_win.cc b/base/profiler/native_stack_sampler_win.cc
deleted file mode 100644
index b53197d..0000000
--- a/base/profiler/native_stack_sampler_win.cc
+++ /dev/null
@@ -1,562 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/profiler/native_stack_sampler.h"
-
-#include <objbase.h>
-#include <windows.h>
-#include <stddef.h>
-#include <winternl.h>
-
-#include <cstdlib>
-#include <map>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/profiler/win32_stack_frame_unwinder.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "base/win/pe_image.h"
-#include "base/win/scoped_handle.h"
-
-namespace base {
-
-// Stack recording functions --------------------------------------------------
-
-namespace {
-
-// The thread environment block internal type.
-struct TEB {
- NT_TIB Tib;
- // Rest of struct is ignored.
-};
-
-// Returns the thread environment block pointer for |thread_handle|.
-const TEB* GetThreadEnvironmentBlock(HANDLE thread_handle) {
- // Define the internal types we need to invoke NtQueryInformationThread.
- enum THREAD_INFORMATION_CLASS { ThreadBasicInformation };
-
- struct CLIENT_ID {
- HANDLE UniqueProcess;
- HANDLE UniqueThread;
- };
-
- struct THREAD_BASIC_INFORMATION {
- NTSTATUS ExitStatus;
- TEB* Teb;
- CLIENT_ID ClientId;
- KAFFINITY AffinityMask;
- LONG Priority;
- LONG BasePriority;
- };
-
- using NtQueryInformationThreadFunction =
- NTSTATUS (WINAPI*)(HANDLE, THREAD_INFORMATION_CLASS, PVOID, ULONG,
- PULONG);
-
- const NtQueryInformationThreadFunction nt_query_information_thread =
- reinterpret_cast<NtQueryInformationThreadFunction>(
- ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"),
- "NtQueryInformationThread"));
- if (!nt_query_information_thread)
- return nullptr;
-
- THREAD_BASIC_INFORMATION basic_info = {0};
- NTSTATUS status =
- nt_query_information_thread(thread_handle, ThreadBasicInformation,
- &basic_info, sizeof(THREAD_BASIC_INFORMATION),
- nullptr);
- if (status != 0)
- return nullptr;
-
- return basic_info.Teb;
-}
-
-#if defined(_WIN64)
-// If the value at |pointer| points to the original stack, rewrite it to point
-// to the corresponding location in the copied stack.
-void RewritePointerIfInOriginalStack(uintptr_t top, uintptr_t bottom,
- void* stack_copy, const void** pointer) {
- const uintptr_t value = reinterpret_cast<uintptr_t>(*pointer);
- if (value >= bottom && value < top) {
- *pointer = reinterpret_cast<const void*>(
- static_cast<unsigned char*>(stack_copy) + (value - bottom));
- }
-}
-#endif
-
-void CopyMemoryFromStack(void* to, const void* from, size_t length)
- NO_SANITIZE("address") {
-#if defined(ADDRESS_SANITIZER)
- // The following loop is an inlined version of memcpy. The code must be
- // inlined to avoid instrumentation when using ASAN (memory sanitizer). The
- // stack profiler is generating false positive when walking the stack.
- for (size_t pos = 0; pos < length; ++pos)
- reinterpret_cast<char*>(to)[pos] = reinterpret_cast<const char*>(from)[pos];
-#else
- std::memcpy(to, from, length);
-#endif
-}
-
-// Rewrites possible pointers to locations within the stack to point to the
-// corresponding locations in the copy, and rewrites the non-volatile registers
-// in |context| likewise. This is necessary to handle stack frames with dynamic
-// stack allocation, where a pointer to the beginning of the dynamic allocation
-// area is stored on the stack and/or in a non-volatile register.
-//
-// Eager rewriting of anything that looks like a pointer to the stack, as done
-// in this function, does not adversely affect the stack unwinding. The only
-// other values on the stack the unwinding depends on are return addresses,
-// which should not point within the stack memory. The rewriting is guaranteed
-// to catch all pointers because the stacks are guaranteed by the ABI to be
-// sizeof(void*) aligned.
-//
-// Note: this function must not access memory in the original stack as it may
-// have been changed or deallocated by this point. This is why |top| and
-// |bottom| are passed as uintptr_t.
-void RewritePointersToStackMemory(uintptr_t top, uintptr_t bottom,
- CONTEXT* context, void* stack_copy) {
-#if defined(_WIN64)
- DWORD64 CONTEXT::* const nonvolatile_registers[] = {
- &CONTEXT::R12,
- &CONTEXT::R13,
- &CONTEXT::R14,
- &CONTEXT::R15,
- &CONTEXT::Rdi,
- &CONTEXT::Rsi,
- &CONTEXT::Rbx,
- &CONTEXT::Rbp,
- &CONTEXT::Rsp
- };
-
- // Rewrite pointers in the context.
- for (size_t i = 0; i < arraysize(nonvolatile_registers); ++i) {
- DWORD64* const reg = &(context->*nonvolatile_registers[i]);
- RewritePointerIfInOriginalStack(top, bottom, stack_copy,
- reinterpret_cast<const void**>(reg));
- }
-
- // Rewrite pointers on the stack.
- const void** start = reinterpret_cast<const void**>(stack_copy);
- const void** end = reinterpret_cast<const void**>(
- reinterpret_cast<char*>(stack_copy) + (top - bottom));
- for (const void** loc = start; loc < end; ++loc)
- RewritePointerIfInOriginalStack(top, bottom, stack_copy, loc);
-#endif
-}
-
-// Movable type representing a recorded stack frame.
-struct RecordedFrame {
- RecordedFrame() {}
-
- RecordedFrame(RecordedFrame&& other)
- : instruction_pointer(other.instruction_pointer),
- module(std::move(other.module)) {
- }
-
- RecordedFrame& operator=(RecordedFrame&& other) {
- instruction_pointer = other.instruction_pointer;
- module = std::move(other.module);
- return *this;
- }
-
- const void* instruction_pointer;
- ScopedModuleHandle module;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(RecordedFrame);
-};
-
-// Walks the stack represented by |context| from the current frame downwards,
-// recording the instruction pointer and associated module for each frame in
-// |stack|.
-void RecordStack(CONTEXT* context, std::vector<RecordedFrame>* stack) {
-#ifdef _WIN64
- DCHECK(stack->empty());
-
- // Reserve enough memory for most stacks, to avoid repeated
- // allocations. Approximately 99.9% of recorded stacks are 128 frames or
- // fewer.
- stack->reserve(128);
-
- Win32StackFrameUnwinder frame_unwinder;
- while (context->Rip) {
- const void* instruction_pointer =
- reinterpret_cast<const void*>(context->Rip);
- ScopedModuleHandle module;
- if (!frame_unwinder.TryUnwind(context, &module))
- return;
- RecordedFrame frame;
- frame.instruction_pointer = instruction_pointer;
- frame.module = std::move(module);
- stack->push_back(std::move(frame));
- }
-#endif
-}
-
-// Gets the unique build ID for a module. Windows build IDs are created by a
-// concatenation of a GUID and AGE fields found in the headers of a module. The
-// GUID is stored in the first 16 bytes and the AGE is stored in the last 4
-// bytes. Returns the empty string if the function fails to get the build ID.
-//
-// Example:
-// dumpbin chrome.exe /headers | find "Format:"
-// ... Format: RSDS, {16B2A428-1DED-442E-9A36-FCE8CBD29726}, 10, ...
-//
-// The resulting buildID string of this instance of chrome.exe is
-// "16B2A4281DED442E9A36FCE8CBD2972610".
-//
-// Note that the AGE field is encoded in decimal, not hex.
-std::string GetBuildIDForModule(HMODULE module_handle) {
- GUID guid;
- DWORD age;
- win::PEImage(module_handle).GetDebugId(&guid, &age, /* pdb_file= */ nullptr);
- const int kGUIDSize = 39;
- std::wstring build_id;
- int result =
- ::StringFromGUID2(guid, WriteInto(&build_id, kGUIDSize), kGUIDSize);
- if (result != kGUIDSize)
- return std::string();
- RemoveChars(build_id, L"{}-", &build_id);
- build_id += StringPrintf(L"%d", age);
- return WideToUTF8(build_id);
-}
-
-// ScopedDisablePriorityBoost -------------------------------------------------
-
-// Disables priority boost on a thread for the lifetime of the object.
-class ScopedDisablePriorityBoost {
- public:
- ScopedDisablePriorityBoost(HANDLE thread_handle);
- ~ScopedDisablePriorityBoost();
-
- private:
- HANDLE thread_handle_;
- BOOL got_previous_boost_state_;
- BOOL boost_state_was_disabled_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedDisablePriorityBoost);
-};
-
-ScopedDisablePriorityBoost::ScopedDisablePriorityBoost(HANDLE thread_handle)
- : thread_handle_(thread_handle),
- got_previous_boost_state_(false),
- boost_state_was_disabled_(false) {
- got_previous_boost_state_ =
- ::GetThreadPriorityBoost(thread_handle_, &boost_state_was_disabled_);
- if (got_previous_boost_state_) {
- // Confusingly, TRUE disables priority boost.
- ::SetThreadPriorityBoost(thread_handle_, TRUE);
- }
-}
-
-ScopedDisablePriorityBoost::~ScopedDisablePriorityBoost() {
- if (got_previous_boost_state_)
- ::SetThreadPriorityBoost(thread_handle_, boost_state_was_disabled_);
-}
-
-// ScopedSuspendThread --------------------------------------------------------
-
-// Suspends a thread for the lifetime of the object.
-class ScopedSuspendThread {
- public:
- ScopedSuspendThread(HANDLE thread_handle);
- ~ScopedSuspendThread();
-
- bool was_successful() const { return was_successful_; }
-
- private:
- HANDLE thread_handle_;
- bool was_successful_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedSuspendThread);
-};
-
-ScopedSuspendThread::ScopedSuspendThread(HANDLE thread_handle)
- : thread_handle_(thread_handle),
- was_successful_(::SuspendThread(thread_handle) !=
- static_cast<DWORD>(-1)) {}
-
-ScopedSuspendThread::~ScopedSuspendThread() {
- if (!was_successful_)
- return;
-
- // Disable the priority boost that the thread would otherwise receive on
- // resume. We do this to avoid artificially altering the dynamics of the
- // executing application any more than we already are by suspending and
- // resuming the thread.
- //
- // Note that this can racily disable a priority boost that otherwise would
- // have been given to the thread, if the thread is waiting on other wait
- // conditions at the time of SuspendThread and those conditions are satisfied
- // before priority boost is reenabled. The measured length of this window is
- // ~100us, so this should occur fairly rarely.
- ScopedDisablePriorityBoost disable_priority_boost(thread_handle_);
- bool resume_thread_succeeded =
- ::ResumeThread(thread_handle_) != static_cast<DWORD>(-1);
- CHECK(resume_thread_succeeded) << "ResumeThread failed: " << GetLastError();
-}
-
-// Tests whether |stack_pointer| points to a location in the guard page.
-//
-// IMPORTANT NOTE: This function is invoked while the target thread is
-// suspended so it must not do any allocation from the default heap, including
-// indirectly via use of DCHECK/CHECK or other logging statements. Otherwise
-// this code can deadlock on heap locks in the default heap acquired by the
-// target thread before it was suspended.
-bool PointsToGuardPage(uintptr_t stack_pointer) {
- MEMORY_BASIC_INFORMATION memory_info;
- SIZE_T result = ::VirtualQuery(reinterpret_cast<LPCVOID>(stack_pointer),
- &memory_info,
- sizeof(memory_info));
- return result != 0 && (memory_info.Protect & PAGE_GUARD);
-}
-
-// Suspends the thread with |thread_handle|, copies its stack and resumes the
-// thread, then records the stack frames and associated modules into |stack|.
-//
-// IMPORTANT NOTE: No allocations from the default heap may occur in the
-// ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or
-// other logging statements. Otherwise this code can deadlock on heap locks in
-// the default heap acquired by the target thread before it was suspended.
-void SuspendThreadAndRecordStack(
- HANDLE thread_handle,
- const void* base_address,
- void* stack_copy_buffer,
- size_t stack_copy_buffer_size,
- std::vector<RecordedFrame>* stack,
- NativeStackSampler::AnnotateCallback annotator,
- StackSamplingProfiler::Sample* sample,
- NativeStackSamplerTestDelegate* test_delegate) {
- DCHECK(stack->empty());
-
- CONTEXT thread_context = {0};
- thread_context.ContextFlags = CONTEXT_FULL;
- // The stack bounds are saved to uintptr_ts for use outside
- // ScopedSuspendThread, as the thread's memory is not safe to dereference
- // beyond that point.
- const uintptr_t top = reinterpret_cast<uintptr_t>(base_address);
- uintptr_t bottom = 0u;
-
- {
- ScopedSuspendThread suspend_thread(thread_handle);
-
- if (!suspend_thread.was_successful())
- return;
-
- if (!::GetThreadContext(thread_handle, &thread_context))
- return;
-#if defined(_WIN64)
- bottom = thread_context.Rsp;
-#else
- bottom = thread_context.Esp;
-#endif
-
- if ((top - bottom) > stack_copy_buffer_size)
- return;
-
- // Dereferencing a pointer in the guard page in a thread that doesn't own
- // the stack results in a STATUS_GUARD_PAGE_VIOLATION exception and a crash.
- // This occurs very rarely, but reliably over the population.
- if (PointsToGuardPage(bottom))
- return;
-
- (*annotator)(sample);
-
- CopyMemoryFromStack(stack_copy_buffer,
- reinterpret_cast<const void*>(bottom), top - bottom);
- }
-
- if (test_delegate)
- test_delegate->OnPreStackWalk();
-
- RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer);
-
- RecordStack(&thread_context, stack);
-}
-
-// NativeStackSamplerWin ------------------------------------------------------
-
-class NativeStackSamplerWin : public NativeStackSampler {
- public:
- NativeStackSamplerWin(win::ScopedHandle thread_handle,
- AnnotateCallback annotator,
- NativeStackSamplerTestDelegate* test_delegate);
- ~NativeStackSamplerWin() override;
-
- // StackSamplingProfiler::NativeStackSampler:
- void ProfileRecordingStarting(
- std::vector<StackSamplingProfiler::Module>* modules) override;
- void RecordStackSample(StackBuffer* stack_buffer,
- StackSamplingProfiler::Sample* sample) override;
- void ProfileRecordingStopped(StackBuffer* stack_buffer) override;
-
- private:
- // Attempts to query the module filename, base address, and id for
- // |module_handle|, and store them in |module|. Returns true if it succeeded.
- static bool GetModuleForHandle(HMODULE module_handle,
- StackSamplingProfiler::Module* module);
-
- // Gets the index for the Module corresponding to |module_handle| in
- // |modules|, adding it if it's not already present. Returns
- // StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be
- // determined for |module|.
- size_t GetModuleIndex(HMODULE module_handle,
- std::vector<StackSamplingProfiler::Module>* modules);
-
- // Copies the information represented by |stack| into |sample| and |modules|.
- void CopyToSample(const std::vector<RecordedFrame>& stack,
- StackSamplingProfiler::Sample* sample,
- std::vector<StackSamplingProfiler::Module>* modules);
-
- win::ScopedHandle thread_handle_;
-
- const AnnotateCallback annotator_;
-
- NativeStackSamplerTestDelegate* const test_delegate_;
-
- // The stack base address corresponding to |thread_handle_|.
- const void* const thread_stack_base_address_;
-
- // Weak. Points to the modules associated with the profile being recorded
- // between ProfileRecordingStarting() and ProfileRecordingStopped().
- std::vector<StackSamplingProfiler::Module>* current_modules_;
-
- // Maps a module handle to the corresponding Module's index within
- // current_modules_.
- std::map<HMODULE, size_t> profile_module_index_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin);
-};
-
-NativeStackSamplerWin::NativeStackSamplerWin(
- win::ScopedHandle thread_handle,
- AnnotateCallback annotator,
- NativeStackSamplerTestDelegate* test_delegate)
- : thread_handle_(thread_handle.Take()),
- annotator_(annotator),
- test_delegate_(test_delegate),
- thread_stack_base_address_(
- GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase) {
- DCHECK(annotator_);
-}
-
-NativeStackSamplerWin::~NativeStackSamplerWin() {
-}
-
-void NativeStackSamplerWin::ProfileRecordingStarting(
- std::vector<StackSamplingProfiler::Module>* modules) {
- current_modules_ = modules;
- profile_module_index_.clear();
-}
-
-void NativeStackSamplerWin::RecordStackSample(
- StackBuffer* stack_buffer,
- StackSamplingProfiler::Sample* sample) {
- DCHECK(stack_buffer);
- DCHECK(current_modules_);
-
- std::vector<RecordedFrame> stack;
- SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_,
- stack_buffer->buffer(), stack_buffer->size(),
- &stack, annotator_, sample, test_delegate_);
- CopyToSample(stack, sample, current_modules_);
-}
-
-void NativeStackSamplerWin::ProfileRecordingStopped(StackBuffer* stack_buffer) {
- current_modules_ = nullptr;
-}
-
-// static
-bool NativeStackSamplerWin::GetModuleForHandle(
- HMODULE module_handle,
- StackSamplingProfiler::Module* module) {
- wchar_t module_name[MAX_PATH];
- DWORD result_length =
- GetModuleFileName(module_handle, module_name, arraysize(module_name));
- if (result_length == 0)
- return false;
-
- module->filename = base::FilePath(module_name);
-
- module->base_address = reinterpret_cast<uintptr_t>(module_handle);
-
- module->id = GetBuildIDForModule(module_handle);
- if (module->id.empty())
- return false;
-
- return true;
-}
-
-size_t NativeStackSamplerWin::GetModuleIndex(
- HMODULE module_handle,
- std::vector<StackSamplingProfiler::Module>* modules) {
- if (!module_handle)
- return StackSamplingProfiler::Frame::kUnknownModuleIndex;
-
- auto loc = profile_module_index_.find(module_handle);
- if (loc == profile_module_index_.end()) {
- StackSamplingProfiler::Module module;
- if (!GetModuleForHandle(module_handle, &module))
- return StackSamplingProfiler::Frame::kUnknownModuleIndex;
- modules->push_back(module);
- loc = profile_module_index_.insert(std::make_pair(
- module_handle, modules->size() - 1)).first;
- }
-
- return loc->second;
-}
-
-void NativeStackSamplerWin::CopyToSample(
- const std::vector<RecordedFrame>& stack,
- StackSamplingProfiler::Sample* sample,
- std::vector<StackSamplingProfiler::Module>* modules) {
- sample->frames.clear();
- sample->frames.reserve(stack.size());
-
- for (const RecordedFrame& frame : stack) {
- sample->frames.push_back(StackSamplingProfiler::Frame(
- reinterpret_cast<uintptr_t>(frame.instruction_pointer),
- GetModuleIndex(frame.module.Get(), modules)));
- }
-}
-
-} // namespace
-
-std::unique_ptr<NativeStackSampler> NativeStackSampler::Create(
- PlatformThreadId thread_id,
- AnnotateCallback annotator,
- NativeStackSamplerTestDelegate* test_delegate) {
-#if _WIN64
- // Get the thread's handle.
- HANDLE thread_handle = ::OpenThread(
- THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION,
- FALSE,
- thread_id);
-
- if (thread_handle) {
- return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin(
- win::ScopedHandle(thread_handle), annotator, test_delegate));
- }
-#endif
- return std::unique_ptr<NativeStackSampler>();
-}
-
-size_t NativeStackSampler::GetStackBufferSize() {
- // The default Win32 reserved stack size is 1 MB and Chrome Windows threads
- // currently always use the default, but this allows for expansion if it
- // occurs. The size beyond the actual stack size consists of unallocated
- // virtual memory pages so carries little cost (just a bit of wasted address
- // space).
- return 2 << 20; // 2 MiB
-}
-
-} // namespace base
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc
deleted file mode 100644
index a8cddf0..0000000
--- a/base/profiler/stack_sampling_profiler.cc
+++ /dev/null
@@ -1,890 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/profiler/stack_sampling_profiler.h"
-
-#include <algorithm>
-#include <map>
-#include <utility>
-
-#include "base/atomic_sequence_num.h"
-#include "base/atomicops.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/lazy_instance.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/singleton.h"
-#include "base/profiler/native_stack_sampler.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/timer/elapsed_timer.h"
-
-namespace base {
-
-namespace {
-
-// This value is used to initialize the WaitableEvent object. This MUST BE set
-// to MANUAL for correct operation of the IsSignaled() call in Start(). See the
-// comment there for why.
-constexpr WaitableEvent::ResetPolicy kResetPolicy =
- WaitableEvent::ResetPolicy::MANUAL;
-
-// This value is used when there is no collection in progress and thus no ID
-// for referencing the active collection to the SamplingThread.
-const int NULL_PROFILER_ID = -1;
-
-void ChangeAtomicFlags(subtle::Atomic32* flags,
- subtle::Atomic32 set,
- subtle::Atomic32 clear) {
- DCHECK(set != 0 || clear != 0);
- DCHECK_EQ(0, set & clear);
-
- subtle::Atomic32 bits = subtle::NoBarrier_Load(flags);
- while (true) {
- subtle::Atomic32 existing =
- subtle::NoBarrier_CompareAndSwap(flags, bits, (bits | set) & ~clear);
- if (existing == bits)
- break;
- bits = existing;
- }
-}
-
-} // namespace
-
-// StackSamplingProfiler::Module ----------------------------------------------
-
-StackSamplingProfiler::Module::Module() : base_address(0u) {}
-StackSamplingProfiler::Module::Module(uintptr_t base_address,
- const std::string& id,
- const FilePath& filename)
- : base_address(base_address), id(id), filename(filename) {}
-
-StackSamplingProfiler::Module::~Module() = default;
-
-// StackSamplingProfiler::Frame -----------------------------------------------
-
-StackSamplingProfiler::Frame::Frame(uintptr_t instruction_pointer,
- size_t module_index)
- : instruction_pointer(instruction_pointer), module_index(module_index) {}
-
-StackSamplingProfiler::Frame::~Frame() = default;
-
-StackSamplingProfiler::Frame::Frame()
- : instruction_pointer(0), module_index(kUnknownModuleIndex) {
-}
-
-// StackSamplingProfiler::Sample ----------------------------------------------
-
-StackSamplingProfiler::Sample::Sample() = default;
-
-StackSamplingProfiler::Sample::Sample(const Sample& sample) = default;
-
-StackSamplingProfiler::Sample::~Sample() = default;
-
-StackSamplingProfiler::Sample::Sample(const Frame& frame) {
- frames.push_back(std::move(frame));
-}
-
-StackSamplingProfiler::Sample::Sample(const std::vector<Frame>& frames)
- : frames(frames) {}
-
-// StackSamplingProfiler::CallStackProfile ------------------------------------
-
-StackSamplingProfiler::CallStackProfile::CallStackProfile() = default;
-
-StackSamplingProfiler::CallStackProfile::CallStackProfile(
- CallStackProfile&& other) = default;
-
-StackSamplingProfiler::CallStackProfile::~CallStackProfile() = default;
-
-StackSamplingProfiler::CallStackProfile&
-StackSamplingProfiler::CallStackProfile::operator=(CallStackProfile&& other) =
- default;
-
-StackSamplingProfiler::CallStackProfile
-StackSamplingProfiler::CallStackProfile::CopyForTesting() const {
- return CallStackProfile(*this);
-}
-
-StackSamplingProfiler::CallStackProfile::CallStackProfile(
- const CallStackProfile& other) = default;
-
-// StackSamplingProfiler::SamplingThread --------------------------------------
-
-class StackSamplingProfiler::SamplingThread : public Thread {
- public:
- class TestAPI {
- public:
- // Reset the existing sampler. This will unfortunately create the object
- // unnecessarily if it doesn't already exist but there's no way around that.
- static void Reset();
-
- // Disables inherent idle-shutdown behavior.
- static void DisableIdleShutdown();
-
- // Begins an idle shutdown as if the idle-timer had expired and wait for
- // it to execute. Since the timer would have only been started at a time
- // when the sampling thread actually was idle, this must be called only
- // when it is known that there are no active sampling threads. If
- // |simulate_intervening_add| is true then, when executed, the shutdown
- // task will believe that a new collection has been added since it was
- // posted.
- static void ShutdownAssumingIdle(bool simulate_intervening_add);
-
- private:
- // Calls the sampling threads ShutdownTask and then signals an event.
- static void ShutdownTaskAndSignalEvent(SamplingThread* sampler,
- int add_events,
- WaitableEvent* event);
- };
-
- struct CollectionContext {
- CollectionContext(int profiler_id,
- PlatformThreadId target,
- const SamplingParams& params,
- const CompletedCallback& callback,
- WaitableEvent* finished,
- std::unique_ptr<NativeStackSampler> sampler)
- : profiler_id(profiler_id),
- target(target),
- params(params),
- callback(callback),
- finished(finished),
- native_sampler(std::move(sampler)) {}
- ~CollectionContext() = default;
-
- // An identifier for the profiler associated with this collection, used to
- // uniquely identify the collection to outside interests.
- const int profiler_id;
-
- const PlatformThreadId target; // ID of The thread being sampled.
- const SamplingParams params; // Information about how to sample.
- const CompletedCallback callback; // Callback made when sampling complete.
- WaitableEvent* const finished; // Signaled when all sampling complete.
-
- // Platform-specific module that does the actual sampling.
- std::unique_ptr<NativeStackSampler> native_sampler;
-
- // The absolute time for the next sample.
- Time next_sample_time;
-
- // The time that a profile was started, for calculating the total duration.
- Time profile_start_time;
-
- // Counters that indicate the current position along the acquisition.
- int burst = 0;
- int sample = 0;
-
- // The collected stack samples. The active profile is always at the back().
- CallStackProfiles profiles;
-
- // Sequence number for generating new profiler ids.
- static AtomicSequenceNumber next_profiler_id;
- };
-
- // Gets the single instance of this class.
- static SamplingThread* GetInstance();
-
- // Adds a new CollectionContext to the thread. This can be called externally
- // from any thread. This returns an ID that can later be used to stop
- // the sampling.
- int Add(std::unique_ptr<CollectionContext> collection);
-
- // Removes an active collection based on its ID, forcing it to run its
- // callback if any data has been collected. This can be called externally
- // from any thread.
- void Remove(int id);
-
- private:
- friend class TestAPI;
- friend struct DefaultSingletonTraits<SamplingThread>;
-
- // The different states in which the sampling-thread can be.
- enum ThreadExecutionState {
- // The thread is not running because it has never been started. It will be
- // started when a sampling request is received.
- NOT_STARTED,
-
- // The thread is running and processing tasks. This is the state when any
- // sampling requests are active and during the "idle" period afterward
- // before the thread is stopped.
- RUNNING,
-
- // Once all sampling requests have finished and the "idle" period has
- // expired, the thread will be set to this state and its shutdown
- // initiated. A call to Stop() must be made to ensure the previous thread
- // has completely exited before calling Start() and moving back to the
- // RUNNING state.
- EXITING,
- };
-
- SamplingThread();
- ~SamplingThread() override;
-
- // Get task runner that is usable from the outside.
- scoped_refptr<SingleThreadTaskRunner> GetOrCreateTaskRunnerForAdd();
- scoped_refptr<SingleThreadTaskRunner> GetTaskRunner(
- ThreadExecutionState* out_state);
-
- // Get task runner that is usable from the sampling thread itself.
- scoped_refptr<SingleThreadTaskRunner> GetTaskRunnerOnSamplingThread();
-
- // Finishes a collection and reports collected data via callback. The
- // collection's |finished| waitable event will be signalled. The |collection|
- // should already have been removed from |active_collections_| by the caller,
- // as this is needed to avoid flakyness in unit tests.
- void FinishCollection(CollectionContext* collection);
-
- // Records a single sample of a collection.
- void RecordSample(CollectionContext* collection);
-
- // Check if the sampling thread is idle and begin a shutdown if it is.
- void ScheduleShutdownIfIdle();
-
- // These methods are tasks that get posted to the internal message queue.
- void AddCollectionTask(std::unique_ptr<CollectionContext> collection);
- void RemoveCollectionTask(int id);
- void PerformCollectionTask(int id);
- void ShutdownTask(int add_events);
-
- // Updates the |next_sample_time| time based on configured parameters.
- // Returns true if there is a next sample or false if sampling is complete.
- bool UpdateNextSampleTime(CollectionContext* collection);
-
- // Thread:
- void CleanUp() override;
-
- // A stack-buffer used by the native sampler for its work. This buffer can
- // be re-used for multiple native sampler objects so long as the API calls
- // that take it are not called concurrently.
- std::unique_ptr<NativeStackSampler::StackBuffer> stack_buffer_;
-
- // A map of IDs to collection contexts. Because this class is a singleton
- // that is never destroyed, context objects will never be destructed except
- // by explicit action. Thus, it's acceptable to pass unretained pointers
- // to these objects when posting tasks.
- std::map<int, std::unique_ptr<CollectionContext>> active_collections_;
-
- // State maintained about the current execution (or non-execution) of
- // the thread. This state must always be accessed while holding the
- // lock. A copy of the task-runner is maintained here for use by any
- // calling thread; this is necessary because Thread's accessor for it is
- // not itself thread-safe. The lock is also used to order calls to the
- // Thread API (Start, Stop, StopSoon, & DetachFromSequence) so that
- // multiple threads may make those calls.
- Lock thread_execution_state_lock_; // Protects all thread_execution_state_*
- ThreadExecutionState thread_execution_state_ = NOT_STARTED;
- scoped_refptr<SingleThreadTaskRunner> thread_execution_state_task_runner_;
- bool thread_execution_state_disable_idle_shutdown_for_testing_ = false;
-
- // A counter that notes adds of new collection requests. It is incremented
- // when changes occur so that delayed shutdown tasks are able to detect if
- // samething new has happened while it was waiting. Like all "execution_state"
- // vars, this must be accessed while holding |thread_execution_state_lock_|.
- int thread_execution_state_add_events_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(SamplingThread);
-};
-
-// static
-void StackSamplingProfiler::SamplingThread::TestAPI::Reset() {
- SamplingThread* sampler = SamplingThread::GetInstance();
-
- ThreadExecutionState state;
- {
- AutoLock lock(sampler->thread_execution_state_lock_);
- state = sampler->thread_execution_state_;
- DCHECK(sampler->active_collections_.empty());
- }
-
- // Stop the thread and wait for it to exit. This has to be done through by
- // the thread itself because it has taken ownership of its own lifetime.
- if (state == RUNNING) {
- ShutdownAssumingIdle(false);
- state = EXITING;
- }
- // Make sure thread is cleaned up since state will be reset to NOT_STARTED.
- if (state == EXITING)
- sampler->Stop();
-
- // Reset internal variables to the just-initialized state.
- {
- AutoLock lock(sampler->thread_execution_state_lock_);
- sampler->thread_execution_state_ = NOT_STARTED;
- sampler->thread_execution_state_task_runner_ = nullptr;
- sampler->thread_execution_state_disable_idle_shutdown_for_testing_ = false;
- sampler->thread_execution_state_add_events_ = 0;
- }
-}
-
-// static
-void StackSamplingProfiler::SamplingThread::TestAPI::DisableIdleShutdown() {
- SamplingThread* sampler = SamplingThread::GetInstance();
-
- {
- AutoLock lock(sampler->thread_execution_state_lock_);
- sampler->thread_execution_state_disable_idle_shutdown_for_testing_ = true;
- }
-}
-
-// static
-void StackSamplingProfiler::SamplingThread::TestAPI::ShutdownAssumingIdle(
- bool simulate_intervening_add) {
- SamplingThread* sampler = SamplingThread::GetInstance();
-
- ThreadExecutionState state;
- scoped_refptr<SingleThreadTaskRunner> task_runner =
- sampler->GetTaskRunner(&state);
- DCHECK_EQ(RUNNING, state);
- DCHECK(task_runner);
-
- int add_events;
- {
- AutoLock lock(sampler->thread_execution_state_lock_);
- add_events = sampler->thread_execution_state_add_events_;
- if (simulate_intervening_add)
- ++sampler->thread_execution_state_add_events_;
- }
-
- WaitableEvent executed(WaitableEvent::ResetPolicy::MANUAL,
- WaitableEvent::InitialState::NOT_SIGNALED);
- // PostTaskAndReply won't work because thread and associated message-loop may
- // be shut down.
- task_runner->PostTask(
- FROM_HERE, BindOnce(&ShutdownTaskAndSignalEvent, Unretained(sampler),
- add_events, Unretained(&executed)));
- executed.Wait();
-}
-
-// static
-void StackSamplingProfiler::SamplingThread::TestAPI::ShutdownTaskAndSignalEvent(
- SamplingThread* sampler,
- int add_events,
- WaitableEvent* event) {
- sampler->ShutdownTask(add_events);
- event->Signal();
-}
-
-AtomicSequenceNumber
- StackSamplingProfiler::SamplingThread::CollectionContext::next_profiler_id;
-
-StackSamplingProfiler::SamplingThread::SamplingThread()
- : Thread("StackSamplingProfiler") {}
-
-StackSamplingProfiler::SamplingThread::~SamplingThread() = default;
-
-StackSamplingProfiler::SamplingThread*
-StackSamplingProfiler::SamplingThread::GetInstance() {
- return Singleton<SamplingThread, LeakySingletonTraits<SamplingThread>>::get();
-}
-
-int StackSamplingProfiler::SamplingThread::Add(
- std::unique_ptr<CollectionContext> collection) {
- // This is not to be run on the sampling thread.
-
- int id = collection->profiler_id;
- scoped_refptr<SingleThreadTaskRunner> task_runner =
- GetOrCreateTaskRunnerForAdd();
-
- task_runner->PostTask(
- FROM_HERE, BindOnce(&SamplingThread::AddCollectionTask, Unretained(this),
- std::move(collection)));
-
- return id;
-}
-
-void StackSamplingProfiler::SamplingThread::Remove(int id) {
- // This is not to be run on the sampling thread.
-
- ThreadExecutionState state;
- scoped_refptr<SingleThreadTaskRunner> task_runner = GetTaskRunner(&state);
- if (state != RUNNING)
- return;
- DCHECK(task_runner);
-
- // This can fail if the thread were to exit between acquisition of the task
- // runner above and the call below. In that case, however, everything has
- // stopped so there's no need to try to stop it.
- task_runner->PostTask(
- FROM_HERE,
- BindOnce(&SamplingThread::RemoveCollectionTask, Unretained(this), id));
-}
-
-scoped_refptr<SingleThreadTaskRunner>
-StackSamplingProfiler::SamplingThread::GetOrCreateTaskRunnerForAdd() {
- AutoLock lock(thread_execution_state_lock_);
-
- // The increment of the "add events" count is why this method is to be only
- // called from "add".
- ++thread_execution_state_add_events_;
-
- if (thread_execution_state_ == RUNNING) {
- DCHECK(thread_execution_state_task_runner_);
- // This shouldn't be called from the sampling thread as it's inefficient.
- // Use GetTaskRunnerOnSamplingThread() instead.
- DCHECK_NE(GetThreadId(), PlatformThread::CurrentId());
- return thread_execution_state_task_runner_;
- }
-
- if (thread_execution_state_ == EXITING) {
- // StopSoon() was previously called to shut down the thread
- // asynchonously. Stop() must now be called before calling Start() again to
- // reset the thread state.
- //
- // We must allow blocking here to satisfy the Thread implementation, but in
- // practice the Stop() call is unlikely to actually block. For this to
- // happen a new profiling request would have to be made within the narrow
- // window between StopSoon() and thread exit following the end of the 60
- // second idle period.
- ScopedAllowBlocking allow_blocking;
- Stop();
- }
-
- DCHECK(!stack_buffer_);
- stack_buffer_ = NativeStackSampler::CreateStackBuffer();
-
- // The thread is not running. Start it and get associated runner. The task-
- // runner has to be saved for future use because though it can be used from
- // any thread, it can be acquired via task_runner() only on the created
- // thread and the thread that creates it (i.e. this thread) for thread-safety
- // reasons which are alleviated in SamplingThread by gating access to it with
- // the |thread_execution_state_lock_|.
- Start();
- thread_execution_state_ = RUNNING;
- thread_execution_state_task_runner_ = Thread::task_runner();
-
- // Detach the sampling thread from the "sequence" (i.e. thread) that
- // started it so that it can be self-managed or stopped by another thread.
- DetachFromSequence();
-
- return thread_execution_state_task_runner_;
-}
-
-scoped_refptr<SingleThreadTaskRunner>
-StackSamplingProfiler::SamplingThread::GetTaskRunner(
- ThreadExecutionState* out_state) {
- AutoLock lock(thread_execution_state_lock_);
- if (out_state)
- *out_state = thread_execution_state_;
- if (thread_execution_state_ == RUNNING) {
- // This shouldn't be called from the sampling thread as it's inefficient.
- // Use GetTaskRunnerOnSamplingThread() instead.
- DCHECK_NE(GetThreadId(), PlatformThread::CurrentId());
- DCHECK(thread_execution_state_task_runner_);
- } else {
- DCHECK(!thread_execution_state_task_runner_);
- }
-
- return thread_execution_state_task_runner_;
-}
-
-scoped_refptr<SingleThreadTaskRunner>
-StackSamplingProfiler::SamplingThread::GetTaskRunnerOnSamplingThread() {
- // This should be called only from the sampling thread as it has limited
- // accessibility.
- DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
-
- return Thread::task_runner();
-}
-
-void StackSamplingProfiler::SamplingThread::FinishCollection(
- CollectionContext* collection) {
- DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
- DCHECK_EQ(0u, active_collections_.count(collection->profiler_id));
-
- // If there is no duration for the final profile (because it was stopped),
- // calculate it now.
- if (!collection->profiles.empty() &&
- collection->profiles.back().profile_duration == TimeDelta()) {
- collection->profiles.back().profile_duration =
- Time::Now() - collection->profile_start_time +
- collection->params.sampling_interval;
- }
-
- // Extract some information so callback and event-signalling can still be
- // done after the collection has been removed from the list of "active" ones.
- // This allows the the controlling object (and tests using it) to be confident
- // that collection is fully finished when those things occur.
- const CompletedCallback callback = collection->callback;
- CallStackProfiles profiles = std::move(collection->profiles);
- WaitableEvent* finished = collection->finished;
-
- // Run the associated callback, passing the collected profiles.
- callback.Run(std::move(profiles));
-
- // Signal that this collection is finished.
- finished->Signal();
-}
-
-void StackSamplingProfiler::SamplingThread::RecordSample(
- CollectionContext* collection) {
- DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
- DCHECK(collection->native_sampler);
-
- // If this is the first sample of a burst, a new Profile needs to be created
- // and filled.
- if (collection->sample == 0) {
- collection->profiles.push_back(CallStackProfile());
- CallStackProfile& profile = collection->profiles.back();
- profile.sampling_period = collection->params.sampling_interval;
- collection->profile_start_time = Time::Now();
- collection->native_sampler->ProfileRecordingStarting(&profile.modules);
- }
-
- // The currently active profile being captured.
- CallStackProfile& profile = collection->profiles.back();
-
- // Record a single sample.
- profile.samples.push_back(Sample());
- collection->native_sampler->RecordStackSample(stack_buffer_.get(),
- &profile.samples.back());
-
- // If this is the last sample of a burst, record the total time.
- if (collection->sample == collection->params.samples_per_burst - 1) {
- profile.profile_duration = Time::Now() - collection->profile_start_time +
- collection->params.sampling_interval;
- collection->native_sampler->ProfileRecordingStopped(stack_buffer_.get());
- }
-}
-
-void StackSamplingProfiler::SamplingThread::ScheduleShutdownIfIdle() {
- DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
-
- if (!active_collections_.empty())
- return;
-
- int add_events;
- {
- AutoLock lock(thread_execution_state_lock_);
- if (thread_execution_state_disable_idle_shutdown_for_testing_)
- return;
- add_events = thread_execution_state_add_events_;
- }
-
- GetTaskRunnerOnSamplingThread()->PostDelayedTask(
- FROM_HERE,
- BindOnce(&SamplingThread::ShutdownTask, Unretained(this), add_events),
- TimeDelta::FromSeconds(60));
-}
-
-void StackSamplingProfiler::SamplingThread::AddCollectionTask(
- std::unique_ptr<CollectionContext> collection) {
- DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
-
- const int profiler_id = collection->profiler_id;
- const TimeDelta initial_delay = collection->params.initial_delay;
-
- active_collections_.insert(
- std::make_pair(profiler_id, std::move(collection)));
-
- GetTaskRunnerOnSamplingThread()->PostDelayedTask(
- FROM_HERE,
- BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this),
- profiler_id),
- initial_delay);
-
- // Another increment of "add events" serves to invalidate any pending
- // shutdown tasks that may have been initiated between the Add() and this
- // task running.
- {
- AutoLock lock(thread_execution_state_lock_);
- ++thread_execution_state_add_events_;
- }
-}
-
-void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(int id) {
- DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
-
- auto found = active_collections_.find(id);
- if (found == active_collections_.end())
- return;
-
- // Remove |collection| from |active_collections_|.
- std::unique_ptr<CollectionContext> collection = std::move(found->second);
- size_t count = active_collections_.erase(id);
- DCHECK_EQ(1U, count);
-
- FinishCollection(collection.get());
- ScheduleShutdownIfIdle();
-}
-
-void StackSamplingProfiler::SamplingThread::PerformCollectionTask(int id) {
- DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
-
- auto found = active_collections_.find(id);
-
- // The task won't be found if it has been stopped.
- if (found == active_collections_.end())
- return;
-
- CollectionContext* collection = found->second.get();
-
- // Handle first-run with no "next time".
- if (collection->next_sample_time == Time())
- collection->next_sample_time = Time::Now();
-
- // Do the collection of a single sample.
- RecordSample(collection);
-
- // Update the time of the next sample recording.
- const bool collection_finished = !UpdateNextSampleTime(collection);
- if (!collection_finished) {
- bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask(
- FROM_HERE,
- BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), id),
- std::max(collection->next_sample_time - Time::Now(), TimeDelta()));
- DCHECK(success);
- return;
- }
-
- // Take ownership of |collection| and remove it from the map. If collection is
- // to be restarted, a new collection task will be added below.
- std::unique_ptr<CollectionContext> owned_collection =
- std::move(found->second);
- size_t count = active_collections_.erase(id);
- DCHECK_EQ(1U, count);
-
- // All capturing has completed so finish the collection.
- FinishCollection(collection);
- ScheduleShutdownIfIdle();
-}
-
-void StackSamplingProfiler::SamplingThread::ShutdownTask(int add_events) {
- DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
-
- // Holding this lock ensures that any attempt to start another job will
- // get postponed until |thread_execution_state_| is updated, thus eliminating
- // the race in starting a new thread while the previous one is exiting.
- AutoLock lock(thread_execution_state_lock_);
-
- // If the current count of creation requests doesn't match the passed count
- // then other tasks have been created since this was posted. Abort shutdown.
- if (thread_execution_state_add_events_ != add_events)
- return;
-
- // There can be no new AddCollectionTasks at this point because creating
- // those always increments "add events". There may be other requests, like
- // Remove, but it's okay to schedule the thread to stop once they've been
- // executed (i.e. "soon").
- DCHECK(active_collections_.empty());
- StopSoon();
-
- // StopSoon will have set the owning sequence (again) so it must be detached
- // (again) in order for Stop/Start to be called (again) should more work
- // come in. Holding the |thread_execution_state_lock_| ensures the necessary
- // happens-after with regard to this detach and future Thread API calls.
- DetachFromSequence();
-
- // Set the thread_state variable so the thread will be restarted when new
- // work comes in. Remove the |thread_execution_state_task_runner_| to avoid
- // confusion.
- thread_execution_state_ = EXITING;
- thread_execution_state_task_runner_ = nullptr;
- stack_buffer_.reset();
-}
-
-bool StackSamplingProfiler::SamplingThread::UpdateNextSampleTime(
- CollectionContext* collection) {
- // This will keep a consistent average interval between samples but will
- // result in constant series of acquisitions, thus nearly locking out the
- // target thread, if the interval is smaller than the time it takes to
- // actually acquire the sample. Anything sampling that quickly is going
- // to be a problem anyway so don't worry about it.
- if (++collection->sample < collection->params.samples_per_burst) {
- collection->next_sample_time += collection->params.sampling_interval;
- return true;
- }
-
- if (++collection->burst < collection->params.bursts) {
- collection->sample = 0;
- collection->next_sample_time += collection->params.burst_interval;
- return true;
- }
-
- return false;
-}
-
-void StackSamplingProfiler::SamplingThread::CleanUp() {
- DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
-
- // There should be no collections remaining when the thread stops.
- DCHECK(active_collections_.empty());
-
- // Let the parent clean up.
- Thread::CleanUp();
-}
-
-// StackSamplingProfiler ------------------------------------------------------
-
-// static
-void StackSamplingProfiler::TestAPI::Reset() {
- SamplingThread::TestAPI::Reset();
- ResetAnnotations();
-}
-
-// static
-void StackSamplingProfiler::TestAPI::ResetAnnotations() {
- subtle::NoBarrier_Store(&process_milestones_, 0u);
-}
-
-// static
-bool StackSamplingProfiler::TestAPI::IsSamplingThreadRunning() {
- return SamplingThread::GetInstance()->IsRunning();
-}
-
-// static
-void StackSamplingProfiler::TestAPI::DisableIdleShutdown() {
- SamplingThread::TestAPI::DisableIdleShutdown();
-}
-
-// static
-void StackSamplingProfiler::TestAPI::PerformSamplingThreadIdleShutdown(
- bool simulate_intervening_start) {
- SamplingThread::TestAPI::ShutdownAssumingIdle(simulate_intervening_start);
-}
-
-subtle::Atomic32 StackSamplingProfiler::process_milestones_ = 0;
-
-StackSamplingProfiler::StackSamplingProfiler(
- const SamplingParams& params,
- const CompletedCallback& callback,
- NativeStackSamplerTestDelegate* test_delegate)
- : StackSamplingProfiler(base::PlatformThread::CurrentId(),
- params,
- callback,
- test_delegate) {}
-
-StackSamplingProfiler::StackSamplingProfiler(
- PlatformThreadId thread_id,
- const SamplingParams& params,
- const CompletedCallback& callback,
- NativeStackSamplerTestDelegate* test_delegate)
- : thread_id_(thread_id),
- params_(params),
- completed_callback_(callback),
- // The event starts "signaled" so code knows it's safe to start thread
- // and "manual" so that it can be waited in multiple places.
- profiling_inactive_(kResetPolicy, WaitableEvent::InitialState::SIGNALED),
- profiler_id_(NULL_PROFILER_ID),
- test_delegate_(test_delegate) {}
-
-StackSamplingProfiler::~StackSamplingProfiler() {
- // Stop returns immediately but the shutdown runs asynchronously. There is a
- // non-zero probability that one more sample will be taken after this call
- // returns.
- Stop();
-
- // The behavior of sampling a thread that has exited is undefined and could
- // cause Bad Things(tm) to occur. The safety model provided by this class is
- // that an instance of this object is expected to live at least as long as
- // the thread it is sampling. However, because the sampling is performed
- // asynchronously by the SamplingThread, there is no way to guarantee this
- // is true without waiting for it to signal that it has finished.
- //
- // The wait time should, at most, be only as long as it takes to collect one
- // sample (~200us) or none at all if sampling has already completed.
- ThreadRestrictions::ScopedAllowWait allow_wait;
- profiling_inactive_.Wait();
-}
-
-void StackSamplingProfiler::Start() {
- if (completed_callback_.is_null())
- return;
-
- std::unique_ptr<NativeStackSampler> native_sampler =
- NativeStackSampler::Create(thread_id_, &RecordAnnotations,
- test_delegate_);
-
- if (!native_sampler)
- return;
-
- // The IsSignaled() check below requires that the WaitableEvent be manually
- // reset, to avoid signaling the event in IsSignaled() itself.
- static_assert(kResetPolicy == WaitableEvent::ResetPolicy::MANUAL,
- "The reset policy must be set to MANUAL");
-
- // If a previous profiling phase is still winding down, wait for it to
- // complete. We can't use task posting for this coordination because the
- // thread owning the profiler may not have a message loop.
- if (!profiling_inactive_.IsSignaled())
- profiling_inactive_.Wait();
- profiling_inactive_.Reset();
-
- DCHECK_EQ(NULL_PROFILER_ID, profiler_id_);
- profiler_id_ = SamplingThread::GetInstance()->Add(
- std::make_unique<SamplingThread::CollectionContext>(
- SamplingThread::CollectionContext::next_profiler_id.GetNext(),
- thread_id_, params_, completed_callback_, &profiling_inactive_,
- std::move(native_sampler)));
- DCHECK_NE(NULL_PROFILER_ID, profiler_id_);
-}
-
-void StackSamplingProfiler::Stop() {
- SamplingThread::GetInstance()->Remove(profiler_id_);
- profiler_id_ = NULL_PROFILER_ID;
-}
-
-// static
-void StackSamplingProfiler::SetProcessMilestone(int milestone) {
- DCHECK_LE(0, milestone);
- DCHECK_GT(static_cast<int>(sizeof(process_milestones_) * 8), milestone);
- DCHECK_EQ(0, subtle::NoBarrier_Load(&process_milestones_) & (1 << milestone));
- ChangeAtomicFlags(&process_milestones_, 1 << milestone, 0);
-}
-
-// static
-void StackSamplingProfiler::RecordAnnotations(Sample* sample) {
- // The code inside this method must not do anything that could acquire a
- // mutex, including allocating memory (which includes LOG messages) because
- // that mutex could be held by a stopped thread, thus resulting in deadlock.
- sample->process_milestones = subtle::NoBarrier_Load(&process_milestones_);
-}
-
-// StackSamplingProfiler::Frame global functions ------------------------------
-
-bool operator==(const StackSamplingProfiler::Module& a,
- const StackSamplingProfiler::Module& b) {
- return a.base_address == b.base_address && a.id == b.id &&
- a.filename == b.filename;
-}
-
-bool operator==(const StackSamplingProfiler::Sample& a,
- const StackSamplingProfiler::Sample& b) {
- return a.process_milestones == b.process_milestones && a.frames == b.frames;
-}
-
-bool operator!=(const StackSamplingProfiler::Sample& a,
- const StackSamplingProfiler::Sample& b) {
- return !(a == b);
-}
-
-bool operator<(const StackSamplingProfiler::Sample& a,
- const StackSamplingProfiler::Sample& b) {
- if (a.process_milestones < b.process_milestones)
- return true;
- if (a.process_milestones > b.process_milestones)
- return false;
-
- return a.frames < b.frames;
-}
-
-bool operator==(const StackSamplingProfiler::Frame &a,
- const StackSamplingProfiler::Frame &b) {
- return a.instruction_pointer == b.instruction_pointer &&
- a.module_index == b.module_index;
-}
-
-bool operator<(const StackSamplingProfiler::Frame &a,
- const StackSamplingProfiler::Frame &b) {
- return (a.module_index < b.module_index) ||
- (a.module_index == b.module_index &&
- a.instruction_pointer < b.instruction_pointer);
-}
-
-} // namespace base
diff --git a/base/profiler/stack_sampling_profiler.h b/base/profiler/stack_sampling_profiler.h
deleted file mode 100644
index 2f9ade5..0000000
--- a/base/profiler/stack_sampling_profiler.h
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
-#define BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
-
-#include <stddef.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/atomicops.h"
-#include "base/base_export.h"
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/platform_thread.h"
-#include "base/time/time.h"
-
-namespace base {
-
-class NativeStackSampler;
-class NativeStackSamplerTestDelegate;
-
-// StackSamplingProfiler periodically stops a thread to sample its stack, for
-// the purpose of collecting information about which code paths are
-// executing. This information is used in aggregate by UMA to identify hot
-// and/or janky code paths.
-//
-// Sample StackSamplingProfiler usage:
-//
-// // Create and customize params as desired.
-// base::StackStackSamplingProfiler::SamplingParams params;
-// // Any thread's ID may be passed as the target.
-// base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
-// params);
-//
-// // Or, to process the profiles within Chrome rather than via UMA, use a
-// // custom completed callback:
-// base::StackStackSamplingProfiler::CompletedCallback
-// thread_safe_callback = ...;
-// base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
-// params, thread_safe_callback);
-//
-// profiler.Start();
-// // ... work being done on the target thread here ...
-// profiler.Stop(); // optional, stops collection before complete per params
-//
-// The default SamplingParams causes stacks to be recorded in a single burst at
-// a 10Hz interval for a total of 30 seconds. All of these parameters may be
-// altered as desired.
-//
-// When all call stack profiles are complete, or the profiler is stopped, the
-// completed callback is called from a thread created by the profiler with the
-// collected profiles.
-//
-// The results of the profiling are passed to the completed callback and consist
-// of a vector of CallStackProfiles. Each CallStackProfile corresponds to a
-// burst as specified in SamplingParams and contains a set of Samples and
-// Modules. One Sample corresponds to a single recorded stack, and the Modules
-// record those modules associated with the recorded stack frames.
-class BASE_EXPORT StackSamplingProfiler {
- public:
- // Module represents the module (DLL or exe) corresponding to a stack frame.
- struct BASE_EXPORT Module {
- Module();
- Module(uintptr_t base_address,
- const std::string& id,
- const FilePath& filename);
- ~Module();
-
- // Points to the base address of the module.
- uintptr_t base_address;
-
- // An opaque binary string that uniquely identifies a particular program
- // version with high probability. This is parsed from headers of the loaded
- // module.
- // For binaries generated by GNU tools:
- // Contents of the .note.gnu.build-id field.
- // On Windows:
- // GUID + AGE in the debug image headers of a module.
- std::string id;
-
- // The filename of the module.
- FilePath filename;
- };
-
- // Frame represents an individual sampled stack frame with module information.
- struct BASE_EXPORT Frame {
- // Identifies an unknown module.
- static const size_t kUnknownModuleIndex = static_cast<size_t>(-1);
-
- Frame(uintptr_t instruction_pointer, size_t module_index);
- ~Frame();
-
- // Default constructor to satisfy IPC macros. Do not use explicitly.
- Frame();
-
- // The sampled instruction pointer within the function.
- uintptr_t instruction_pointer;
-
- // Index of the module in CallStackProfile::modules. We don't represent
- // module state directly here to save space.
- size_t module_index;
- };
-
- // Sample represents a set of stack frames with some extra information.
- struct BASE_EXPORT Sample {
- Sample();
- Sample(const Sample& sample);
- ~Sample();
-
- // These constructors are used only during testing.
- Sample(const Frame& frame);
- Sample(const std::vector<Frame>& frames);
-
- // The entire stack frame when the sample is taken.
- std::vector<Frame> frames;
-
- // A bit-field indicating which process milestones have passed. This can be
- // used to tell where in the process lifetime the samples are taken. Just
- // as a "lifetime" can only move forward, these bits mark the milestones of
- // the processes life as they occur. Bits can be set but never reset. The
- // actual definition of the individual bits is left to the user of this
- // module.
- uint32_t process_milestones = 0;
- };
-
- // CallStackProfile represents a set of samples.
- struct BASE_EXPORT CallStackProfile {
- CallStackProfile();
- CallStackProfile(CallStackProfile&& other);
- ~CallStackProfile();
-
- CallStackProfile& operator=(CallStackProfile&& other);
-
- CallStackProfile CopyForTesting() const;
-
- std::vector<Module> modules;
- std::vector<Sample> samples;
-
- // Duration of this profile.
- TimeDelta profile_duration;
-
- // Time between samples.
- TimeDelta sampling_period;
-
- private:
- // Copying is possible but expensive so disallow it except for internal use
- // (i.e. CopyForTesting); use std::move instead.
- CallStackProfile(const CallStackProfile& other);
-
- DISALLOW_ASSIGN(CallStackProfile);
- };
-
- using CallStackProfiles = std::vector<CallStackProfile>;
-
- // Represents parameters that configure the sampling.
- struct BASE_EXPORT SamplingParams {
- // Time to delay before first samples are taken.
- TimeDelta initial_delay = TimeDelta::FromMilliseconds(0);
-
- // Number of sampling bursts to perform.
- int bursts = 1;
-
- // Interval between sampling bursts. This is the desired duration from the
- // start of one burst to the start of the next burst.
- TimeDelta burst_interval = TimeDelta::FromSeconds(10);
-
- // Number of samples to record per burst.
- int samples_per_burst = 300;
-
- // Interval between samples during a sampling burst. This is the desired
- // duration from the start of one sample to the start of the next sample.
- TimeDelta sampling_interval = TimeDelta::FromMilliseconds(100);
- };
-
- // Testing support. These methods are static beause they interact with the
- // sampling thread, a singleton used by all StackSamplingProfiler objects.
- // These methods can only be called by the same thread that started the
- // sampling.
- class BASE_EXPORT TestAPI {
- public:
- // Resets the internal state to that of a fresh start. This is necessary
- // so that tests don't inherit state from previous tests.
- static void Reset();
-
- // Resets internal annotations (like process phase) to initial values.
- static void ResetAnnotations();
-
- // Returns whether the sampling thread is currently running or not.
- static bool IsSamplingThreadRunning();
-
- // Disables inherent idle-shutdown behavior.
- static void DisableIdleShutdown();
-
- // Initiates an idle shutdown task, as though the idle timer had expired,
- // causing the thread to exit. There is no "idle" check so this must be
- // called only when all sampling tasks have completed. This blocks until
- // the task has been executed, though the actual stopping of the thread
- // still happens asynchronously. Watch IsSamplingThreadRunning() to know
- // when the thread has exited. If |simulate_intervening_start| is true then
- // this method will make it appear to the shutdown task that a new profiler
- // was started between when the idle-shutdown was initiated and when it
- // runs.
- static void PerformSamplingThreadIdleShutdown(
- bool simulate_intervening_start);
- };
-
- // The callback type used to collect completed profiles. The passed |profiles|
- // are move-only. Other threads, including the UI thread, may block on
- // callback completion so this should run as quickly as possible.
- //
- // IMPORTANT NOTE: The callback is invoked on a thread the profiler
- // constructs, rather than on the thread used to construct the profiler and
- // set the callback, and thus the callback must be callable on any thread. For
- // threads with message loops that create StackSamplingProfilers, posting a
- // task to the message loop with the moved (i.e. std::move) profiles is the
- // thread-safe callback implementation.
- using CompletedCallback = Callback<void(CallStackProfiles)>;
-
- // Creates a profiler for the CURRENT thread that sends completed profiles
- // to |callback|. An optional |test_delegate| can be supplied by tests.
- // The caller must ensure that this object gets destroyed before the current
- // thread exits.
- StackSamplingProfiler(
- const SamplingParams& params,
- const CompletedCallback& callback,
- NativeStackSamplerTestDelegate* test_delegate = nullptr);
-
- // Creates a profiler for ANOTHER thread that sends completed profiles to
- // |callback|. An optional |test_delegate| can be supplied by tests.
- //
- // IMPORTANT: The caller must ensure that the thread being sampled does not
- // exit before this object gets destructed or Bad Things(tm) may occur.
- StackSamplingProfiler(
- PlatformThreadId thread_id,
- const SamplingParams& params,
- const CompletedCallback& callback,
- NativeStackSamplerTestDelegate* test_delegate = nullptr);
-
- // Stops any profiling currently taking place before destroying the profiler.
- // This will block until the callback has been run if profiling has started
- // but not already finished.
- ~StackSamplingProfiler();
-
- // Initializes the profiler and starts sampling. Might block on a
- // WaitableEvent if this StackSamplingProfiler was previously started and
- // recently stopped, while the previous profiling phase winds down.
- void Start();
-
- // Stops the profiler and any ongoing sampling. This method will return
- // immediately with the callback being run asynchronously. At most one
- // more stack sample will be taken after this method returns. Calling this
- // function is optional; if not invoked profiling terminates when all the
- // profiling bursts specified in the SamplingParams are completed or the
- // profiler object is destroyed, whichever occurs first.
- void Stop();
-
- // Set the current system state that is recorded with each captured stack
- // frame. This is thread-safe so can be called from anywhere. The parameter
- // value should be from an enumeration of the appropriate type with values
- // ranging from 0 to 31, inclusive. This sets bits within Sample field of
- // |process_milestones|. The actual meanings of these bits are defined
- // (globally) by the caller(s).
- static void SetProcessMilestone(int milestone);
-
- private:
- friend class TestAPI;
-
- // SamplingThread is a separate thread used to suspend and sample stacks from
- // the target thread.
- class SamplingThread;
-
- // Adds annotations to a Sample.
- static void RecordAnnotations(Sample* sample);
-
- // This global variables holds the current system state and is recorded with
- // every captured sample, done on a separate thread which is why updates to
- // this must be atomic. A PostTask to move the the updates to that thread
- // would skew the timing and a lock could result in deadlock if the thread
- // making a change was also being profiled and got stopped.
- static subtle::Atomic32 process_milestones_;
-
- // The thread whose stack will be sampled.
- PlatformThreadId thread_id_;
-
- const SamplingParams params_;
-
- const CompletedCallback completed_callback_;
-
- // This starts "signaled", is reset when sampling begins, and is signaled
- // when that sampling is complete and the callback done.
- WaitableEvent profiling_inactive_;
-
- // Object that does the native sampling. This is created during construction
- // and later passed to the sampling thread when profiling is started.
- std::unique_ptr<NativeStackSampler> native_sampler_;
-
- // An ID uniquely identifying this profiler to the sampling thread. This
- // will be an internal "null" value when no collection has been started.
- int profiler_id_;
-
- // Stored until it can be passed to the NativeStackSampler created in Start().
- NativeStackSamplerTestDelegate* const test_delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(StackSamplingProfiler);
-};
-
-// These operators permit types to be compared and used in a map of Samples, as
-// done in tests and by the metrics provider code.
-BASE_EXPORT bool operator==(const StackSamplingProfiler::Module& a,
- const StackSamplingProfiler::Module& b);
-BASE_EXPORT bool operator==(const StackSamplingProfiler::Sample& a,
- const StackSamplingProfiler::Sample& b);
-BASE_EXPORT bool operator!=(const StackSamplingProfiler::Sample& a,
- const StackSamplingProfiler::Sample& b);
-BASE_EXPORT bool operator<(const StackSamplingProfiler::Sample& a,
- const StackSamplingProfiler::Sample& b);
-BASE_EXPORT bool operator==(const StackSamplingProfiler::Frame& a,
- const StackSamplingProfiler::Frame& b);
-BASE_EXPORT bool operator<(const StackSamplingProfiler::Frame& a,
- const StackSamplingProfiler::Frame& b);
-
-} // namespace base
-
-#endif // BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
diff --git a/base/profiler/test_support_library.cc b/base/profiler/test_support_library.cc
deleted file mode 100644
index 035f8f7..0000000
--- a/base/profiler/test_support_library.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Note: there is intentionally no header file associated with this library so
-// we don't risk implicitly demand loading it by accessing a symbol.
-
-#if defined(WIN32)
-#define BASE_PROFILER_TEST_SUPPORT_LIBRARY_EXPORT __declspec(dllexport)
-#else // defined(WIN32)
-#define BASE_PROFILER_TEST_SUPPORT_LIBRARY_EXPORT __attribute__((visibility("default")))
-#endif
-
-namespace base {
-
-// Must be defined in an extern "C" block so we can look up the unmangled name.
-extern "C" {
-
-BASE_PROFILER_TEST_SUPPORT_LIBRARY_EXPORT void InvokeCallbackFunction(
- void (*function)(void*),
- void* arg) {
- function(arg);
- // Prevent tail call.
- volatile int i = 0;
- i = 1;
-}
-
-} // extern "C"
-
-} // namespace base
diff --git a/base/profiler/win32_stack_frame_unwinder.cc b/base/profiler/win32_stack_frame_unwinder.cc
deleted file mode 100644
index 9e6ab39..0000000
--- a/base/profiler/win32_stack_frame_unwinder.cc
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/profiler/win32_stack_frame_unwinder.h"
-
-#include <windows.h>
-
-#include <utility>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-
-namespace base {
-
-// Win32UnwindFunctions -------------------------------------------------------
-
-const HMODULE ModuleHandleTraits::kNonNullModuleForTesting =
- reinterpret_cast<HMODULE>(static_cast<uintptr_t>(-1));
-
-// static
-bool ModuleHandleTraits::CloseHandle(HMODULE handle) {
- if (handle == kNonNullModuleForTesting)
- return true;
-
- return ::FreeLibrary(handle) != 0;
-}
-
-// static
-bool ModuleHandleTraits::IsHandleValid(HMODULE handle) {
- return handle != nullptr;
-}
-
-// static
-HMODULE ModuleHandleTraits::NullHandle() {
- return nullptr;
-}
-
-namespace {
-
-// Implements the UnwindFunctions interface for the corresponding Win32
-// functions.
-class Win32UnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions {
-public:
- Win32UnwindFunctions();
- ~Win32UnwindFunctions() override;
-
- PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter,
- PDWORD64 image_base) override;
-
- void VirtualUnwind(DWORD64 image_base,
- DWORD64 program_counter,
- PRUNTIME_FUNCTION runtime_function,
- CONTEXT* context) override;
-
- ScopedModuleHandle GetModuleForProgramCounter(
- DWORD64 program_counter) override;
-
-private:
- DISALLOW_COPY_AND_ASSIGN(Win32UnwindFunctions);
-};
-
-Win32UnwindFunctions::Win32UnwindFunctions() {}
-Win32UnwindFunctions::~Win32UnwindFunctions() {}
-
-PRUNTIME_FUNCTION Win32UnwindFunctions::LookupFunctionEntry(
- DWORD64 program_counter,
- PDWORD64 image_base) {
-#ifdef _WIN64
- return RtlLookupFunctionEntry(program_counter, image_base, nullptr);
-#else
- NOTREACHED();
- return nullptr;
-#endif
-}
-
-void Win32UnwindFunctions::VirtualUnwind(DWORD64 image_base,
- DWORD64 program_counter,
- PRUNTIME_FUNCTION runtime_function,
- CONTEXT* context) {
-#ifdef _WIN64
- void* handler_data;
- ULONG64 establisher_frame;
- KNONVOLATILE_CONTEXT_POINTERS nvcontext = {};
- RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, program_counter,
- runtime_function, context, &handler_data,
- &establisher_frame, &nvcontext);
-#else
- NOTREACHED();
-#endif
-}
-
-ScopedModuleHandle Win32UnwindFunctions::GetModuleForProgramCounter(
- DWORD64 program_counter) {
- HMODULE module_handle = nullptr;
- // GetModuleHandleEx() increments the module reference count, which is then
- // managed and ultimately decremented by ScopedModuleHandle.
- if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
- reinterpret_cast<LPCTSTR>(program_counter),
- &module_handle)) {
- const DWORD error = ::GetLastError();
- DCHECK_EQ(ERROR_MOD_NOT_FOUND, static_cast<int>(error));
- }
- return ScopedModuleHandle(module_handle);
-}
-
-} // namespace
-
-// Win32StackFrameUnwinder ----------------------------------------------------
-
-Win32StackFrameUnwinder::UnwindFunctions::~UnwindFunctions() {}
-Win32StackFrameUnwinder::UnwindFunctions::UnwindFunctions() {}
-
-Win32StackFrameUnwinder::Win32StackFrameUnwinder()
- : Win32StackFrameUnwinder(WrapUnique(new Win32UnwindFunctions)) {}
-
-Win32StackFrameUnwinder::~Win32StackFrameUnwinder() {}
-
-bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context,
- ScopedModuleHandle* module) {
-#ifdef _WIN64
- ScopedModuleHandle frame_module =
- unwind_functions_->GetModuleForProgramCounter(context->Rip);
- if (!frame_module.IsValid()) {
- // There's no loaded module containing the instruction pointer. This can be
- // due to executing code that is not in a module. In particular,
- // runtime-generated code associated with third-party injected DLLs
- // typically is not in a module. It can also be due to the the module having
- // been unloaded since we recorded the stack. In the latter case the
- // function unwind information was part of the unloaded module, so it's not
- // possible to unwind further.
- //
- // If a module was found, it's still theoretically possible for the detected
- // module module to be different than the one that was loaded when the stack
- // was copied (i.e. if the module was unloaded and a different module loaded
- // in overlapping memory). This likely would cause a crash, but has not been
- // observed in practice.
- return false;
- }
-
- ULONG64 image_base;
- // Try to look up unwind metadata for the current function.
- PRUNTIME_FUNCTION runtime_function =
- unwind_functions_->LookupFunctionEntry(context->Rip, &image_base);
-
- if (runtime_function) {
- unwind_functions_->VirtualUnwind(image_base, context->Rip, runtime_function,
- context);
- at_top_frame_ = false;
- } else {
- if (at_top_frame_) {
- at_top_frame_ = false;
-
- // This is a leaf function (i.e. a function that neither calls a function,
- // nor allocates any stack space itself) so the return address is at RSP.
- context->Rip = *reinterpret_cast<DWORD64*>(context->Rsp);
- context->Rsp += 8;
- } else {
- // In theory we shouldn't get here, as it means we've encountered a
- // function without unwind information below the top of the stack, which
- // is forbidden by the Microsoft x64 calling convention.
- //
- // The one known case in Chrome code that executes this path occurs
- // because of BoringSSL unwind information inconsistent with the actual
- // function code. See https://crbug.com/542919.
- //
- // Note that dodgy third-party generated code that otherwise would enter
- // this path should be caught by the module check above, since the code
- // typically is located outside of a module.
- return false;
- }
- }
-
- module->Set(frame_module.Take());
- return true;
-#else
- NOTREACHED();
- return false;
-#endif
-}
-
-Win32StackFrameUnwinder::Win32StackFrameUnwinder(
- std::unique_ptr<UnwindFunctions> unwind_functions)
- : at_top_frame_(true), unwind_functions_(std::move(unwind_functions)) {}
-
-} // namespace base
diff --git a/base/profiler/win32_stack_frame_unwinder.h b/base/profiler/win32_stack_frame_unwinder.h
deleted file mode 100644
index c92d50c..0000000
--- a/base/profiler/win32_stack_frame_unwinder.h
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_PROFILER_WIN32_STACK_FRAME_UNWINDER_H_
-#define BASE_PROFILER_WIN32_STACK_FRAME_UNWINDER_H_
-
-#include <windows.h>
-
-#include <memory>
-
-#include "base/base_export.h"
-#include "base/macros.h"
-#include "base/win/scoped_handle.h"
-
-namespace base {
-
-#if !defined(_WIN64)
-// Allows code to compile for x86. Actual support for x86 will require either
-// refactoring these interfaces or separate architecture-specific interfaces.
-struct RUNTIME_FUNCTION {
- DWORD BeginAddress;
- DWORD EndAddress;
-};
-using PRUNTIME_FUNCTION = RUNTIME_FUNCTION*;
-#endif // !defined(_WIN64)
-
-// Traits class to adapt GenericScopedHandle for HMODULES.
-class ModuleHandleTraits : public win::HandleTraits {
- public:
- using Handle = HMODULE;
-
- static bool BASE_EXPORT CloseHandle(HMODULE handle);
- static bool BASE_EXPORT IsHandleValid(HMODULE handle);
- static HMODULE BASE_EXPORT NullHandle();
-
- BASE_EXPORT static const HMODULE kNonNullModuleForTesting;
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleHandleTraits);
-};
-
-// HMODULE is not really a handle, and has reference count semantics, so the
-// standard VerifierTraits does not apply.
-using ScopedModuleHandle =
- win::GenericScopedHandle<ModuleHandleTraits, win::DummyVerifierTraits>;
-
-// Instances of this class are expected to be created and destroyed for each
-// stack unwinding. This class is not used while the target thread is suspended,
-// so may allocate from the default heap.
-class BASE_EXPORT Win32StackFrameUnwinder {
- public:
- // Interface for Win32 unwind-related functionality this class depends
- // on. Provides a seam for testing.
- class BASE_EXPORT UnwindFunctions {
- public:
- virtual ~UnwindFunctions();
-
- virtual PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter,
- PDWORD64 image_base) = 0;
- virtual void VirtualUnwind(DWORD64 image_base,
- DWORD64 program_counter,
- PRUNTIME_FUNCTION runtime_function,
- CONTEXT* context) = 0;
-
- // Returns the module containing |program_counter|. Can return null if the
- // module has been unloaded.
- virtual ScopedModuleHandle GetModuleForProgramCounter(
- DWORD64 program_counter) = 0;
-
- protected:
- UnwindFunctions();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(UnwindFunctions);
- };
-
- Win32StackFrameUnwinder();
- ~Win32StackFrameUnwinder();
-
- // Attempts to unwind the frame represented by the stack and instruction
- // pointers in |context|. If successful, updates |context| and provides the
- // module associated with the frame in |module|.
- bool TryUnwind(CONTEXT* context, ScopedModuleHandle* module);
-
- private:
- // This function is for internal and test purposes only.
- Win32StackFrameUnwinder(std::unique_ptr<UnwindFunctions> unwind_functions);
- friend class Win32StackFrameUnwinderTest;
-
- // State associated with each stack unwinding.
- bool at_top_frame_;
- bool unwind_info_present_for_all_frames_;
-
- std::unique_ptr<UnwindFunctions> unwind_functions_;
-
- DISALLOW_COPY_AND_ASSIGN(Win32StackFrameUnwinder);
-};
-
-} // namespace base
-
-#endif // BASE_PROFILER_WIN32_STACK_FRAME_UNWINDER_H_
diff --git a/base/synchronization/lock_impl_win.cc b/base/synchronization/lock_impl_win.cc
index e0c4e9d..fe9c664 100644
--- a/base/synchronization/lock_impl_win.cc
+++ b/base/synchronization/lock_impl_win.cc
@@ -4,8 +4,6 @@
#include "base/synchronization/lock_impl.h"
-#include "base/debug/activity_tracker.h"
-
#include <windows.h>
namespace base {
diff --git a/base/synchronization/waitable_event_win.cc b/base/synchronization/waitable_event_win.cc
index d04a5a6..60126f2 100644
--- a/base/synchronization/waitable_event_win.cc
+++ b/base/synchronization/waitable_event_win.cc
@@ -10,7 +10,6 @@
#include <algorithm>
#include <utility>
-#include "base/debug/activity_tracker.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/threading/scoped_blocking_call.h"
diff --git a/base/task_scheduler/scheduler_worker.cc b/base/task_scheduler/scheduler_worker.cc
index 33b400a..32042e4 100644
--- a/base/task_scheduler/scheduler_worker.cc
+++ b/base/task_scheduler/scheduler_worker.cc
@@ -9,7 +9,6 @@
#include <utility>
#include "base/compiler_specific.h"
-#include "base/debug/alias.h"
#include "base/logging.h"
#include "base/task_scheduler/scheduler_worker_observer.h"
#include "base/task_scheduler/task_tracker.h"
@@ -212,62 +211,52 @@
NOINLINE void SchedulerWorker::RunPooledWorker() {
const int line_number = __LINE__;
RunWorker();
- base::debug::Alias(&line_number);
}
NOINLINE void SchedulerWorker::RunBackgroundPooledWorker() {
const int line_number = __LINE__;
RunWorker();
- base::debug::Alias(&line_number);
}
NOINLINE void SchedulerWorker::RunSharedWorker() {
const int line_number = __LINE__;
RunWorker();
- base::debug::Alias(&line_number);
}
NOINLINE void SchedulerWorker::RunBackgroundSharedWorker() {
const int line_number = __LINE__;
RunWorker();
- base::debug::Alias(&line_number);
}
NOINLINE void SchedulerWorker::RunDedicatedWorker() {
const int line_number = __LINE__;
RunWorker();
- base::debug::Alias(&line_number);
}
NOINLINE void SchedulerWorker::RunBackgroundDedicatedWorker() {
const int line_number = __LINE__;
RunWorker();
- base::debug::Alias(&line_number);
}
#if defined(OS_WIN)
NOINLINE void SchedulerWorker::RunSharedCOMWorker() {
const int line_number = __LINE__;
RunWorker();
- base::debug::Alias(&line_number);
}
NOINLINE void SchedulerWorker::RunBackgroundSharedCOMWorker() {
const int line_number = __LINE__;
RunWorker();
- base::debug::Alias(&line_number);
}
NOINLINE void SchedulerWorker::RunDedicatedCOMWorker() {
const int line_number = __LINE__;
RunWorker();
- base::debug::Alias(&line_number);
}
NOINLINE void SchedulerWorker::RunBackgroundDedicatedCOMWorker() {
const int line_number = __LINE__;
RunWorker();
- base::debug::Alias(&line_number);
}
#endif // defined(OS_WIN)
diff --git a/base/task_scheduler/service_thread.cc b/base/task_scheduler/service_thread.cc
index ce8bf4d..9ee0986 100644
--- a/base/task_scheduler/service_thread.cc
+++ b/base/task_scheduler/service_thread.cc
@@ -4,7 +4,6 @@
#include "base/task_scheduler/service_thread.h"
-#include "base/debug/alias.h"
#include "base/task_scheduler/post_task.h"
#include "base/task_scheduler/task_tracker.h"
#include "base/task_scheduler/task_traits.h"
@@ -20,7 +19,6 @@
NOINLINE void ServiceThread::Run(RunLoop* run_loop) {
const int line_number = __LINE__;
Thread::Run(run_loop);
- base::debug::Alias(&line_number);
}
} // namespace internal
diff --git a/base/task_scheduler/task_tracker.cc b/base/task_scheduler/task_tracker.cc
index 33424bb..704aadd 100644
--- a/base/task_scheduler/task_tracker.cc
+++ b/base/task_scheduler/task_tracker.cc
@@ -245,8 +245,6 @@
if (task.delayed_run_time.is_null())
subtle::NoBarrier_AtomicIncrement(&num_incomplete_undelayed_tasks_, 1);
- task_annotator_.DidQueueTask(nullptr, task);
-
return true;
}
@@ -374,7 +372,7 @@
}
if (can_run_task) {
- task_annotator_.RunTask(nullptr, &task);
+ std::move(task.task).Run();
}
// Make sure the arguments bound to the callback are deleted within the
diff --git a/base/task_scheduler/task_tracker.h b/base/task_scheduler/task_tracker.h
index ae484ce..3240e3a 100644
--- a/base/task_scheduler/task_tracker.h
+++ b/base/task_scheduler/task_tracker.h
@@ -12,7 +12,6 @@
#include "base/atomicops.h"
#include "base/base_export.h"
#include "base/callback_forward.h"
-#include "base/debug/task_annotator.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
@@ -258,8 +257,6 @@
// manner.
void CallFlushCallbackForTesting();
- debug::TaskAnnotator task_annotator_;
-
// Number of tasks blocking shutdown and boolean indicating whether shutdown
// has started.
const std::unique_ptr<State> state_;
diff --git a/base/third_party/symbolize/DEPS b/base/third_party/symbolize/DEPS
deleted file mode 100644
index 73eab50..0000000
--- a/base/third_party/symbolize/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+glog",
-]
diff --git a/base/third_party/symbolize/LICENSE b/base/third_party/symbolize/LICENSE
deleted file mode 100644
index 433a3d1..0000000
--- a/base/third_party/symbolize/LICENSE
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/base/third_party/symbolize/README.chromium b/base/third_party/symbolize/README.chromium
deleted file mode 100644
index ff78e0e..0000000
--- a/base/third_party/symbolize/README.chromium
+++ /dev/null
@@ -1,24 +0,0 @@
-Name: google-glog's symbolization library
-URL: https://github.com/google/glog
-License: BSD
-
-The following files are copied AS-IS from:
-http://code.google.com/p/google-glog/source/browse/#svn/trunk/src (r141)
-https://github.com/google/glog/tree/a5ffa884137f7687d0393ccba22557d583654a25
-
-- demangle.cc
-- demangle.h
-- symbolize.cc
-- symbolize.h
-
-Cherry picked upstream changes:
-https://github.com/google/glog/pull/115
-https://github.com/google/glog/pull/261
-to fix symbolization issues when using lld.
-
-The following files are minimal stubs created for use in Chromium:
-
-- config.h
-- glog/logging.h
-- glog/raw_logging.h
-- utilities.h
diff --git a/base/third_party/symbolize/config.h b/base/third_party/symbolize/config.h
deleted file mode 100644
index 945f5a6..0000000
--- a/base/third_party/symbolize/config.h
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#define GOOGLE_NAMESPACE google
-#define _END_GOOGLE_NAMESPACE_ }
-#define _START_GOOGLE_NAMESPACE_ namespace google {
diff --git a/base/third_party/symbolize/demangle.cc b/base/third_party/symbolize/demangle.cc
deleted file mode 100644
index e858181..0000000
--- a/base/third_party/symbolize/demangle.cc
+++ /dev/null
@@ -1,1304 +0,0 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Satoru Takabayashi
-//
-// For reference check out:
-// http://www.codesourcery.com/public/cxx-abi/abi.html#mangling
-//
-// Note that we only have partial C++0x support yet.
-
-#include <stdio.h> // for NULL
-#include "demangle.h"
-
-_START_GOOGLE_NAMESPACE_
-
-typedef struct {
- const char *abbrev;
- const char *real_name;
-} AbbrevPair;
-
-// List of operators from Itanium C++ ABI.
-static const AbbrevPair kOperatorList[] = {
- { "nw", "new" },
- { "na", "new[]" },
- { "dl", "delete" },
- { "da", "delete[]" },
- { "ps", "+" },
- { "ng", "-" },
- { "ad", "&" },
- { "de", "*" },
- { "co", "~" },
- { "pl", "+" },
- { "mi", "-" },
- { "ml", "*" },
- { "dv", "/" },
- { "rm", "%" },
- { "an", "&" },
- { "or", "|" },
- { "eo", "^" },
- { "aS", "=" },
- { "pL", "+=" },
- { "mI", "-=" },
- { "mL", "*=" },
- { "dV", "/=" },
- { "rM", "%=" },
- { "aN", "&=" },
- { "oR", "|=" },
- { "eO", "^=" },
- { "ls", "<<" },
- { "rs", ">>" },
- { "lS", "<<=" },
- { "rS", ">>=" },
- { "eq", "==" },
- { "ne", "!=" },
- { "lt", "<" },
- { "gt", ">" },
- { "le", "<=" },
- { "ge", ">=" },
- { "nt", "!" },
- { "aa", "&&" },
- { "oo", "||" },
- { "pp", "++" },
- { "mm", "--" },
- { "cm", "," },
- { "pm", "->*" },
- { "pt", "->" },
- { "cl", "()" },
- { "ix", "[]" },
- { "qu", "?" },
- { "st", "sizeof" },
- { "sz", "sizeof" },
- { NULL, NULL },
-};
-
-// List of builtin types from Itanium C++ ABI.
-static const AbbrevPair kBuiltinTypeList[] = {
- { "v", "void" },
- { "w", "wchar_t" },
- { "b", "bool" },
- { "c", "char" },
- { "a", "signed char" },
- { "h", "unsigned char" },
- { "s", "short" },
- { "t", "unsigned short" },
- { "i", "int" },
- { "j", "unsigned int" },
- { "l", "long" },
- { "m", "unsigned long" },
- { "x", "long long" },
- { "y", "unsigned long long" },
- { "n", "__int128" },
- { "o", "unsigned __int128" },
- { "f", "float" },
- { "d", "double" },
- { "e", "long double" },
- { "g", "__float128" },
- { "z", "ellipsis" },
- { NULL, NULL }
-};
-
-// List of substitutions Itanium C++ ABI.
-static const AbbrevPair kSubstitutionList[] = {
- { "St", "" },
- { "Sa", "allocator" },
- { "Sb", "basic_string" },
- // std::basic_string<char, std::char_traits<char>,std::allocator<char> >
- { "Ss", "string"},
- // std::basic_istream<char, std::char_traits<char> >
- { "Si", "istream" },
- // std::basic_ostream<char, std::char_traits<char> >
- { "So", "ostream" },
- // std::basic_iostream<char, std::char_traits<char> >
- { "Sd", "iostream" },
- { NULL, NULL }
-};
-
-// State needed for demangling.
-typedef struct {
- const char *mangled_cur; // Cursor of mangled name.
- char *out_cur; // Cursor of output string.
- const char *out_begin; // Beginning of output string.
- const char *out_end; // End of output string.
- const char *prev_name; // For constructors/destructors.
- int prev_name_length; // For constructors/destructors.
- short nest_level; // For nested names.
- bool append; // Append flag.
- bool overflowed; // True if output gets overflowed.
-} State;
-
-// We don't use strlen() in libc since it's not guaranteed to be async
-// signal safe.
-static size_t StrLen(const char *str) {
- size_t len = 0;
- while (*str != '\0') {
- ++str;
- ++len;
- }
- return len;
-}
-
-// Returns true if "str" has at least "n" characters remaining.
-static bool AtLeastNumCharsRemaining(const char *str, int n) {
- for (int i = 0; i < n; ++i) {
- if (str[i] == '\0') {
- return false;
- }
- }
- return true;
-}
-
-// Returns true if "str" has "prefix" as a prefix.
-static bool StrPrefix(const char *str, const char *prefix) {
- size_t i = 0;
- while (str[i] != '\0' && prefix[i] != '\0' &&
- str[i] == prefix[i]) {
- ++i;
- }
- return prefix[i] == '\0'; // Consumed everything in "prefix".
-}
-
-static void InitState(State *state, const char *mangled,
- char *out, int out_size) {
- state->mangled_cur = mangled;
- state->out_cur = out;
- state->out_begin = out;
- state->out_end = out + out_size;
- state->prev_name = NULL;
- state->prev_name_length = -1;
- state->nest_level = -1;
- state->append = true;
- state->overflowed = false;
-}
-
-// Returns true and advances "mangled_cur" if we find "one_char_token"
-// at "mangled_cur" position. It is assumed that "one_char_token" does
-// not contain '\0'.
-static bool ParseOneCharToken(State *state, const char one_char_token) {
- if (state->mangled_cur[0] == one_char_token) {
- ++state->mangled_cur;
- return true;
- }
- return false;
-}
-
-// Returns true and advances "mangled_cur" if we find "two_char_token"
-// at "mangled_cur" position. It is assumed that "two_char_token" does
-// not contain '\0'.
-static bool ParseTwoCharToken(State *state, const char *two_char_token) {
- if (state->mangled_cur[0] == two_char_token[0] &&
- state->mangled_cur[1] == two_char_token[1]) {
- state->mangled_cur += 2;
- return true;
- }
- return false;
-}
-
-// Returns true and advances "mangled_cur" if we find any character in
-// "char_class" at "mangled_cur" position.
-static bool ParseCharClass(State *state, const char *char_class) {
- const char *p = char_class;
- for (; *p != '\0'; ++p) {
- if (state->mangled_cur[0] == *p) {
- ++state->mangled_cur;
- return true;
- }
- }
- return false;
-}
-
-// This function is used for handling an optional non-terminal.
-static bool Optional(bool) {
- return true;
-}
-
-// This function is used for handling <non-terminal>+ syntax.
-typedef bool (*ParseFunc)(State *);
-static bool OneOrMore(ParseFunc parse_func, State *state) {
- if (parse_func(state)) {
- while (parse_func(state)) {
- }
- return true;
- }
- return false;
-}
-
-// This function is used for handling <non-terminal>* syntax. The function
-// always returns true and must be followed by a termination token or a
-// terminating sequence not handled by parse_func (e.g.
-// ParseOneCharToken(state, 'E')).
-static bool ZeroOrMore(ParseFunc parse_func, State *state) {
- while (parse_func(state)) {
- }
- return true;
-}
-
-// Append "str" at "out_cur". If there is an overflow, "overflowed"
-// is set to true for later use. The output string is ensured to
-// always terminate with '\0' as long as there is no overflow.
-static void Append(State *state, const char * const str, const int length) {
- int i;
- for (i = 0; i < length; ++i) {
- if (state->out_cur + 1 < state->out_end) { // +1 for '\0'
- *state->out_cur = str[i];
- ++state->out_cur;
- } else {
- state->overflowed = true;
- break;
- }
- }
- if (!state->overflowed) {
- *state->out_cur = '\0'; // Terminate it with '\0'
- }
-}
-
-// We don't use equivalents in libc to avoid locale issues.
-static bool IsLower(char c) {
- return c >= 'a' && c <= 'z';
-}
-
-static bool IsAlpha(char c) {
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
-}
-
-static bool IsDigit(char c) {
- return c >= '0' && c <= '9';
-}
-
-// Returns true if "str" is a function clone suffix. These suffixes are used
-// by GCC 4.5.x and later versions to indicate functions which have been
-// cloned during optimization. We treat any sequence (.<alpha>+.<digit>+)+ as
-// a function clone suffix.
-static bool IsFunctionCloneSuffix(const char *str) {
- size_t i = 0;
- while (str[i] != '\0') {
- // Consume a single .<alpha>+.<digit>+ sequence.
- if (str[i] != '.' || !IsAlpha(str[i + 1])) {
- return false;
- }
- i += 2;
- while (IsAlpha(str[i])) {
- ++i;
- }
- if (str[i] != '.' || !IsDigit(str[i + 1])) {
- return false;
- }
- i += 2;
- while (IsDigit(str[i])) {
- ++i;
- }
- }
- return true; // Consumed everything in "str".
-}
-
-// Append "str" with some tweaks, iff "append" state is true.
-// Returns true so that it can be placed in "if" conditions.
-static void MaybeAppendWithLength(State *state, const char * const str,
- const int length) {
- if (state->append && length > 0) {
- // Append a space if the output buffer ends with '<' and "str"
- // starts with '<' to avoid <<<.
- if (str[0] == '<' && state->out_begin < state->out_cur &&
- state->out_cur[-1] == '<') {
- Append(state, " ", 1);
- }
- // Remember the last identifier name for ctors/dtors.
- if (IsAlpha(str[0]) || str[0] == '_') {
- state->prev_name = state->out_cur;
- state->prev_name_length = length;
- }
- Append(state, str, length);
- }
-}
-
-// A convenient wrapper arount MaybeAppendWithLength().
-static bool MaybeAppend(State *state, const char * const str) {
- if (state->append) {
- int length = StrLen(str);
- MaybeAppendWithLength(state, str, length);
- }
- return true;
-}
-
-// This function is used for handling nested names.
-static bool EnterNestedName(State *state) {
- state->nest_level = 0;
- return true;
-}
-
-// This function is used for handling nested names.
-static bool LeaveNestedName(State *state, short prev_value) {
- state->nest_level = prev_value;
- return true;
-}
-
-// Disable the append mode not to print function parameters, etc.
-static bool DisableAppend(State *state) {
- state->append = false;
- return true;
-}
-
-// Restore the append mode to the previous state.
-static bool RestoreAppend(State *state, bool prev_value) {
- state->append = prev_value;
- return true;
-}
-
-// Increase the nest level for nested names.
-static void MaybeIncreaseNestLevel(State *state) {
- if (state->nest_level > -1) {
- ++state->nest_level;
- }
-}
-
-// Appends :: for nested names if necessary.
-static void MaybeAppendSeparator(State *state) {
- if (state->nest_level >= 1) {
- MaybeAppend(state, "::");
- }
-}
-
-// Cancel the last separator if necessary.
-static void MaybeCancelLastSeparator(State *state) {
- if (state->nest_level >= 1 && state->append &&
- state->out_begin <= state->out_cur - 2) {
- state->out_cur -= 2;
- *state->out_cur = '\0';
- }
-}
-
-// Returns true if the identifier of the given length pointed to by
-// "mangled_cur" is anonymous namespace.
-static bool IdentifierIsAnonymousNamespace(State *state, int length) {
- static const char anon_prefix[] = "_GLOBAL__N_";
- return (length > (int)sizeof(anon_prefix) - 1 && // Should be longer.
- StrPrefix(state->mangled_cur, anon_prefix));
-}
-
-// Forward declarations of our parsing functions.
-static bool ParseMangledName(State *state);
-static bool ParseEncoding(State *state);
-static bool ParseName(State *state);
-static bool ParseUnscopedName(State *state);
-static bool ParseUnscopedTemplateName(State *state);
-static bool ParseNestedName(State *state);
-static bool ParsePrefix(State *state);
-static bool ParseUnqualifiedName(State *state);
-static bool ParseSourceName(State *state);
-static bool ParseLocalSourceName(State *state);
-static bool ParseNumber(State *state, int *number_out);
-static bool ParseFloatNumber(State *state);
-static bool ParseSeqId(State *state);
-static bool ParseIdentifier(State *state, int length);
-static bool ParseOperatorName(State *state);
-static bool ParseSpecialName(State *state);
-static bool ParseCallOffset(State *state);
-static bool ParseNVOffset(State *state);
-static bool ParseVOffset(State *state);
-static bool ParseCtorDtorName(State *state);
-static bool ParseType(State *state);
-static bool ParseCVQualifiers(State *state);
-static bool ParseBuiltinType(State *state);
-static bool ParseFunctionType(State *state);
-static bool ParseBareFunctionType(State *state);
-static bool ParseClassEnumType(State *state);
-static bool ParseArrayType(State *state);
-static bool ParsePointerToMemberType(State *state);
-static bool ParseTemplateParam(State *state);
-static bool ParseTemplateTemplateParam(State *state);
-static bool ParseTemplateArgs(State *state);
-static bool ParseTemplateArg(State *state);
-static bool ParseExpression(State *state);
-static bool ParseExprPrimary(State *state);
-static bool ParseLocalName(State *state);
-static bool ParseDiscriminator(State *state);
-static bool ParseSubstitution(State *state);
-
-// Implementation note: the following code is a straightforward
-// translation of the Itanium C++ ABI defined in BNF with a couple of
-// exceptions.
-//
-// - Support GNU extensions not defined in the Itanium C++ ABI
-// - <prefix> and <template-prefix> are combined to avoid infinite loop
-// - Reorder patterns to shorten the code
-// - Reorder patterns to give greedier functions precedence
-// We'll mark "Less greedy than" for these cases in the code
-//
-// Each parsing function changes the state and returns true on
-// success. Otherwise, don't change the state and returns false. To
-// ensure that the state isn't changed in the latter case, we save the
-// original state before we call more than one parsing functions
-// consecutively with &&, and restore the state if unsuccessful. See
-// ParseEncoding() as an example of this convention. We follow the
-// convention throughout the code.
-//
-// Originally we tried to do demangling without following the full ABI
-// syntax but it turned out we needed to follow the full syntax to
-// parse complicated cases like nested template arguments. Note that
-// implementing a full-fledged demangler isn't trivial (libiberty's
-// cp-demangle.c has +4300 lines).
-//
-// Note that (foo) in <(foo) ...> is a modifier to be ignored.
-//
-// Reference:
-// - Itanium C++ ABI
-// <http://www.codesourcery.com/cxx-abi/abi.html#mangling>
-
-// <mangled-name> ::= _Z <encoding>
-static bool ParseMangledName(State *state) {
- return ParseTwoCharToken(state, "_Z") && ParseEncoding(state);
-}
-
-// <encoding> ::= <(function) name> <bare-function-type>
-// ::= <(data) name>
-// ::= <special-name>
-static bool ParseEncoding(State *state) {
- State copy = *state;
- if (ParseName(state) && ParseBareFunctionType(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseName(state) || ParseSpecialName(state)) {
- return true;
- }
- return false;
-}
-
-// <name> ::= <nested-name>
-// ::= <unscoped-template-name> <template-args>
-// ::= <unscoped-name>
-// ::= <local-name>
-static bool ParseName(State *state) {
- if (ParseNestedName(state) || ParseLocalName(state)) {
- return true;
- }
-
- State copy = *state;
- if (ParseUnscopedTemplateName(state) &&
- ParseTemplateArgs(state)) {
- return true;
- }
- *state = copy;
-
- // Less greedy than <unscoped-template-name> <template-args>.
- if (ParseUnscopedName(state)) {
- return true;
- }
- return false;
-}
-
-// <unscoped-name> ::= <unqualified-name>
-// ::= St <unqualified-name>
-static bool ParseUnscopedName(State *state) {
- if (ParseUnqualifiedName(state)) {
- return true;
- }
-
- State copy = *state;
- if (ParseTwoCharToken(state, "St") &&
- MaybeAppend(state, "std::") &&
- ParseUnqualifiedName(state)) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <unscoped-template-name> ::= <unscoped-name>
-// ::= <substitution>
-static bool ParseUnscopedTemplateName(State *state) {
- return ParseUnscopedName(state) || ParseSubstitution(state);
-}
-
-// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
-// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
-static bool ParseNestedName(State *state) {
- State copy = *state;
- if (ParseOneCharToken(state, 'N') &&
- EnterNestedName(state) &&
- Optional(ParseCVQualifiers(state)) &&
- ParsePrefix(state) &&
- LeaveNestedName(state, copy.nest_level) &&
- ParseOneCharToken(state, 'E')) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// This part is tricky. If we literally translate them to code, we'll
-// end up infinite loop. Hence we merge them to avoid the case.
-//
-// <prefix> ::= <prefix> <unqualified-name>
-// ::= <template-prefix> <template-args>
-// ::= <template-param>
-// ::= <substitution>
-// ::= # empty
-// <template-prefix> ::= <prefix> <(template) unqualified-name>
-// ::= <template-param>
-// ::= <substitution>
-static bool ParsePrefix(State *state) {
- bool has_something = false;
- while (true) {
- MaybeAppendSeparator(state);
- if (ParseTemplateParam(state) ||
- ParseSubstitution(state) ||
- ParseUnscopedName(state)) {
- has_something = true;
- MaybeIncreaseNestLevel(state);
- continue;
- }
- MaybeCancelLastSeparator(state);
- if (has_something && ParseTemplateArgs(state)) {
- return ParsePrefix(state);
- } else {
- break;
- }
- }
- return true;
-}
-
-// <unqualified-name> ::= <operator-name>
-// ::= <ctor-dtor-name>
-// ::= <source-name>
-// ::= <local-source-name>
-static bool ParseUnqualifiedName(State *state) {
- return (ParseOperatorName(state) ||
- ParseCtorDtorName(state) ||
- ParseSourceName(state) ||
- ParseLocalSourceName(state));
-}
-
-// <source-name> ::= <positive length number> <identifier>
-static bool ParseSourceName(State *state) {
- State copy = *state;
- int length = -1;
- if (ParseNumber(state, &length) && ParseIdentifier(state, length)) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <local-source-name> ::= L <source-name> [<discriminator>]
-//
-// References:
-// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
-// http://gcc.gnu.org/viewcvs?view=rev&revision=124467
-static bool ParseLocalSourceName(State *state) {
- State copy = *state;
- if (ParseOneCharToken(state, 'L') && ParseSourceName(state) &&
- Optional(ParseDiscriminator(state))) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <number> ::= [n] <non-negative decimal integer>
-// If "number_out" is non-null, then *number_out is set to the value of the
-// parsed number on success.
-static bool ParseNumber(State *state, int *number_out) {
- int sign = 1;
- if (ParseOneCharToken(state, 'n')) {
- sign = -1;
- }
- const char *p = state->mangled_cur;
- int number = 0;
- for (;*p != '\0'; ++p) {
- if (IsDigit(*p)) {
- number = number * 10 + (*p - '0');
- } else {
- break;
- }
- }
- if (p != state->mangled_cur) { // Conversion succeeded.
- state->mangled_cur = p;
- if (number_out != NULL) {
- *number_out = number * sign;
- }
- return true;
- }
- return false;
-}
-
-// Floating-point literals are encoded using a fixed-length lowercase
-// hexadecimal string.
-static bool ParseFloatNumber(State *state) {
- const char *p = state->mangled_cur;
- for (;*p != '\0'; ++p) {
- if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) {
- break;
- }
- }
- if (p != state->mangled_cur) { // Conversion succeeded.
- state->mangled_cur = p;
- return true;
- }
- return false;
-}
-
-// The <seq-id> is a sequence number in base 36,
-// using digits and upper case letters
-static bool ParseSeqId(State *state) {
- const char *p = state->mangled_cur;
- for (;*p != '\0'; ++p) {
- if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) {
- break;
- }
- }
- if (p != state->mangled_cur) { // Conversion succeeded.
- state->mangled_cur = p;
- return true;
- }
- return false;
-}
-
-// <identifier> ::= <unqualified source code identifier> (of given length)
-static bool ParseIdentifier(State *state, int length) {
- if (length == -1 ||
- !AtLeastNumCharsRemaining(state->mangled_cur, length)) {
- return false;
- }
- if (IdentifierIsAnonymousNamespace(state, length)) {
- MaybeAppend(state, "(anonymous namespace)");
- } else {
- MaybeAppendWithLength(state, state->mangled_cur, length);
- }
- state->mangled_cur += length;
- return true;
-}
-
-// <operator-name> ::= nw, and other two letters cases
-// ::= cv <type> # (cast)
-// ::= v <digit> <source-name> # vendor extended operator
-static bool ParseOperatorName(State *state) {
- if (!AtLeastNumCharsRemaining(state->mangled_cur, 2)) {
- return false;
- }
- // First check with "cv" (cast) case.
- State copy = *state;
- if (ParseTwoCharToken(state, "cv") &&
- MaybeAppend(state, "operator ") &&
- EnterNestedName(state) &&
- ParseType(state) &&
- LeaveNestedName(state, copy.nest_level)) {
- return true;
- }
- *state = copy;
-
- // Then vendor extended operators.
- if (ParseOneCharToken(state, 'v') && ParseCharClass(state, "0123456789") &&
- ParseSourceName(state)) {
- return true;
- }
- *state = copy;
-
- // Other operator names should start with a lower alphabet followed
- // by a lower/upper alphabet.
- if (!(IsLower(state->mangled_cur[0]) &&
- IsAlpha(state->mangled_cur[1]))) {
- return false;
- }
- // We may want to perform a binary search if we really need speed.
- const AbbrevPair *p;
- for (p = kOperatorList; p->abbrev != NULL; ++p) {
- if (state->mangled_cur[0] == p->abbrev[0] &&
- state->mangled_cur[1] == p->abbrev[1]) {
- MaybeAppend(state, "operator");
- if (IsLower(*p->real_name)) { // new, delete, etc.
- MaybeAppend(state, " ");
- }
- MaybeAppend(state, p->real_name);
- state->mangled_cur += 2;
- return true;
- }
- }
- return false;
-}
-
-// <special-name> ::= TV <type>
-// ::= TT <type>
-// ::= TI <type>
-// ::= TS <type>
-// ::= Tc <call-offset> <call-offset> <(base) encoding>
-// ::= GV <(object) name>
-// ::= T <call-offset> <(base) encoding>
-// G++ extensions:
-// ::= TC <type> <(offset) number> _ <(base) type>
-// ::= TF <type>
-// ::= TJ <type>
-// ::= GR <name>
-// ::= GA <encoding>
-// ::= Th <call-offset> <(base) encoding>
-// ::= Tv <call-offset> <(base) encoding>
-//
-// Note: we don't care much about them since they don't appear in
-// stack traces. The are special data.
-static bool ParseSpecialName(State *state) {
- State copy = *state;
- if (ParseOneCharToken(state, 'T') &&
- ParseCharClass(state, "VTIS") &&
- ParseType(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseTwoCharToken(state, "Tc") && ParseCallOffset(state) &&
- ParseCallOffset(state) && ParseEncoding(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseTwoCharToken(state, "GV") &&
- ParseName(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseOneCharToken(state, 'T') && ParseCallOffset(state) &&
- ParseEncoding(state)) {
- return true;
- }
- *state = copy;
-
- // G++ extensions
- if (ParseTwoCharToken(state, "TC") && ParseType(state) &&
- ParseNumber(state, NULL) && ParseOneCharToken(state, '_') &&
- DisableAppend(state) &&
- ParseType(state)) {
- RestoreAppend(state, copy.append);
- return true;
- }
- *state = copy;
-
- if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "FJ") &&
- ParseType(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseTwoCharToken(state, "GR") && ParseName(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseTwoCharToken(state, "GA") && ParseEncoding(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "hv") &&
- ParseCallOffset(state) && ParseEncoding(state)) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <call-offset> ::= h <nv-offset> _
-// ::= v <v-offset> _
-static bool ParseCallOffset(State *state) {
- State copy = *state;
- if (ParseOneCharToken(state, 'h') &&
- ParseNVOffset(state) && ParseOneCharToken(state, '_')) {
- return true;
- }
- *state = copy;
-
- if (ParseOneCharToken(state, 'v') &&
- ParseVOffset(state) && ParseOneCharToken(state, '_')) {
- return true;
- }
- *state = copy;
-
- return false;
-}
-
-// <nv-offset> ::= <(offset) number>
-static bool ParseNVOffset(State *state) {
- return ParseNumber(state, NULL);
-}
-
-// <v-offset> ::= <(offset) number> _ <(virtual offset) number>
-static bool ParseVOffset(State *state) {
- State copy = *state;
- if (ParseNumber(state, NULL) && ParseOneCharToken(state, '_') &&
- ParseNumber(state, NULL)) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <ctor-dtor-name> ::= C1 | C2 | C3
-// ::= D0 | D1 | D2
-static bool ParseCtorDtorName(State *state) {
- State copy = *state;
- if (ParseOneCharToken(state, 'C') &&
- ParseCharClass(state, "123")) {
- const char * const prev_name = state->prev_name;
- const int prev_name_length = state->prev_name_length;
- MaybeAppendWithLength(state, prev_name, prev_name_length);
- return true;
- }
- *state = copy;
-
- if (ParseOneCharToken(state, 'D') &&
- ParseCharClass(state, "012")) {
- const char * const prev_name = state->prev_name;
- const int prev_name_length = state->prev_name_length;
- MaybeAppend(state, "~");
- MaybeAppendWithLength(state, prev_name, prev_name_length);
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <type> ::= <CV-qualifiers> <type>
-// ::= P <type> # pointer-to
-// ::= R <type> # reference-to
-// ::= O <type> # rvalue reference-to (C++0x)
-// ::= C <type> # complex pair (C 2000)
-// ::= G <type> # imaginary (C 2000)
-// ::= U <source-name> <type> # vendor extended type qualifier
-// ::= <builtin-type>
-// ::= <function-type>
-// ::= <class-enum-type>
-// ::= <array-type>
-// ::= <pointer-to-member-type>
-// ::= <template-template-param> <template-args>
-// ::= <template-param>
-// ::= <substitution>
-// ::= Dp <type> # pack expansion of (C++0x)
-// ::= Dt <expression> E # decltype of an id-expression or class
-// # member access (C++0x)
-// ::= DT <expression> E # decltype of an expression (C++0x)
-//
-static bool ParseType(State *state) {
- // We should check CV-qualifers, and PRGC things first.
- State copy = *state;
- if (ParseCVQualifiers(state) && ParseType(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseCharClass(state, "OPRCG") && ParseType(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseTwoCharToken(state, "Dp") && ParseType(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "tT") &&
- ParseExpression(state) && ParseOneCharToken(state, 'E')) {
- return true;
- }
- *state = copy;
-
- if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
- ParseType(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseBuiltinType(state) ||
- ParseFunctionType(state) ||
- ParseClassEnumType(state) ||
- ParseArrayType(state) ||
- ParsePointerToMemberType(state) ||
- ParseSubstitution(state)) {
- return true;
- }
-
- if (ParseTemplateTemplateParam(state) &&
- ParseTemplateArgs(state)) {
- return true;
- }
- *state = copy;
-
- // Less greedy than <template-template-param> <template-args>.
- if (ParseTemplateParam(state)) {
- return true;
- }
-
- return false;
-}
-
-// <CV-qualifiers> ::= [r] [V] [K]
-// We don't allow empty <CV-qualifiers> to avoid infinite loop in
-// ParseType().
-static bool ParseCVQualifiers(State *state) {
- int num_cv_qualifiers = 0;
- num_cv_qualifiers += ParseOneCharToken(state, 'r');
- num_cv_qualifiers += ParseOneCharToken(state, 'V');
- num_cv_qualifiers += ParseOneCharToken(state, 'K');
- return num_cv_qualifiers > 0;
-}
-
-// <builtin-type> ::= v, etc.
-// ::= u <source-name>
-static bool ParseBuiltinType(State *state) {
- const AbbrevPair *p;
- for (p = kBuiltinTypeList; p->abbrev != NULL; ++p) {
- if (state->mangled_cur[0] == p->abbrev[0]) {
- MaybeAppend(state, p->real_name);
- ++state->mangled_cur;
- return true;
- }
- }
-
- State copy = *state;
- if (ParseOneCharToken(state, 'u') && ParseSourceName(state)) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <function-type> ::= F [Y] <bare-function-type> E
-static bool ParseFunctionType(State *state) {
- State copy = *state;
- if (ParseOneCharToken(state, 'F') &&
- Optional(ParseOneCharToken(state, 'Y')) &&
- ParseBareFunctionType(state) && ParseOneCharToken(state, 'E')) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <bare-function-type> ::= <(signature) type>+
-static bool ParseBareFunctionType(State *state) {
- State copy = *state;
- DisableAppend(state);
- if (OneOrMore(ParseType, state)) {
- RestoreAppend(state, copy.append);
- MaybeAppend(state, "()");
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <class-enum-type> ::= <name>
-static bool ParseClassEnumType(State *state) {
- return ParseName(state);
-}
-
-// <array-type> ::= A <(positive dimension) number> _ <(element) type>
-// ::= A [<(dimension) expression>] _ <(element) type>
-static bool ParseArrayType(State *state) {
- State copy = *state;
- if (ParseOneCharToken(state, 'A') && ParseNumber(state, NULL) &&
- ParseOneCharToken(state, '_') && ParseType(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseOneCharToken(state, 'A') && Optional(ParseExpression(state)) &&
- ParseOneCharToken(state, '_') && ParseType(state)) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <pointer-to-member-type> ::= M <(class) type> <(member) type>
-static bool ParsePointerToMemberType(State *state) {
- State copy = *state;
- if (ParseOneCharToken(state, 'M') && ParseType(state) &&
- ParseType(state)) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <template-param> ::= T_
-// ::= T <parameter-2 non-negative number> _
-static bool ParseTemplateParam(State *state) {
- if (ParseTwoCharToken(state, "T_")) {
- MaybeAppend(state, "?"); // We don't support template substitutions.
- return true;
- }
-
- State copy = *state;
- if (ParseOneCharToken(state, 'T') && ParseNumber(state, NULL) &&
- ParseOneCharToken(state, '_')) {
- MaybeAppend(state, "?"); // We don't support template substitutions.
- return true;
- }
- *state = copy;
- return false;
-}
-
-
-// <template-template-param> ::= <template-param>
-// ::= <substitution>
-static bool ParseTemplateTemplateParam(State *state) {
- return (ParseTemplateParam(state) ||
- ParseSubstitution(state));
-}
-
-// <template-args> ::= I <template-arg>+ E
-static bool ParseTemplateArgs(State *state) {
- State copy = *state;
- DisableAppend(state);
- if (ParseOneCharToken(state, 'I') &&
- OneOrMore(ParseTemplateArg, state) &&
- ParseOneCharToken(state, 'E')) {
- RestoreAppend(state, copy.append);
- MaybeAppend(state, "<>");
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <template-arg> ::= <type>
-// ::= <expr-primary>
-// ::= I <template-arg>* E # argument pack
-// ::= X <expression> E
-static bool ParseTemplateArg(State *state) {
- State copy = *state;
- if (ParseOneCharToken(state, 'I') &&
- ZeroOrMore(ParseTemplateArg, state) &&
- ParseOneCharToken(state, 'E')) {
- return true;
- }
- *state = copy;
-
- if (ParseType(state) ||
- ParseExprPrimary(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseOneCharToken(state, 'X') && ParseExpression(state) &&
- ParseOneCharToken(state, 'E')) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <expression> ::= <template-param>
-// ::= <expr-primary>
-// ::= <unary operator-name> <expression>
-// ::= <binary operator-name> <expression> <expression>
-// ::= <trinary operator-name> <expression> <expression>
-// <expression>
-// ::= st <type>
-// ::= sr <type> <unqualified-name> <template-args>
-// ::= sr <type> <unqualified-name>
-static bool ParseExpression(State *state) {
- if (ParseTemplateParam(state) || ParseExprPrimary(state)) {
- return true;
- }
-
- State copy = *state;
- if (ParseOperatorName(state) &&
- ParseExpression(state) &&
- ParseExpression(state) &&
- ParseExpression(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseOperatorName(state) &&
- ParseExpression(state) &&
- ParseExpression(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseOperatorName(state) &&
- ParseExpression(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseTwoCharToken(state, "st") && ParseType(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
- ParseUnqualifiedName(state) &&
- ParseTemplateArgs(state)) {
- return true;
- }
- *state = copy;
-
- if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
- ParseUnqualifiedName(state)) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <expr-primary> ::= L <type> <(value) number> E
-// ::= L <type> <(value) float> E
-// ::= L <mangled-name> E
-// // A bug in g++'s C++ ABI version 2 (-fabi-version=2).
-// ::= LZ <encoding> E
-static bool ParseExprPrimary(State *state) {
- State copy = *state;
- if (ParseOneCharToken(state, 'L') && ParseType(state) &&
- ParseNumber(state, NULL) &&
- ParseOneCharToken(state, 'E')) {
- return true;
- }
- *state = copy;
-
- if (ParseOneCharToken(state, 'L') && ParseType(state) &&
- ParseFloatNumber(state) &&
- ParseOneCharToken(state, 'E')) {
- return true;
- }
- *state = copy;
-
- if (ParseOneCharToken(state, 'L') && ParseMangledName(state) &&
- ParseOneCharToken(state, 'E')) {
- return true;
- }
- *state = copy;
-
- if (ParseTwoCharToken(state, "LZ") && ParseEncoding(state) &&
- ParseOneCharToken(state, 'E')) {
- return true;
- }
- *state = copy;
-
- return false;
-}
-
-// <local-name> := Z <(function) encoding> E <(entity) name>
-// [<discriminator>]
-// := Z <(function) encoding> E s [<discriminator>]
-static bool ParseLocalName(State *state) {
- State copy = *state;
- if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&
- ParseOneCharToken(state, 'E') && MaybeAppend(state, "::") &&
- ParseName(state) && Optional(ParseDiscriminator(state))) {
- return true;
- }
- *state = copy;
-
- if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&
- ParseTwoCharToken(state, "Es") && Optional(ParseDiscriminator(state))) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <discriminator> := _ <(non-negative) number>
-static bool ParseDiscriminator(State *state) {
- State copy = *state;
- if (ParseOneCharToken(state, '_') && ParseNumber(state, NULL)) {
- return true;
- }
- *state = copy;
- return false;
-}
-
-// <substitution> ::= S_
-// ::= S <seq-id> _
-// ::= St, etc.
-static bool ParseSubstitution(State *state) {
- if (ParseTwoCharToken(state, "S_")) {
- MaybeAppend(state, "?"); // We don't support substitutions.
- return true;
- }
-
- State copy = *state;
- if (ParseOneCharToken(state, 'S') && ParseSeqId(state) &&
- ParseOneCharToken(state, '_')) {
- MaybeAppend(state, "?"); // We don't support substitutions.
- return true;
- }
- *state = copy;
-
- // Expand abbreviations like "St" => "std".
- if (ParseOneCharToken(state, 'S')) {
- const AbbrevPair *p;
- for (p = kSubstitutionList; p->abbrev != NULL; ++p) {
- if (state->mangled_cur[0] == p->abbrev[1]) {
- MaybeAppend(state, "std");
- if (p->real_name[0] != '\0') {
- MaybeAppend(state, "::");
- MaybeAppend(state, p->real_name);
- }
- ++state->mangled_cur;
- return true;
- }
- }
- }
- *state = copy;
- return false;
-}
-
-// Parse <mangled-name>, optionally followed by either a function-clone suffix
-// or version suffix. Returns true only if all of "mangled_cur" was consumed.
-static bool ParseTopLevelMangledName(State *state) {
- if (ParseMangledName(state)) {
- if (state->mangled_cur[0] != '\0') {
- // Drop trailing function clone suffix, if any.
- if (IsFunctionCloneSuffix(state->mangled_cur)) {
- return true;
- }
- // Append trailing version suffix if any.
- // ex. _Z3foo@@GLIBCXX_3.4
- if (state->mangled_cur[0] == '@') {
- MaybeAppend(state, state->mangled_cur);
- return true;
- }
- return false; // Unconsumed suffix.
- }
- return true;
- }
- return false;
-}
-
-// The demangler entry point.
-bool Demangle(const char *mangled, char *out, int out_size) {
- State state;
- InitState(&state, mangled, out, out_size);
- return ParseTopLevelMangledName(&state) && !state.overflowed;
-}
-
-_END_GOOGLE_NAMESPACE_
diff --git a/base/third_party/symbolize/demangle.h b/base/third_party/symbolize/demangle.h
deleted file mode 100644
index 9c75915..0000000
--- a/base/third_party/symbolize/demangle.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Satoru Takabayashi
-//
-// An async-signal-safe and thread-safe demangler for Itanium C++ ABI
-// (aka G++ V3 ABI).
-
-// The demangler is implemented to be used in async signal handlers to
-// symbolize stack traces. We cannot use libstdc++'s
-// abi::__cxa_demangle() in such signal handlers since it's not async
-// signal safe (it uses malloc() internally).
-//
-// Note that this demangler doesn't support full demangling. More
-// specifically, it doesn't print types of function parameters and
-// types of template arguments. It just skips them. However, it's
-// still very useful to extract basic information such as class,
-// function, constructor, destructor, and operator names.
-//
-// See the implementation note in demangle.cc if you are interested.
-//
-// Example:
-//
-// | Mangled Name | The Demangler | abi::__cxa_demangle()
-// |---------------|---------------|-----------------------
-// | _Z1fv | f() | f()
-// | _Z1fi | f() | f(int)
-// | _Z3foo3bar | foo() | foo(bar)
-// | _Z1fIiEvi | f<>() | void f<int>(int)
-// | _ZN1N1fE | N::f | N::f
-// | _ZN3Foo3BarEv | Foo::Bar() | Foo::Bar()
-// | _Zrm1XS_" | operator%() | operator%(X, X)
-// | _ZN3FooC1Ev | Foo::Foo() | Foo::Foo()
-// | _Z1fSs | f() | f(std::basic_string<char,
-// | | | std::char_traits<char>,
-// | | | std::allocator<char> >)
-//
-// See the unit test for more examples.
-//
-// Note: we might want to write demanglers for ABIs other than Itanium
-// C++ ABI in the future.
-//
-
-#ifndef BASE_DEMANGLE_H_
-#define BASE_DEMANGLE_H_
-
-#include "config.h"
-
-_START_GOOGLE_NAMESPACE_
-
-// Demangle "mangled". On success, return true and write the
-// demangled symbol name to "out". Otherwise, return false.
-// "out" is modified even if demangling is unsuccessful.
-bool Demangle(const char *mangled, char *out, int out_size);
-
-_END_GOOGLE_NAMESPACE_
-
-#endif // BASE_DEMANGLE_H_
diff --git a/base/third_party/symbolize/glog/logging.h b/base/third_party/symbolize/glog/logging.h
deleted file mode 100644
index a42c306..0000000
--- a/base/third_party/symbolize/glog/logging.h
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Empty.
diff --git a/base/third_party/symbolize/glog/raw_logging.h b/base/third_party/symbolize/glog/raw_logging.h
deleted file mode 100644
index f5515c4..0000000
--- a/base/third_party/symbolize/glog/raw_logging.h
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#define WARNING 1;
-#define RAW_LOG(severity, ...); // Do nothing.
diff --git a/base/third_party/symbolize/symbolize.cc b/base/third_party/symbolize/symbolize.cc
deleted file mode 100644
index e6fbb84..0000000
--- a/base/third_party/symbolize/symbolize.cc
+++ /dev/null
@@ -1,883 +0,0 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Satoru Takabayashi
-// Stack-footprint reduction work done by Raksit Ashok
-//
-// Implementation note:
-//
-// We don't use heaps but only use stacks. We want to reduce the
-// stack consumption so that the symbolizer can run on small stacks.
-//
-// Here are some numbers collected with GCC 4.1.0 on x86:
-// - sizeof(Elf32_Sym) = 16
-// - sizeof(Elf32_Shdr) = 40
-// - sizeof(Elf64_Sym) = 24
-// - sizeof(Elf64_Shdr) = 64
-//
-// This implementation is intended to be async-signal-safe but uses
-// some functions which are not guaranteed to be so, such as memchr()
-// and memmove(). We assume they are async-signal-safe.
-//
-// Additional header can be specified by the GLOG_BUILD_CONFIG_INCLUDE
-// macro to add platform specific defines (e.g. OS_OPENBSD).
-
-#ifdef GLOG_BUILD_CONFIG_INCLUDE
-#include GLOG_BUILD_CONFIG_INCLUDE
-#endif // GLOG_BUILD_CONFIG_INCLUDE
-
-#include "utilities.h"
-
-#if defined(HAVE_SYMBOLIZE)
-
-#include <string.h>
-
-#include <algorithm>
-#include <limits>
-
-#include "symbolize.h"
-#include "demangle.h"
-
-_START_GOOGLE_NAMESPACE_
-
-// We don't use assert() since it's not guaranteed to be
-// async-signal-safe. Instead we define a minimal assertion
-// macro. So far, we don't need pretty printing for __FILE__, etc.
-
-// A wrapper for abort() to make it callable in ? :.
-static int AssertFail() {
- abort();
- return 0; // Should not reach.
-}
-
-#define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
-
-static SymbolizeCallback g_symbolize_callback = NULL;
-void InstallSymbolizeCallback(SymbolizeCallback callback) {
- g_symbolize_callback = callback;
-}
-
-static SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback =
- NULL;
-void InstallSymbolizeOpenObjectFileCallback(
- SymbolizeOpenObjectFileCallback callback) {
- g_symbolize_open_object_file_callback = callback;
-}
-
-// This function wraps the Demangle function to provide an interface
-// where the input symbol is demangled in-place.
-// To keep stack consumption low, we would like this function to not
-// get inlined.
-static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
- char demangled[256]; // Big enough for sane demangled symbols.
- if (Demangle(out, demangled, sizeof(demangled))) {
- // Demangling succeeded. Copy to out if the space allows.
- size_t len = strlen(demangled);
- if (len + 1 <= (size_t)out_size) { // +1 for '\0'.
- SAFE_ASSERT(len < sizeof(demangled));
- memmove(out, demangled, len + 1);
- }
- }
-}
-
-_END_GOOGLE_NAMESPACE_
-
-#if defined(__ELF__)
-
-#include <dlfcn.h>
-#if defined(OS_OPENBSD)
-#include <sys/exec_elf.h>
-#else
-#include <elf.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "symbolize.h"
-#include "config.h"
-#include "glog/raw_logging.h"
-
-// Re-runs fn until it doesn't cause EINTR.
-#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
-
-_START_GOOGLE_NAMESPACE_
-
-// Read up to "count" bytes from file descriptor "fd" into the buffer
-// starting at "buf" while handling short reads and EINTR. On
-// success, return the number of bytes read. Otherwise, return -1.
-static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
- SAFE_ASSERT(fd >= 0);
- SAFE_ASSERT(count <= std::numeric_limits<ssize_t>::max());
- char *buf0 = reinterpret_cast<char *>(buf);
- ssize_t num_bytes = 0;
- while (num_bytes < count) {
- ssize_t len;
- NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
- if (len < 0) { // There was an error other than EINTR.
- return -1;
- }
- if (len == 0) { // Reached EOF.
- break;
- }
- num_bytes += len;
- }
- SAFE_ASSERT(num_bytes <= count);
- return num_bytes;
-}
-
-// Read up to "count" bytes from "offset" in the file pointed by file
-// descriptor "fd" into the buffer starting at "buf". On success,
-// return the number of bytes read. Otherwise, return -1.
-static ssize_t ReadFromOffset(const int fd, void *buf,
- const size_t count, const off_t offset) {
- off_t off = lseek(fd, offset, SEEK_SET);
- if (off == (off_t)-1) {
- return -1;
- }
- return ReadPersistent(fd, buf, count);
-}
-
-// Try reading exactly "count" bytes from "offset" bytes in a file
-// pointed by "fd" into the buffer starting at "buf" while handling
-// short reads and EINTR. On success, return true. Otherwise, return
-// false.
-static bool ReadFromOffsetExact(const int fd, void *buf,
- const size_t count, const off_t offset) {
- ssize_t len = ReadFromOffset(fd, buf, count, offset);
- return len == count;
-}
-
-// Returns elf_header.e_type if the file pointed by fd is an ELF binary.
-static int FileGetElfType(const int fd) {
- ElfW(Ehdr) elf_header;
- if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
- return -1;
- }
- if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
- return -1;
- }
- return elf_header.e_type;
-}
-
-// Read the section headers in the given ELF binary, and if a section
-// of the specified type is found, set the output to this section header
-// and return true. Otherwise, return false.
-// To keep stack consumption low, we would like this function to not get
-// inlined.
-static ATTRIBUTE_NOINLINE bool
-GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const off_t sh_offset,
- ElfW(Word) type, ElfW(Shdr) *out) {
- // Read at most 16 section headers at a time to save read calls.
- ElfW(Shdr) buf[16];
- for (int i = 0; i < sh_num;) {
- const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
- const ssize_t num_bytes_to_read =
- (sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);
- const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,
- sh_offset + i * sizeof(buf[0]));
- SAFE_ASSERT(len % sizeof(buf[0]) == 0);
- const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
- SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
- for (int j = 0; j < num_headers_in_buf; ++j) {
- if (buf[j].sh_type == type) {
- *out = buf[j];
- return true;
- }
- }
- i += num_headers_in_buf;
- }
- return false;
-}
-
-// There is no particular reason to limit section name to 63 characters,
-// but there has (as yet) been no need for anything longer either.
-const int kMaxSectionNameLen = 64;
-
-// name_len should include terminating '\0'.
-bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
- ElfW(Shdr) *out) {
- ElfW(Ehdr) elf_header;
- if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
- return false;
- }
-
- ElfW(Shdr) shstrtab;
- off_t shstrtab_offset = (elf_header.e_shoff +
- elf_header.e_shentsize * elf_header.e_shstrndx);
- if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
- return false;
- }
-
- for (int i = 0; i < elf_header.e_shnum; ++i) {
- off_t section_header_offset = (elf_header.e_shoff +
- elf_header.e_shentsize * i);
- if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
- return false;
- }
- char header_name[kMaxSectionNameLen];
- if (sizeof(header_name) < name_len) {
- RAW_LOG(WARNING, "Section name '%s' is too long (%" PRIuS "); "
- "section will not be found (even if present).", name, name_len);
- // No point in even trying.
- return false;
- }
- off_t name_offset = shstrtab.sh_offset + out->sh_name;
- ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
- if (n_read == -1) {
- return false;
- } else if (n_read != name_len) {
- // Short read -- name could be at end of file.
- continue;
- }
- if (memcmp(header_name, name, name_len) == 0) {
- return true;
- }
- }
- return false;
-}
-
-// Read a symbol table and look for the symbol containing the
-// pc. Iterate over symbols in a symbol table and look for the symbol
-// containing "pc". On success, return true and write the symbol name
-// to out. Otherwise, return false.
-// To keep stack consumption low, we would like this function to not get
-// inlined.
-static ATTRIBUTE_NOINLINE bool
-FindSymbol(uint64_t pc, const int fd, char *out, int out_size,
- uint64_t symbol_offset, const ElfW(Shdr) *strtab,
- const ElfW(Shdr) *symtab) {
- if (symtab == NULL) {
- return false;
- }
- const int num_symbols = symtab->sh_size / symtab->sh_entsize;
- for (int i = 0; i < num_symbols;) {
- off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
-
- // If we are reading Elf64_Sym's, we want to limit this array to
- // 32 elements (to keep stack consumption low), otherwise we can
- // have a 64 element Elf32_Sym array.
-#if __WORDSIZE == 64
-#define NUM_SYMBOLS 32
-#else
-#define NUM_SYMBOLS 64
-#endif
-
- // Read at most NUM_SYMBOLS symbols at once to save read() calls.
- ElfW(Sym) buf[NUM_SYMBOLS];
- int num_symbols_to_read = std::min(NUM_SYMBOLS, num_symbols - i);
- const ssize_t len =
- ReadFromOffset(fd, &buf, sizeof(buf[0]) * num_symbols_to_read, offset);
- SAFE_ASSERT(len % sizeof(buf[0]) == 0);
- const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
- SAFE_ASSERT(num_symbols_in_buf <= num_symbols_to_read);
- for (int j = 0; j < num_symbols_in_buf; ++j) {
- const ElfW(Sym)& symbol = buf[j];
- uint64_t start_address = symbol.st_value;
- start_address += symbol_offset;
- uint64_t end_address = start_address + symbol.st_size;
- if (symbol.st_value != 0 && // Skip null value symbols.
- symbol.st_shndx != 0 && // Skip undefined symbols.
- start_address <= pc && pc < end_address) {
- ssize_t len1 = ReadFromOffset(fd, out, out_size,
- strtab->sh_offset + symbol.st_name);
- if (len1 <= 0 || memchr(out, '\0', out_size) == NULL) {
- return false;
- }
- return true; // Obtained the symbol name.
- }
- }
- i += num_symbols_in_buf;
- }
- return false;
-}
-
-// Get the symbol name of "pc" from the file pointed by "fd". Process
-// both regular and dynamic symbol tables if necessary. On success,
-// write the symbol name to "out" and return true. Otherwise, return
-// false.
-static bool GetSymbolFromObjectFile(const int fd,
- uint64_t pc,
- char* out,
- int out_size,
- uint64_t base_address) {
- // Read the ELF header.
- ElfW(Ehdr) elf_header;
- if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
- return false;
- }
-
- ElfW(Shdr) symtab, strtab;
-
- // Consult a regular symbol table first.
- if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
- SHT_SYMTAB, &symtab)) {
- if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
- symtab.sh_link * sizeof(symtab))) {
- return false;
- }
- if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
- return true; // Found the symbol in a regular symbol table.
- }
- }
-
- // If the symbol is not found, then consult a dynamic symbol table.
- if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
- SHT_DYNSYM, &symtab)) {
- if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
- symtab.sh_link * sizeof(symtab))) {
- return false;
- }
- if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
- return true; // Found the symbol in a dynamic symbol table.
- }
- }
-
- return false;
-}
-
-namespace {
-// Thin wrapper around a file descriptor so that the file descriptor
-// gets closed for sure.
-struct FileDescriptor {
- const int fd_;
- explicit FileDescriptor(int fd) : fd_(fd) {}
- ~FileDescriptor() {
- if (fd_ >= 0) {
- NO_INTR(close(fd_));
- }
- }
- int get() { return fd_; }
-
- private:
- explicit FileDescriptor(const FileDescriptor&);
- void operator=(const FileDescriptor&);
-};
-
-// Helper class for reading lines from file.
-//
-// Note: we don't use ProcMapsIterator since the object is big (it has
-// a 5k array member) and uses async-unsafe functions such as sscanf()
-// and snprintf().
-class LineReader {
- public:
- explicit LineReader(int fd, char *buf, int buf_len) : fd_(fd),
- buf_(buf), buf_len_(buf_len), bol_(buf), eol_(buf), eod_(buf) {
- }
-
- // Read '\n'-terminated line from file. On success, modify "bol"
- // and "eol", then return true. Otherwise, return false.
- //
- // Note: if the last line doesn't end with '\n', the line will be
- // dropped. It's an intentional behavior to make the code simple.
- bool ReadLine(const char **bol, const char **eol) {
- if (BufferIsEmpty()) { // First time.
- const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
- if (num_bytes <= 0) { // EOF or error.
- return false;
- }
- eod_ = buf_ + num_bytes;
- bol_ = buf_;
- } else {
- bol_ = eol_ + 1; // Advance to the next line in the buffer.
- SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_".
- if (!HasCompleteLine()) {
- const int incomplete_line_length = eod_ - bol_;
- // Move the trailing incomplete line to the beginning.
- memmove(buf_, bol_, incomplete_line_length);
- // Read text from file and append it.
- char * const append_pos = buf_ + incomplete_line_length;
- const int capacity_left = buf_len_ - incomplete_line_length;
- const ssize_t num_bytes = ReadPersistent(fd_, append_pos,
- capacity_left);
- if (num_bytes <= 0) { // EOF or error.
- return false;
- }
- eod_ = append_pos + num_bytes;
- bol_ = buf_;
- }
- }
- eol_ = FindLineFeed();
- if (eol_ == NULL) { // '\n' not found. Malformed line.
- return false;
- }
- *eol_ = '\0'; // Replace '\n' with '\0'.
-
- *bol = bol_;
- *eol = eol_;
- return true;
- }
-
- // Beginning of line.
- const char *bol() {
- return bol_;
- }
-
- // End of line.
- const char *eol() {
- return eol_;
- }
-
- private:
- explicit LineReader(const LineReader&);
- void operator=(const LineReader&);
-
- char *FindLineFeed() {
- return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_));
- }
-
- bool BufferIsEmpty() {
- return buf_ == eod_;
- }
-
- bool HasCompleteLine() {
- return !BufferIsEmpty() && FindLineFeed() != NULL;
- }
-
- const int fd_;
- char * const buf_;
- const int buf_len_;
- char *bol_;
- char *eol_;
- const char *eod_; // End of data in "buf_".
-};
-} // namespace
-
-// Place the hex number read from "start" into "*hex". The pointer to
-// the first non-hex character or "end" is returned.
-static char *GetHex(const char *start, const char *end, uint64_t *hex) {
- *hex = 0;
- const char *p;
- for (p = start; p < end; ++p) {
- int ch = *p;
- if ((ch >= '0' && ch <= '9') ||
- (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
- *hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
- } else { // Encountered the first non-hex character.
- break;
- }
- }
- SAFE_ASSERT(p <= end);
- return const_cast<char *>(p);
-}
-
-// Searches for the object file (from /proc/self/maps) that contains
-// the specified pc. If found, sets |start_address| to the start address
-// of where this object file is mapped in memory, sets the module base
-// address into |base_address|, copies the object file name into
-// |out_file_name|, and attempts to open the object file. If the object
-// file is opened successfully, returns the file descriptor. Otherwise,
-// returns -1. |out_file_name_size| is the size of the file name buffer
-// (including the null-terminator).
-static ATTRIBUTE_NOINLINE int
-OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
- uint64_t &start_address,
- uint64_t &base_address,
- char *out_file_name,
- int out_file_name_size) {
- int object_fd;
-
- int maps_fd;
- NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
- FileDescriptor wrapped_maps_fd(maps_fd);
- if (wrapped_maps_fd.get() < 0) {
- return -1;
- }
-
- int mem_fd;
- NO_INTR(mem_fd = open("/proc/self/mem", O_RDONLY));
- FileDescriptor wrapped_mem_fd(mem_fd);
- if (wrapped_mem_fd.get() < 0) {
- return -1;
- }
-
- // Iterate over maps and look for the map containing the pc. Then
- // look into the symbol tables inside.
- char buf[1024]; // Big enough for line of sane /proc/self/maps
- int num_maps = 0;
- LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
- while (true) {
- num_maps++;
- const char *cursor;
- const char *eol;
- if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
- return -1;
- }
-
- // Start parsing line in /proc/self/maps. Here is an example:
- //
- // 08048000-0804c000 r-xp 00000000 08:01 2142121 /bin/cat
- //
- // We want start address (08048000), end address (0804c000), flags
- // (r-xp) and file name (/bin/cat).
-
- // Read start address.
- cursor = GetHex(cursor, eol, &start_address);
- if (cursor == eol || *cursor != '-') {
- return -1; // Malformed line.
- }
- ++cursor; // Skip '-'.
-
- // Read end address.
- uint64_t end_address;
- cursor = GetHex(cursor, eol, &end_address);
- if (cursor == eol || *cursor != ' ') {
- return -1; // Malformed line.
- }
- ++cursor; // Skip ' '.
-
- // Read flags. Skip flags until we encounter a space or eol.
- const char * const flags_start = cursor;
- while (cursor < eol && *cursor != ' ') {
- ++cursor;
- }
- // We expect at least four letters for flags (ex. "r-xp").
- if (cursor == eol || cursor < flags_start + 4) {
- return -1; // Malformed line.
- }
-
- // Determine the base address by reading ELF headers in process memory.
- ElfW(Ehdr) ehdr;
- if (flags_start[0] == 'r' &&
- ReadFromOffsetExact(mem_fd, &ehdr, sizeof(ElfW(Ehdr)), start_address) &&
- memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {
- switch (ehdr.e_type) {
- case ET_EXEC:
- base_address = 0;
- break;
- case ET_DYN:
- // Find the segment containing file offset 0. This will correspond
- // to the ELF header that we just read. Normally this will have
- // virtual address 0, but this is not guaranteed. We must subtract
- // the virtual address from the address where the ELF header was
- // mapped to get the base address.
- //
- // If we fail to find a segment for file offset 0, use the address
- // of the ELF header as the base address.
- base_address = start_address;
- for (unsigned i = 0; i != ehdr.e_phnum; ++i) {
- ElfW(Phdr) phdr;
- if (ReadFromOffsetExact(
- mem_fd, &phdr, sizeof(phdr),
- start_address + ehdr.e_phoff + i * sizeof(phdr)) &&
- phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
- base_address = start_address - phdr.p_vaddr;
- break;
- }
- }
- break;
- default:
- // ET_REL or ET_CORE. These aren't directly executable, so they don't
- // affect the base address.
- break;
- }
- }
-
- // Check start and end addresses.
- if (!(start_address <= pc && pc < end_address)) {
- continue; // We skip this map. PC isn't in this map.
- }
-
- // Check flags. We are only interested in "r-x" maps.
- if (memcmp(flags_start, "r-x", 3) != 0) { // Not a "r-x" map.
- continue; // We skip this map.
- }
- ++cursor; // Skip ' '.
-
- // Read file offset.
- uint64_t file_offset;
- cursor = GetHex(cursor, eol, &file_offset);
- if (cursor == eol || *cursor != ' ') {
- return -1; // Malformed line.
- }
- ++cursor; // Skip ' '.
-
- // Skip to file name. "cursor" now points to dev. We need to
- // skip at least two spaces for dev and inode.
- int num_spaces = 0;
- while (cursor < eol) {
- if (*cursor == ' ') {
- ++num_spaces;
- } else if (num_spaces >= 2) {
- // The first non-space character after skipping two spaces
- // is the beginning of the file name.
- break;
- }
- ++cursor;
- }
- if (cursor == eol) {
- return -1; // Malformed line.
- }
-
- // Finally, "cursor" now points to file name of our interest.
- NO_INTR(object_fd = open(cursor, O_RDONLY));
- if (object_fd < 0) {
- // Failed to open object file. Copy the object file name to
- // |out_file_name|.
- strncpy(out_file_name, cursor, out_file_name_size);
- // Making sure |out_file_name| is always null-terminated.
- out_file_name[out_file_name_size - 1] = '\0';
- return -1;
- }
- return object_fd;
- }
-}
-
-// POSIX doesn't define any async-signal safe function for converting
-// an integer to ASCII. We'll have to define our own version.
-// itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
-// conversion was successful or NULL otherwise. It never writes more than "sz"
-// bytes. Output will be truncated as needed, and a NUL character is always
-// appended.
-// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
-char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
- // Make sure we can write at least one NUL byte.
- size_t n = 1;
- if (n > sz)
- return NULL;
-
- if (base < 2 || base > 16) {
- buf[0] = '\000';
- return NULL;
- }
-
- char *start = buf;
-
- uintptr_t j = i;
-
- // Handle negative numbers (only for base 10).
- if (i < 0 && base == 10) {
- // This does "j = -i" while avoiding integer overflow.
- j = static_cast<uintptr_t>(-(i + 1)) + 1;
-
- // Make sure we can write the '-' character.
- if (++n > sz) {
- buf[0] = '\000';
- return NULL;
- }
- *start++ = '-';
- }
-
- // Loop until we have converted the entire number. Output at least one
- // character (i.e. '0').
- char *ptr = start;
- do {
- // Make sure there is still enough space left in our output buffer.
- if (++n > sz) {
- buf[0] = '\000';
- return NULL;
- }
-
- // Output the next digit.
- *ptr++ = "0123456789abcdef"[j % base];
- j /= base;
-
- if (padding > 0)
- padding--;
- } while (j > 0 || padding > 0);
-
- // Terminate the output with a NUL character.
- *ptr = '\000';
-
- // Conversion to ASCII actually resulted in the digits being in reverse
- // order. We can't easily generate them in forward order, as we can't tell
- // the number of characters needed until we are done converting.
- // So, now, we reverse the string (except for the possible "-" sign).
- while (--ptr > start) {
- char ch = *ptr;
- *ptr = *start;
- *start++ = ch;
- }
- return buf;
-}
-
-// Safely appends string |source| to string |dest|. Never writes past the
-// buffer size |dest_size| and guarantees that |dest| is null-terminated.
-void SafeAppendString(const char* source, char* dest, int dest_size) {
- int dest_string_length = strlen(dest);
- SAFE_ASSERT(dest_string_length < dest_size);
- dest += dest_string_length;
- dest_size -= dest_string_length;
- strncpy(dest, source, dest_size);
- // Making sure |dest| is always null-terminated.
- dest[dest_size - 1] = '\0';
-}
-
-// Converts a 64-bit value into a hex string, and safely appends it to |dest|.
-// Never writes past the buffer size |dest_size| and guarantees that |dest| is
-// null-terminated.
-void SafeAppendHexNumber(uint64_t value, char* dest, int dest_size) {
- // 64-bit numbers in hex can have up to 16 digits.
- char buf[17] = {'\0'};
- SafeAppendString(itoa_r(value, buf, sizeof(buf), 16, 0), dest, dest_size);
-}
-
-// The implementation of our symbolization routine. If it
-// successfully finds the symbol containing "pc" and obtains the
-// symbol name, returns true and write the symbol name to "out".
-// Otherwise, returns false. If Callback function is installed via
-// InstallSymbolizeCallback(), the function is also called in this function,
-// and "out" is used as its output.
-// To keep stack consumption low, we would like this function to not
-// get inlined.
-static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
- int out_size) {
- uint64_t pc0 = reinterpret_cast<uintptr_t>(pc);
- uint64_t start_address = 0;
- uint64_t base_address = 0;
- int object_fd = -1;
-
- if (out_size < 1) {
- return false;
- }
- out[0] = '\0';
- SafeAppendString("(", out, out_size);
-
- if (g_symbolize_open_object_file_callback) {
- object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
- base_address, out + 1,
- out_size - 1);
- } else {
- object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
- base_address,
- out + 1,
- out_size - 1);
- }
-
- // Check whether a file name was returned.
-#if !defined(PRINT_UNSYMBOLIZED_STACK_TRACES)
- if (object_fd < 0) {
-#endif
- if (out[1]) {
- // The object file containing PC was determined successfully however the
- // object file was not opened successfully. This is still considered
- // success because the object file name and offset are known and tools
- // like asan_symbolize.py can be used for the symbolization.
- out[out_size - 1] = '\0'; // Making sure |out| is always null-terminated.
- SafeAppendString("+0x", out, out_size);
- SafeAppendHexNumber(pc0 - base_address, out, out_size);
- SafeAppendString(")", out, out_size);
- return true;
- }
- // Failed to determine the object file containing PC. Bail out.
- return false;
-#if !defined(PRINT_UNSYMBOLIZED_STACK_TRACES)
- }
-#endif
- FileDescriptor wrapped_object_fd(object_fd);
- int elf_type = FileGetElfType(wrapped_object_fd.get());
- if (elf_type == -1) {
- return false;
- }
- if (g_symbolize_callback) {
- // Run the call back if it's installed.
- // Note: relocation (and much of the rest of this code) will be
- // wrong for prelinked shared libraries and PIE executables.
- uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;
- int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
- pc, out, out_size,
- relocation);
- if (num_bytes_written > 0) {
- out += num_bytes_written;
- out_size -= num_bytes_written;
- }
- }
- if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
- out, out_size, base_address)) {
- return false;
- }
-
- // Symbolization succeeded. Now we try to demangle the symbol.
- DemangleInplace(out, out_size);
- return true;
-}
-
-_END_GOOGLE_NAMESPACE_
-
-#elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
-
-#include <dlfcn.h>
-#include <string.h>
-
-_START_GOOGLE_NAMESPACE_
-
-static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
- int out_size) {
- Dl_info info;
- if (dladdr(pc, &info)) {
- if ((int)strlen(info.dli_sname) < out_size) {
- strcpy(out, info.dli_sname);
- // Symbolization succeeded. Now we try to demangle the symbol.
- DemangleInplace(out, out_size);
- return true;
- }
- }
- return false;
-}
-
-_END_GOOGLE_NAMESPACE_
-
-#else
-# error BUG: HAVE_SYMBOLIZE was wrongly set
-#endif
-
-_START_GOOGLE_NAMESPACE_
-
-bool Symbolize(void *pc, char *out, int out_size) {
- SAFE_ASSERT(out_size >= 0);
- return SymbolizeAndDemangle(pc, out, out_size);
-}
-
-_END_GOOGLE_NAMESPACE_
-
-#else /* HAVE_SYMBOLIZE */
-
-#include <assert.h>
-
-#include "config.h"
-
-_START_GOOGLE_NAMESPACE_
-
-// TODO: Support other environments.
-bool Symbolize(void *pc, char *out, int out_size) {
- assert(0);
- return false;
-}
-
-_END_GOOGLE_NAMESPACE_
-
-#endif
diff --git a/base/third_party/symbolize/symbolize.h b/base/third_party/symbolize/symbolize.h
deleted file mode 100644
index aeb2fe3..0000000
--- a/base/third_party/symbolize/symbolize.h
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Satoru Takabayashi
-//
-// This library provides Symbolize() function that symbolizes program
-// counters to their corresponding symbol names on linux platforms.
-// This library has a minimal implementation of an ELF symbol table
-// reader (i.e. it doesn't depend on libelf, etc.).
-//
-// The algorithm used in Symbolize() is as follows.
-//
-// 1. Go through a list of maps in /proc/self/maps and find the map
-// containing the program counter.
-//
-// 2. Open the mapped file and find a regular symbol table inside.
-// Iterate over symbols in the symbol table and look for the symbol
-// containing the program counter. If such a symbol is found,
-// obtain the symbol name, and demangle the symbol if possible.
-// If the symbol isn't found in the regular symbol table (binary is
-// stripped), try the same thing with a dynamic symbol table.
-//
-// Note that Symbolize() is originally implemented to be used in
-// FailureSignalHandler() in base/google.cc. Hence it doesn't use
-// malloc() and other unsafe operations. It should be both
-// thread-safe and async-signal-safe.
-
-#ifndef BASE_SYMBOLIZE_H_
-#define BASE_SYMBOLIZE_H_
-
-#include "utilities.h"
-#include "config.h"
-#include "glog/logging.h"
-
-#ifdef HAVE_SYMBOLIZE
-
-#if defined(__ELF__) // defined by gcc
-#if defined(__OpenBSD__)
-#include <sys/exec_elf.h>
-#else
-#include <elf.h>
-#endif
-
-#if !defined(ANDROID)
-#include <link.h> // For ElfW() macro.
-#endif
-
-// For systems where SIZEOF_VOID_P is not defined, determine it
-// based on __LP64__ (defined by gcc on 64-bit systems)
-#if !defined(SIZEOF_VOID_P)
-# if defined(__LP64__)
-# define SIZEOF_VOID_P 8
-# else
-# define SIZEOF_VOID_P 4
-# endif
-#endif
-
-// If there is no ElfW macro, let's define it by ourself.
-#ifndef ElfW
-# if SIZEOF_VOID_P == 4
-# define ElfW(type) Elf32_##type
-# elif SIZEOF_VOID_P == 8
-# define ElfW(type) Elf64_##type
-# else
-# error "Unknown sizeof(void *)"
-# endif
-#endif
-
-_START_GOOGLE_NAMESPACE_
-
-// Gets the section header for the given name, if it exists. Returns true on
-// success. Otherwise, returns false.
-bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
- ElfW(Shdr) *out);
-
-_END_GOOGLE_NAMESPACE_
-
-#endif /* __ELF__ */
-
-_START_GOOGLE_NAMESPACE_
-
-// Restrictions on the callbacks that follow:
-// - The callbacks must not use heaps but only use stacks.
-// - The callbacks must be async-signal-safe.
-
-// Installs a callback function, which will be called right before a symbol name
-// is printed. The callback is intended to be used for showing a file name and a
-// line number preceding a symbol name.
-// "fd" is a file descriptor of the object file containing the program
-// counter "pc". The callback function should write output to "out"
-// and return the size of the output written. On error, the callback
-// function should return -1.
-typedef int (*SymbolizeCallback)(int fd, void *pc, char *out, size_t out_size,
- uint64_t relocation);
-void InstallSymbolizeCallback(SymbolizeCallback callback);
-
-// Installs a callback function, which will be called instead of
-// OpenObjectFileContainingPcAndGetStartAddress. The callback is expected
-// to searches for the object file (from /proc/self/maps) that contains
-// the specified pc. If found, sets |start_address| to the start address
-// of where this object file is mapped in memory, sets the module base
-// address into |base_address|, copies the object file name into
-// |out_file_name|, and attempts to open the object file. If the object
-// file is opened successfully, returns the file descriptor. Otherwise,
-// returns -1. |out_file_name_size| is the size of the file name buffer
-// (including the null-terminator).
-typedef int (*SymbolizeOpenObjectFileCallback)(uint64_t pc,
- uint64_t &start_address,
- uint64_t &base_address,
- char *out_file_name,
- int out_file_name_size);
-void InstallSymbolizeOpenObjectFileCallback(
- SymbolizeOpenObjectFileCallback callback);
-
-_END_GOOGLE_NAMESPACE_
-
-#endif
-
-_START_GOOGLE_NAMESPACE_
-
-// Symbolizes a program counter. On success, returns true and write the
-// symbol name to "out". The symbol name is demangled if possible
-// (supports symbols generated by GCC 3.x or newer). Otherwise,
-// returns false.
-bool Symbolize(void *pc, char *out, int out_size);
-
-_END_GOOGLE_NAMESPACE_
-
-#endif // BASE_SYMBOLIZE_H_
diff --git a/base/third_party/symbolize/utilities.h b/base/third_party/symbolize/utilities.h
deleted file mode 100644
index 65c5ba0..0000000
--- a/base/third_party/symbolize/utilities.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define HAVE_SYMBOLIZE 1
-#define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
index daccc0e..d45211f 100644
--- a/base/threading/platform_thread_win.cc
+++ b/base/threading/platform_thread_win.cc
@@ -6,9 +6,6 @@
#include <stddef.h>
-#include "base/debug/activity_tracker.h"
-#include "base/debug/alias.h"
-#include "base/debug/profiler.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
@@ -237,10 +234,6 @@
if (!thread_id)
last_error = ::GetLastError();
- // Record information about the exiting thread in case joining hangs.
- base::debug::Alias(&thread_id);
- base::debug::Alias(&last_error);
-
// Record the event that this thread is blocking upon (for hang diagnosis).
base::debug::ScopedThreadJoinActivity thread_activity(&thread_handle);
diff --git a/base/threading/post_task_and_reply_impl.cc b/base/threading/post_task_and_reply_impl.cc
index 5aacdad..83c9dcb 100644
--- a/base/threading/post_task_and_reply_impl.cc
+++ b/base/threading/post_task_and_reply_impl.cc
@@ -7,7 +7,6 @@
#include <utility>
#include "base/bind.h"
-#include "base/debug/leak_annotations.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
@@ -54,7 +53,6 @@
// https://crbug.com/829122).
auto relay_to_delete =
std::make_unique<PostTaskAndReplyRelay>(std::move(*this));
- ANNOTATE_LEAKING_OBJECT_PTR(relay_to_delete.get());
reply_task_runner_->DeleteSoon(from_here_, std::move(relay_to_delete));
}
diff --git a/base/win/scoped_handle_verifier.cc b/base/win/scoped_handle_verifier.cc
index 930d147..080bdbc 100644
--- a/base/win/scoped_handle_verifier.cc
+++ b/base/win/scoped_handle_verifier.cc
@@ -9,8 +9,6 @@
#include <unordered_map>
-#include "base/debug/alias.h"
-#include "base/debug/stack_trace.h"
#include "base/synchronization/lock_impl.h"
#include "base/win/current_module.h"
@@ -156,9 +154,7 @@
std::pair<HandleMap::iterator, bool> result = map_.insert(item);
if (!result.second) {
ScopedHandleVerifierInfo other = result.first->second;
- base::debug::Alias(&other);
auto creation_stack = creation_stack_;
- base::debug::Alias(&creation_stack);
CHECK(false); // Attempt to start tracking already tracked handle.
}
}
@@ -174,15 +170,12 @@
HandleMap::iterator i = map_.find(handle);
if (i == map_.end()) {
auto creation_stack = creation_stack_;
- base::debug::Alias(&creation_stack);
CHECK(false); // Attempting to close an untracked handle.
}
ScopedHandleVerifierInfo other = i->second;
if (other.owner != owner) {
- base::debug::Alias(&other);
auto creation_stack = creation_stack_;
- base::debug::Alias(&creation_stack);
CHECK(false); // Attempting to close a handle not owned by opener.
}
@@ -206,9 +199,7 @@
return;
ScopedHandleVerifierInfo other = i->second;
- base::debug::Alias(&other);
auto creation_stack = creation_stack_;
- base::debug::Alias(&creation_stack);
CHECK(false); // CloseHandle called on tracked handle.
}
diff --git a/base/win/scoped_handle_verifier.h b/base/win/scoped_handle_verifier.h
index 008e790..a7c131e 100644
--- a/base/win/scoped_handle_verifier.h
+++ b/base/win/scoped_handle_verifier.h
@@ -10,7 +10,6 @@
#include <unordered_map>
#include "base/base_export.h"
-#include "base/debug/stack_trace.h"
#include "base/hash.h"
#include "base/synchronization/lock_impl.h"
#include "base/threading/thread_local.h"
diff --git a/base/win/scoped_hdc.h b/base/win/scoped_hdc.h
index 890e34a..ef50e05 100644
--- a/base/win/scoped_hdc.h
+++ b/base/win/scoped_hdc.h
@@ -7,7 +7,6 @@
#include <windows.h>
-#include "base/debug/gdi_debug_util_win.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/win/scoped_handle.h"
diff --git a/build/gen.py b/build/gen.py
index 39257c9..2755480 100755
--- a/build/gen.py
+++ b/build/gen.py
@@ -231,11 +231,6 @@
'base/callback_helpers.cc',
'base/callback_internal.cc',
'base/command_line.cc',
- 'base/debug/alias.cc',
- 'base/debug/crash_logging.cc',
- 'base/debug/dump_without_crashing.cc',
- 'base/debug/stack_trace.cc',
- 'base/debug/task_annotator.cc',
'base/environment.cc',
'base/files/file.cc',
'base/files/file_enumerator.cc',
@@ -543,8 +538,6 @@
if is_posix:
static_libraries['base']['sources'].extend([
'base/base_paths_posix.cc',
- 'base/debug/debugger_posix.cc',
- 'base/debug/stack_trace_posix.cc',
'base/files/file_enumerator_posix.cc',
'base/files/file_descriptor_watcher_posix.cc',
'base/files/file_posix.cc',
@@ -664,11 +657,6 @@
static_libraries['base']['sources'].extend([
'base/base_paths_win.cc',
'base/cpu.cc',
- 'base/debug/close_handle_hook_win.cc',
- 'base/debug/debugger.cc',
- 'base/debug/debugger_win.cc',
- 'base/debug/profiler.cc',
- 'base/debug/stack_trace_win.cc',
'base/files/file_enumerator_win.cc',
'base/files/file_path_watcher_win.cc',
'base/files/file_util_win.cc',
@@ -686,8 +674,6 @@
'base/process/process_iterator_win.cc',
'base/process/process_metrics_win.cc',
'base/process/process_win.cc',
- 'base/profiler/native_stack_sampler_win.cc',
- 'base/profiler/win32_stack_frame_unwinder.cc',
'base/rand_util_win.cc',
'base/strings/sys_string_conversions_win.cc',
'base/synchronization/condition_variable_win.cc',