Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,194 @@
//===-- AddressRange.cpp ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/AddressRange.h"
#include "lldb/Core/Module.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/ConstString.h" // for ConstString
#include "lldb/Utility/FileSpec.h" // for FileSpec
#include "lldb/Utility/Stream.h"
#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS
#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH
#include <memory> // for shared_ptr
#include <inttypes.h> // for PRIx64
namespace lldb_private {
class SectionList;
}
using namespace lldb;
using namespace lldb_private;
AddressRange::AddressRange() : m_base_addr(), m_byte_size(0) {}
AddressRange::AddressRange(addr_t file_addr, addr_t byte_size,
const SectionList *section_list)
: m_base_addr(file_addr, section_list), m_byte_size(byte_size) {}
AddressRange::AddressRange(const lldb::SectionSP &section, addr_t offset,
addr_t byte_size)
: m_base_addr(section, offset), m_byte_size(byte_size) {}
AddressRange::AddressRange(const Address &so_addr, addr_t byte_size)
: m_base_addr(so_addr), m_byte_size(byte_size) {}
AddressRange::~AddressRange() {}
// bool
// AddressRange::Contains (const Address &addr) const
//{
// const addr_t byte_size = GetByteSize();
// if (byte_size)
// return addr.GetSection() == m_base_addr.GetSection() &&
// (addr.GetOffset() - m_base_addr.GetOffset()) < byte_size;
//}
//
// bool
// AddressRange::Contains (const Address *addr) const
//{
// if (addr)
// return Contains (*addr);
// return false;
//}
bool AddressRange::ContainsFileAddress(const Address &addr) const {
if (addr.GetSection() == m_base_addr.GetSection())
return (addr.GetOffset() - m_base_addr.GetOffset()) < GetByteSize();
addr_t file_base_addr = GetBaseAddress().GetFileAddress();
if (file_base_addr == LLDB_INVALID_ADDRESS)
return false;
addr_t file_addr = addr.GetFileAddress();
if (file_addr == LLDB_INVALID_ADDRESS)
return false;
if (file_base_addr <= file_addr)
return (file_addr - file_base_addr) < GetByteSize();
return false;
}
bool AddressRange::ContainsFileAddress(addr_t file_addr) const {
if (file_addr == LLDB_INVALID_ADDRESS)
return false;
addr_t file_base_addr = GetBaseAddress().GetFileAddress();
if (file_base_addr == LLDB_INVALID_ADDRESS)
return false;
if (file_base_addr <= file_addr)
return (file_addr - file_base_addr) < GetByteSize();
return false;
}
bool AddressRange::ContainsLoadAddress(const Address &addr,
Target *target) const {
if (addr.GetSection() == m_base_addr.GetSection())
return (addr.GetOffset() - m_base_addr.GetOffset()) < GetByteSize();
addr_t load_base_addr = GetBaseAddress().GetLoadAddress(target);
if (load_base_addr == LLDB_INVALID_ADDRESS)
return false;
addr_t load_addr = addr.GetLoadAddress(target);
if (load_addr == LLDB_INVALID_ADDRESS)
return false;
if (load_base_addr <= load_addr)
return (load_addr - load_base_addr) < GetByteSize();
return false;
}
bool AddressRange::ContainsLoadAddress(addr_t load_addr, Target *target) const {
if (load_addr == LLDB_INVALID_ADDRESS)
return false;
addr_t load_base_addr = GetBaseAddress().GetLoadAddress(target);
if (load_base_addr == LLDB_INVALID_ADDRESS)
return false;
if (load_base_addr <= load_addr)
return (load_addr - load_base_addr) < GetByteSize();
return false;
}
void AddressRange::Clear() {
m_base_addr.Clear();
m_byte_size = 0;
}
bool AddressRange::Dump(Stream *s, Target *target, Address::DumpStyle style,
Address::DumpStyle fallback_style) const {
addr_t vmaddr = LLDB_INVALID_ADDRESS;
int addr_size = sizeof(addr_t);
if (target)
addr_size = target->GetArchitecture().GetAddressByteSize();
bool show_module = false;
switch (style) {
default:
break;
case Address::DumpStyleSectionNameOffset:
case Address::DumpStyleSectionPointerOffset:
s->PutChar('[');
m_base_addr.Dump(s, target, style, fallback_style);
s->PutChar('-');
s->Address(m_base_addr.GetOffset() + GetByteSize(), addr_size);
s->PutChar(')');
return true;
break;
case Address::DumpStyleModuleWithFileAddress:
show_module = true;
LLVM_FALLTHROUGH;
case Address::DumpStyleFileAddress:
vmaddr = m_base_addr.GetFileAddress();
break;
case Address::DumpStyleLoadAddress:
vmaddr = m_base_addr.GetLoadAddress(target);
break;
}
if (vmaddr != LLDB_INVALID_ADDRESS) {
if (show_module) {
ModuleSP module_sp(GetBaseAddress().GetModule());
if (module_sp)
s->Printf("%s", module_sp->GetFileSpec().GetFilename().AsCString(
"<Unknown>"));
}
s->AddressRange(vmaddr, vmaddr + GetByteSize(), addr_size);
return true;
} else if (fallback_style != Address::DumpStyleInvalid) {
return Dump(s, target, fallback_style, Address::DumpStyleInvalid);
}
return false;
}
void AddressRange::DumpDebug(Stream *s) const {
s->Printf("%p: AddressRange section = %p, offset = 0x%16.16" PRIx64
", byte_size = 0x%16.16" PRIx64 "\n",
static_cast<const void *>(this),
static_cast<void *>(m_base_addr.GetSection().get()),
m_base_addr.GetOffset(), GetByteSize());
}
//
// bool
// lldb::operator== (const AddressRange& lhs, const AddressRange& rhs)
//{
// if (lhs.GetBaseAddress() == rhs.GetBaseAddress())
// return lhs.GetByteSize() == rhs.GetByteSize();
// return false;
//}

View File

@@ -0,0 +1,46 @@
//===-- AddressResolver.cpp -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/AddressResolver.h"
#include "lldb/Core/SearchFilter.h"
namespace lldb_private {
class ModuleList;
}
using namespace lldb_private;
//----------------------------------------------------------------------
// AddressResolver:
//----------------------------------------------------------------------
AddressResolver::AddressResolver() {}
AddressResolver::~AddressResolver() {}
void AddressResolver::ResolveAddressInModules(SearchFilter &filter,
ModuleList &modules) {
filter.SearchInModuleList(*this, modules);
}
void AddressResolver::ResolveAddress(SearchFilter &filter) {
filter.Search(*this);
}
std::vector<AddressRange> &AddressResolver::GetAddressRanges() {
return m_address_ranges;
}
size_t AddressResolver::GetNumberOfAddresses() {
return m_address_ranges.size();
}
AddressRange &AddressResolver::GetAddressRangeAtIndex(size_t idx) {
return m_address_ranges[idx];
}

View File

@@ -0,0 +1,88 @@
//===-- AddressResolverFileLine.cpp -----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/AddressResolverFileLine.h"
#include "lldb/Core/Address.h" // for Address
#include "lldb/Core/AddressRange.h" // for AddressRange
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LineEntry.h" // for LineEntry
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Utility/ConstString.h" // for ConstString
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Logging.h" // for GetLogIfAllCategoriesSet, LIB...
#include "lldb/Utility/Stream.h" // for Stream
#include "lldb/Utility/StreamString.h"
#include "lldb/lldb-enumerations.h" // for SymbolContextItem::eSymbolCon...
#include "lldb/lldb-types.h" // for addr_t
#include <inttypes.h> // for PRIx64
#include <vector> // for vector
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// AddressResolverFileLine:
//----------------------------------------------------------------------
AddressResolverFileLine::AddressResolverFileLine(const FileSpec &file_spec,
uint32_t line_no,
bool check_inlines)
: AddressResolver(), m_file_spec(file_spec), m_line_number(line_no),
m_inlines(check_inlines) {}
AddressResolverFileLine::~AddressResolverFileLine() {}
Searcher::CallbackReturn
AddressResolverFileLine::SearchCallback(SearchFilter &filter,
SymbolContext &context, Address *addr,
bool containing) {
SymbolContextList sc_list;
uint32_t sc_list_size;
CompileUnit *cu = context.comp_unit;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
sc_list_size =
cu->ResolveSymbolContext(m_file_spec, m_line_number, m_inlines, false,
eSymbolContextEverything, sc_list);
for (uint32_t i = 0; i < sc_list_size; i++) {
SymbolContext sc;
if (sc_list.GetContextAtIndex(i, sc)) {
Address line_start = sc.line_entry.range.GetBaseAddress();
addr_t byte_size = sc.line_entry.range.GetByteSize();
if (line_start.IsValid()) {
AddressRange new_range(line_start, byte_size);
m_address_ranges.push_back(new_range);
if (log) {
StreamString s;
// new_bp_loc->GetDescription (&s, lldb::eDescriptionLevelVerbose);
// log->Printf ("Added address: %s\n", s.GetData());
}
} else {
if (log)
log->Printf(
"error: Unable to resolve address at file address 0x%" PRIx64
" for %s:%d\n",
line_start.GetFileAddress(),
m_file_spec.GetFilename().AsCString("<Unknown>"), m_line_number);
}
}
}
return Searcher::eCallbackReturnContinue;
}
Searcher::Depth AddressResolverFileLine::GetDepth() {
return Searcher::eDepthCompUnit;
}
void AddressResolverFileLine::GetDescription(Stream *s) {
s->Printf("File and line address - file: \"%s\" line: %u",
m_file_spec.GetFilename().AsCString("<Unknown>"), m_line_number);
}

View File

@@ -0,0 +1,201 @@
//===-- AddressResolverName.cpp ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/AddressResolverName.h"
#include "lldb/Core/Address.h" // for Address, operator==
#include "lldb/Core/AddressRange.h" // for AddressRange
#include "lldb/Core/Module.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Logging.h" // for GetLogIfAllCategoriesSet, LIB...
#include "lldb/Utility/Stream.h" // for Stream
#include "lldb/lldb-enumerations.h" // for SymbolType::eSymbolTypeCode
#include "lldb/lldb-forward.h" // for ModuleSP
#include "lldb/lldb-types.h" // for addr_t
#include "llvm/ADT/StringRef.h" // for StringRef
#include <memory> // for shared_ptr
#include <string> // for string
#include <vector> // for vector
#include <stdint.h> // for uint32_t
using namespace lldb;
using namespace lldb_private;
AddressResolverName::AddressResolverName(const char *func_name,
AddressResolver::MatchType type)
: AddressResolver(), m_func_name(func_name), m_class_name(nullptr),
m_regex(), m_match_type(type) {
if (m_match_type == AddressResolver::Regexp) {
if (!m_regex.Compile(m_func_name.GetStringRef())) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Warning("function name regexp: \"%s\" did not compile.",
m_func_name.AsCString());
}
}
}
AddressResolverName::AddressResolverName(RegularExpression &func_regex)
: AddressResolver(), m_func_name(nullptr), m_class_name(nullptr),
m_regex(func_regex), m_match_type(AddressResolver::Regexp) {}
AddressResolverName::AddressResolverName(const char *class_name,
const char *method,
AddressResolver::MatchType type)
: AddressResolver(), m_func_name(method), m_class_name(class_name),
m_regex(), m_match_type(type) {}
AddressResolverName::~AddressResolverName() = default;
// FIXME: Right now we look at the module level, and call the module's
// "FindFunctions".
// Greg says he will add function tables, maybe at the CompileUnit level to
// accelerate function
// lookup. At that point, we should switch the depth to CompileUnit, and look
// in these tables.
Searcher::CallbackReturn
AddressResolverName::SearchCallback(SearchFilter &filter,
SymbolContext &context, Address *addr,
bool containing) {
SymbolContextList func_list;
SymbolContextList sym_list;
bool skip_prologue = true;
uint32_t i;
SymbolContext sc;
Address func_addr;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (m_class_name) {
if (log)
log->Warning("Class/method function specification not supported yet.\n");
return Searcher::eCallbackReturnStop;
}
const bool include_symbols = false;
const bool include_inlines = true;
const bool append = false;
switch (m_match_type) {
case AddressResolver::Exact:
if (context.module_sp) {
context.module_sp->FindSymbolsWithNameAndType(m_func_name,
eSymbolTypeCode, sym_list);
context.module_sp->FindFunctions(m_func_name, nullptr,
eFunctionNameTypeAuto, include_symbols,
include_inlines, append, func_list);
}
break;
case AddressResolver::Regexp:
if (context.module_sp) {
context.module_sp->FindSymbolsMatchingRegExAndType(
m_regex, eSymbolTypeCode, sym_list);
context.module_sp->FindFunctions(m_regex, include_symbols,
include_inlines, append, func_list);
}
break;
case AddressResolver::Glob:
if (log)
log->Warning("glob is not supported yet.");
break;
}
// Remove any duplicates between the function list and the symbol list
if (func_list.GetSize()) {
for (i = 0; i < func_list.GetSize(); i++) {
if (!func_list.GetContextAtIndex(i, sc))
continue;
if (sc.function == nullptr)
continue;
uint32_t j = 0;
while (j < sym_list.GetSize()) {
SymbolContext symbol_sc;
if (sym_list.GetContextAtIndex(j, symbol_sc)) {
if (symbol_sc.symbol && symbol_sc.symbol->ValueIsAddress()) {
if (sc.function->GetAddressRange().GetBaseAddress() ==
symbol_sc.symbol->GetAddressRef()) {
sym_list.RemoveContextAtIndex(j);
continue; // Don't increment j
}
}
}
j++;
}
}
for (i = 0; i < func_list.GetSize(); i++) {
if (func_list.GetContextAtIndex(i, sc)) {
if (sc.function) {
func_addr = sc.function->GetAddressRange().GetBaseAddress();
addr_t byte_size = sc.function->GetAddressRange().GetByteSize();
if (skip_prologue) {
const uint32_t prologue_byte_size =
sc.function->GetPrologueByteSize();
if (prologue_byte_size) {
func_addr.SetOffset(func_addr.GetOffset() + prologue_byte_size);
byte_size -= prologue_byte_size;
}
}
if (filter.AddressPasses(func_addr)) {
AddressRange new_range(func_addr, byte_size);
m_address_ranges.push_back(new_range);
}
}
}
}
}
for (i = 0; i < sym_list.GetSize(); i++) {
if (sym_list.GetContextAtIndex(i, sc)) {
if (sc.symbol && sc.symbol->ValueIsAddress()) {
func_addr = sc.symbol->GetAddressRef();
addr_t byte_size = sc.symbol->GetByteSize();
if (skip_prologue) {
const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
if (prologue_byte_size) {
func_addr.SetOffset(func_addr.GetOffset() + prologue_byte_size);
byte_size -= prologue_byte_size;
}
}
if (filter.AddressPasses(func_addr)) {
AddressRange new_range(func_addr, byte_size);
m_address_ranges.push_back(new_range);
}
}
}
}
return Searcher::eCallbackReturnContinue;
}
Searcher::Depth AddressResolverName::GetDepth() {
return Searcher::eDepthModule;
}
void AddressResolverName::GetDescription(Stream *s) {
s->PutCString("Address by function name: ");
if (m_match_type == AddressResolver::Regexp)
s->Printf("'%s' (regular expression)", m_regex.GetText().str().c_str());
else
s->Printf("'%s'", m_func_name.AsCString());
}

View File

@@ -0,0 +1,480 @@
//===-- Broadcaster.cpp -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/Listener.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Logging.h" // for GetLogIfAnyCategoriesSet, Get...
#include "lldb/Utility/Stream.h" // for Stream
#include "lldb/Utility/StreamString.h"
#include <algorithm> // for find_if
#include <memory> // for make_shared
#include <type_traits> // for move
#include <assert.h> // for assert
#include <stddef.h> // for size_t
using namespace lldb;
using namespace lldb_private;
Broadcaster::Broadcaster(BroadcasterManagerSP manager_sp, const char *name)
: m_broadcaster_sp(std::make_shared<BroadcasterImpl>(*this)),
m_manager_sp(manager_sp), m_broadcaster_name(name) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
if (log)
log->Printf("%p Broadcaster::Broadcaster(\"%s\")",
static_cast<void *>(this), GetBroadcasterName().AsCString());
}
Broadcaster::BroadcasterImpl::BroadcasterImpl(Broadcaster &broadcaster)
: m_broadcaster(broadcaster), m_listeners(), m_listeners_mutex(),
m_hijacking_listeners(), m_hijacking_masks() {}
Broadcaster::~Broadcaster() {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
if (log)
log->Printf("%p Broadcaster::~Broadcaster(\"%s\")",
static_cast<void *>(this), m_broadcaster_name.AsCString());
Clear();
}
void Broadcaster::CheckInWithManager() {
if (m_manager_sp) {
m_manager_sp->SignUpListenersForBroadcaster(*this);
}
}
llvm::SmallVector<std::pair<ListenerSP, uint32_t &>, 4>
Broadcaster::BroadcasterImpl::GetListeners() {
llvm::SmallVector<std::pair<ListenerSP, uint32_t &>, 4> listeners;
listeners.reserve(m_listeners.size());
for (auto it = m_listeners.begin(); it != m_listeners.end();) {
lldb::ListenerSP curr_listener_sp(it->first.lock());
if (curr_listener_sp && it->second) {
listeners.emplace_back(std::move(curr_listener_sp), it->second);
++it;
} else
it = m_listeners.erase(it);
}
return listeners;
}
void Broadcaster::BroadcasterImpl::Clear() {
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
// Make sure the listener forgets about this broadcaster. We do
// this in the broadcaster in case the broadcaster object initiates
// the removal.
for (auto &pair : GetListeners())
pair.first->BroadcasterWillDestruct(&m_broadcaster);
m_listeners.clear();
}
Broadcaster *Broadcaster::BroadcasterImpl::GetBroadcaster() {
return &m_broadcaster;
}
bool Broadcaster::BroadcasterImpl::GetEventNames(
Stream &s, uint32_t event_mask, bool prefix_with_broadcaster_name) const {
uint32_t num_names_added = 0;
if (event_mask && !m_event_names.empty()) {
event_names_map::const_iterator end = m_event_names.end();
for (uint32_t bit = 1u, mask = event_mask; mask != 0 && bit != 0;
bit <<= 1, mask >>= 1) {
if (mask & 1) {
event_names_map::const_iterator pos = m_event_names.find(bit);
if (pos != end) {
if (num_names_added > 0)
s.PutCString(", ");
if (prefix_with_broadcaster_name) {
s.PutCString(GetBroadcasterName());
s.PutChar('.');
}
s.PutCString(pos->second);
++num_names_added;
}
}
}
}
return num_names_added > 0;
}
void Broadcaster::AddInitialEventsToListener(
const lldb::ListenerSP &listener_sp, uint32_t requested_events) {}
uint32_t
Broadcaster::BroadcasterImpl::AddListener(const lldb::ListenerSP &listener_sp,
uint32_t event_mask) {
if (!listener_sp)
return 0;
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
// See if we already have this listener, and if so, update its mask
bool handled = false;
for (auto &pair : GetListeners()) {
if (pair.first == listener_sp) {
handled = true;
pair.second |= event_mask;
m_broadcaster.AddInitialEventsToListener(listener_sp, event_mask);
break;
}
}
if (!handled) {
// Grant a new listener the available event bits
m_listeners.push_back(
std::make_pair(lldb::ListenerWP(listener_sp), event_mask));
// Individual broadcasters decide whether they have outstanding data when a
// listener attaches, and insert it into the listener with this method.
m_broadcaster.AddInitialEventsToListener(listener_sp, event_mask);
}
// Return the event bits that were granted to the listener
return event_mask;
}
bool Broadcaster::BroadcasterImpl::EventTypeHasListeners(uint32_t event_type) {
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
if (!m_hijacking_listeners.empty() && event_type & m_hijacking_masks.back())
return true;
for (auto &pair : GetListeners()) {
if (pair.second & event_type)
return true;
}
return false;
}
bool Broadcaster::BroadcasterImpl::RemoveListener(
lldb_private::Listener *listener, uint32_t event_mask) {
if (!listener)
return false;
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
for (auto &pair : GetListeners()) {
if (pair.first.get() == listener) {
pair.second &= ~event_mask;
return true;
}
}
return false;
}
bool Broadcaster::BroadcasterImpl::RemoveListener(
const lldb::ListenerSP &listener_sp, uint32_t event_mask) {
return RemoveListener(listener_sp.get(), event_mask);
}
void Broadcaster::BroadcasterImpl::BroadcastEvent(EventSP &event_sp) {
return PrivateBroadcastEvent(event_sp, false);
}
void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique(EventSP &event_sp) {
return PrivateBroadcastEvent(event_sp, true);
}
void Broadcaster::BroadcasterImpl::PrivateBroadcastEvent(EventSP &event_sp,
bool unique) {
// Can't add a nullptr event...
if (!event_sp)
return;
// Update the broadcaster on this event
event_sp->SetBroadcaster(&m_broadcaster);
const uint32_t event_type = event_sp->GetType();
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
ListenerSP hijacking_listener_sp;
if (!m_hijacking_listeners.empty()) {
assert(!m_hijacking_masks.empty());
hijacking_listener_sp = m_hijacking_listeners.back();
if ((event_type & m_hijacking_masks.back()) == 0)
hijacking_listener_sp.reset();
}
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS));
if (log) {
StreamString event_description;
event_sp->Dump(&event_description);
log->Printf("%p Broadcaster(\"%s\")::BroadcastEvent (event_sp = {%s}, "
"unique =%i) hijack = %p",
static_cast<void *>(this), GetBroadcasterName(),
event_description.GetData(), unique,
static_cast<void *>(hijacking_listener_sp.get()));
}
if (hijacking_listener_sp) {
if (unique &&
hijacking_listener_sp->PeekAtNextEventForBroadcasterWithType(
&m_broadcaster, event_type))
return;
hijacking_listener_sp->AddEvent(event_sp);
} else {
for (auto &pair : GetListeners()) {
if (!(pair.second & event_type))
continue;
if (unique &&
pair.first->PeekAtNextEventForBroadcasterWithType(&m_broadcaster,
event_type))
continue;
pair.first->AddEvent(event_sp);
}
}
}
void Broadcaster::BroadcasterImpl::BroadcastEvent(uint32_t event_type,
EventData *event_data) {
auto event_sp = std::make_shared<Event>(event_type, event_data);
PrivateBroadcastEvent(event_sp, false);
}
void Broadcaster::BroadcasterImpl::BroadcastEvent(
uint32_t event_type, const lldb::EventDataSP &event_data_sp) {
auto event_sp = std::make_shared<Event>(event_type, event_data_sp);
PrivateBroadcastEvent(event_sp, false);
}
void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique(
uint32_t event_type, EventData *event_data) {
auto event_sp = std::make_shared<Event>(event_type, event_data);
PrivateBroadcastEvent(event_sp, true);
}
bool Broadcaster::BroadcasterImpl::HijackBroadcaster(
const lldb::ListenerSP &listener_sp, uint32_t event_mask) {
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS));
if (log)
log->Printf(
"%p Broadcaster(\"%s\")::HijackBroadcaster (listener(\"%s\")=%p)",
static_cast<void *>(this), GetBroadcasterName(),
listener_sp->m_name.c_str(), static_cast<void *>(listener_sp.get()));
m_hijacking_listeners.push_back(listener_sp);
m_hijacking_masks.push_back(event_mask);
return true;
}
bool Broadcaster::BroadcasterImpl::IsHijackedForEvent(uint32_t event_mask) {
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
if (!m_hijacking_listeners.empty())
return (event_mask & m_hijacking_masks.back()) != 0;
return false;
}
const char *Broadcaster::BroadcasterImpl::GetHijackingListenerName() {
if (m_hijacking_listeners.size()) {
return m_hijacking_listeners.back()->GetName();
} else {
return nullptr;
}
}
void Broadcaster::BroadcasterImpl::RestoreBroadcaster() {
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
if (!m_hijacking_listeners.empty()) {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS));
if (log) {
ListenerSP listener_sp = m_hijacking_listeners.back();
log->Printf("%p Broadcaster(\"%s\")::RestoreBroadcaster (about to pop "
"listener(\"%s\")=%p)",
static_cast<void *>(this), GetBroadcasterName(),
listener_sp->m_name.c_str(),
static_cast<void *>(listener_sp.get()));
}
m_hijacking_listeners.pop_back();
}
if (!m_hijacking_masks.empty())
m_hijacking_masks.pop_back();
}
ConstString &Broadcaster::GetBroadcasterClass() const {
static ConstString class_name("lldb.anonymous");
return class_name;
}
BroadcastEventSpec::BroadcastEventSpec(const BroadcastEventSpec &rhs) = default;
bool BroadcastEventSpec::operator<(const BroadcastEventSpec &rhs) const {
if (GetBroadcasterClass() == rhs.GetBroadcasterClass()) {
return GetEventBits() < rhs.GetEventBits();
} else {
return GetBroadcasterClass() < rhs.GetBroadcasterClass();
}
}
BroadcastEventSpec &BroadcastEventSpec::
operator=(const BroadcastEventSpec &rhs) = default;
BroadcasterManager::BroadcasterManager() : m_manager_mutex() {}
lldb::BroadcasterManagerSP BroadcasterManager::MakeBroadcasterManager() {
return lldb::BroadcasterManagerSP(new BroadcasterManager());
}
uint32_t BroadcasterManager::RegisterListenerForEvents(
const lldb::ListenerSP &listener_sp, BroadcastEventSpec event_spec) {
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end();
uint32_t available_bits = event_spec.GetEventBits();
while (iter != end_iter &&
(iter = find_if(iter, end_iter,
BroadcasterClassMatches(
event_spec.GetBroadcasterClass()))) != end_iter) {
available_bits &= ~((*iter).first.GetEventBits());
iter++;
}
if (available_bits != 0) {
m_event_map.insert(event_listener_key(
BroadcastEventSpec(event_spec.GetBroadcasterClass(), available_bits),
listener_sp));
m_listeners.insert(listener_sp);
}
return available_bits;
}
bool BroadcasterManager::UnregisterListenerForEvents(
const lldb::ListenerSP &listener_sp, BroadcastEventSpec event_spec) {
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
bool removed_some = false;
if (m_listeners.erase(listener_sp) == 0)
return false;
ListenerMatchesAndSharedBits predicate(event_spec, listener_sp);
std::vector<BroadcastEventSpec> to_be_readded;
uint32_t event_bits_to_remove = event_spec.GetEventBits();
// Go through the map and delete the exact matches, and build a list of
// matches that weren't exact to re-add:
while (true) {
collection::iterator iter, end_iter = m_event_map.end();
iter = find_if(m_event_map.begin(), end_iter, predicate);
if (iter == end_iter) {
break;
} else {
uint32_t iter_event_bits = (*iter).first.GetEventBits();
removed_some = true;
if (event_bits_to_remove != iter_event_bits) {
uint32_t new_event_bits = iter_event_bits & ~event_bits_to_remove;
to_be_readded.push_back(BroadcastEventSpec(
event_spec.GetBroadcasterClass(), new_event_bits));
}
m_event_map.erase(iter);
}
}
// Okay now add back the bits that weren't completely removed:
for (size_t i = 0; i < to_be_readded.size(); i++) {
m_event_map.insert(event_listener_key(to_be_readded[i], listener_sp));
}
return removed_some;
}
ListenerSP BroadcasterManager::GetListenerForEventSpec(
BroadcastEventSpec event_spec) const {
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
collection::const_iterator iter, end_iter = m_event_map.end();
iter = find_if(m_event_map.begin(), end_iter,
BroadcastEventSpecMatches(event_spec));
if (iter != end_iter)
return (*iter).second;
else
return nullptr;
}
void BroadcasterManager::RemoveListener(Listener *listener) {
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
ListenerMatchesPointer predicate(listener);
listener_collection::iterator iter = m_listeners.begin(),
end_iter = m_listeners.end();
std::find_if(iter, end_iter, predicate);
if (iter != end_iter)
m_listeners.erase(iter);
while (true) {
collection::iterator iter, end_iter = m_event_map.end();
iter = find_if(m_event_map.begin(), end_iter, predicate);
if (iter == end_iter)
break;
else
m_event_map.erase(iter);
}
}
void BroadcasterManager::RemoveListener(const lldb::ListenerSP &listener_sp) {
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
ListenerMatches predicate(listener_sp);
if (m_listeners.erase(listener_sp) == 0)
return;
while (true) {
collection::iterator iter, end_iter = m_event_map.end();
iter = find_if(m_event_map.begin(), end_iter, predicate);
if (iter == end_iter)
break;
else
m_event_map.erase(iter);
}
}
void BroadcasterManager::SignUpListenersForBroadcaster(
Broadcaster &broadcaster) {
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end();
while (iter != end_iter &&
(iter = find_if(iter, end_iter,
BroadcasterClassMatches(
broadcaster.GetBroadcasterClass()))) != end_iter) {
(*iter).second->StartListeningForEvents(&broadcaster,
(*iter).first.GetEventBits());
iter++;
}
}
void BroadcasterManager::Clear() {
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
listener_collection::iterator end_iter = m_listeners.end();
for (listener_collection::iterator iter = m_listeners.begin();
iter != end_iter; iter++)
(*iter)->BroadcasterManagerWillDestruct(this->shared_from_this());
m_listeners.clear();
m_event_map.clear();
}

View File

@@ -0,0 +1,83 @@
set(LLDB_CURSES_LIBS)
if (NOT LLDB_DISABLE_CURSES)
list(APPEND LLDB_CURSES_LIBS ${CURSES_LIBRARIES})
if(LLVM_ENABLE_TERMINFO AND HAVE_TERMINFO)
list(APPEND LLDB_CURSES_LIBS ${TERMINFO_LIBS})
endif()
endif()
add_lldb_library(lldbCore
Address.cpp
AddressRange.cpp
AddressResolver.cpp
AddressResolverFileLine.cpp
AddressResolverName.cpp
Broadcaster.cpp
Communication.cpp
Debugger.cpp
Disassembler.cpp
DumpDataExtractor.cpp
DynamicLoader.cpp
EmulateInstruction.cpp
Event.cpp
FileLineResolver.cpp
FileSpecList.cpp
FormatEntity.cpp
IOHandler.cpp
Listener.cpp
Mangled.cpp
Module.cpp
ModuleChild.cpp
ModuleList.cpp
Opcode.cpp
PluginManager.cpp
RegisterValue.cpp
Scalar.cpp
SearchFilter.cpp
Section.cpp
SourceManager.cpp
State.cpp
StreamAsynchronousIO.cpp
StreamFile.cpp
UserSettingsController.cpp
Value.cpp
ValueObject.cpp
ValueObjectCast.cpp
ValueObjectChild.cpp
ValueObjectConstResult.cpp
ValueObjectConstResultCast.cpp
ValueObjectConstResultChild.cpp
ValueObjectConstResultImpl.cpp
ValueObjectDynamicValue.cpp
ValueObjectList.cpp
ValueObjectMemory.cpp
ValueObjectRegister.cpp
ValueObjectSyntheticFilter.cpp
ValueObjectVariable.cpp
LINK_LIBS
clangAST
lldbBreakpoint
lldbDataFormatters
lldbExpression
lldbHost
lldbInterpreter
lldbSymbol
lldbTarget
lldbUtility
lldbPluginProcessUtility
lldbPluginCPlusPlusLanguage
lldbPluginObjCLanguage
lldbPluginObjectFileJIT
${LLDB_CURSES_LIBS}
LINK_COMPONENTS
BinaryFormat
Support
Demangle
)
# Needed to properly resolve references in a debug build.
# TODO: Remove once we have better layering
set_target_properties(lldbCore PROPERTIES LINK_INTERFACE_MULTIPLICITY 4)

View File

@@ -0,0 +1,423 @@
//===-- Communication.cpp ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/Communication.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/Listener.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Utility/Connection.h"
#include "lldb/Utility/ConstString.h" // for ConstString
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Logging.h" // for LogIfAnyCategoriesSet, LIBLLDB...
#include "lldb/Utility/Status.h" // for Status
#include "llvm/ADT/None.h" // for None
#include "llvm/ADT/Optional.h" // for Optional
#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH
#include <algorithm> // for min
#include <chrono> // for duration, seconds
#include <cstring>
#include <memory> // for shared_ptr
#include <errno.h> // for EIO
#include <inttypes.h> // for PRIu64
#include <stdio.h> // for snprintf
using namespace lldb;
using namespace lldb_private;
ConstString &Communication::GetStaticBroadcasterClass() {
static ConstString class_name("lldb.communication");
return class_name;
}
Communication::Communication(const char *name)
: Broadcaster(nullptr, name), m_connection_sp(),
m_read_thread_enabled(false), m_read_thread_did_exit(false), m_bytes(),
m_bytes_mutex(), m_write_mutex(), m_synchronize_mutex(),
m_callback(nullptr), m_callback_baton(nullptr), m_close_on_eof(true)
{
lldb_private::LogIfAnyCategoriesSet(
LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_COMMUNICATION,
"%p Communication::Communication (name = %s)", this, name);
SetEventName(eBroadcastBitDisconnected, "disconnected");
SetEventName(eBroadcastBitReadThreadGotBytes, "got bytes");
SetEventName(eBroadcastBitReadThreadDidExit, "read thread did exit");
SetEventName(eBroadcastBitReadThreadShouldExit, "read thread should exit");
SetEventName(eBroadcastBitPacketAvailable, "packet available");
SetEventName(eBroadcastBitNoMorePendingInput, "no more pending input");
CheckInWithManager();
}
Communication::~Communication() {
lldb_private::LogIfAnyCategoriesSet(
LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_COMMUNICATION,
"%p Communication::~Communication (name = %s)", this,
GetBroadcasterName().AsCString());
Clear();
}
void Communication::Clear() {
SetReadThreadBytesReceivedCallback(nullptr, nullptr);
Disconnect(nullptr);
StopReadThread(nullptr);
}
ConnectionStatus Communication::Connect(const char *url, Status *error_ptr) {
Clear();
lldb_private::LogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION,
"%p Communication::Connect (url = %s)",
this, url);
lldb::ConnectionSP connection_sp(m_connection_sp);
if (connection_sp)
return connection_sp->Connect(url, error_ptr);
if (error_ptr)
error_ptr->SetErrorString("Invalid connection.");
return eConnectionStatusNoConnection;
}
ConnectionStatus Communication::Disconnect(Status *error_ptr) {
lldb_private::LogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION,
"%p Communication::Disconnect ()", this);
lldb::ConnectionSP connection_sp(m_connection_sp);
if (connection_sp) {
ConnectionStatus status = connection_sp->Disconnect(error_ptr);
// We currently don't protect connection_sp with any mutex for
// multi-threaded environments. So lets not nuke our connection class
// without putting some multi-threaded protections in. We also probably
// don't want to pay for the overhead it might cause if every time we
// access the connection we have to take a lock.
//
// This unique pointer will cleanup after itself when this object goes away,
// so there is no need to currently have it destroy itself immediately
// upon disconnnect.
// connection_sp.reset();
return status;
}
return eConnectionStatusNoConnection;
}
bool Communication::IsConnected() const {
lldb::ConnectionSP connection_sp(m_connection_sp);
return (connection_sp ? connection_sp->IsConnected() : false);
}
bool Communication::HasConnection() const {
return m_connection_sp.get() != nullptr;
}
size_t Communication::Read(void *dst, size_t dst_len,
const Timeout<std::micro> &timeout,
ConnectionStatus &status, Status *error_ptr) {
Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION);
LLDB_LOG(
log,
"this = {0}, dst = {1}, dst_len = {2}, timeout = {3}, connection = {4}",
this, dst, dst_len, timeout, m_connection_sp.get());
if (m_read_thread_enabled) {
// We have a dedicated read thread that is getting data for us
size_t cached_bytes = GetCachedBytes(dst, dst_len);
if (cached_bytes > 0 || (timeout && timeout->count() == 0)) {
status = eConnectionStatusSuccess;
return cached_bytes;
}
if (!m_connection_sp) {
if (error_ptr)
error_ptr->SetErrorString("Invalid connection.");
status = eConnectionStatusNoConnection;
return 0;
}
ListenerSP listener_sp(Listener::MakeListener("Communication::Read"));
listener_sp->StartListeningForEvents(
this, eBroadcastBitReadThreadGotBytes | eBroadcastBitReadThreadDidExit);
EventSP event_sp;
while (listener_sp->GetEvent(event_sp, timeout)) {
const uint32_t event_type = event_sp->GetType();
if (event_type & eBroadcastBitReadThreadGotBytes) {
return GetCachedBytes(dst, dst_len);
}
if (event_type & eBroadcastBitReadThreadDidExit) {
if (GetCloseOnEOF())
Disconnect(nullptr);
break;
}
}
return 0;
}
// We aren't using a read thread, just read the data synchronously in this
// thread.
return ReadFromConnection(dst, dst_len, timeout, status, error_ptr);
}
size_t Communication::Write(const void *src, size_t src_len,
ConnectionStatus &status, Status *error_ptr) {
lldb::ConnectionSP connection_sp(m_connection_sp);
std::lock_guard<std::mutex> guard(m_write_mutex);
lldb_private::LogIfAnyCategoriesSet(
LIBLLDB_LOG_COMMUNICATION,
"%p Communication::Write (src = %p, src_len = %" PRIu64
") connection = %p",
this, src, (uint64_t)src_len, connection_sp.get());
if (connection_sp)
return connection_sp->Write(src, src_len, status, error_ptr);
if (error_ptr)
error_ptr->SetErrorString("Invalid connection.");
status = eConnectionStatusNoConnection;
return 0;
}
bool Communication::StartReadThread(Status *error_ptr) {
if (error_ptr)
error_ptr->Clear();
if (m_read_thread.IsJoinable())
return true;
lldb_private::LogIfAnyCategoriesSet(
LIBLLDB_LOG_COMMUNICATION, "%p Communication::StartReadThread ()", this);
char thread_name[1024];
snprintf(thread_name, sizeof(thread_name), "<lldb.comm.%s>",
GetBroadcasterName().AsCString());
m_read_thread_enabled = true;
m_read_thread_did_exit = false;
m_read_thread = ThreadLauncher::LaunchThread(
thread_name, Communication::ReadThread, this, error_ptr);
if (!m_read_thread.IsJoinable())
m_read_thread_enabled = false;
return m_read_thread_enabled;
}
bool Communication::StopReadThread(Status *error_ptr) {
if (!m_read_thread.IsJoinable())
return true;
lldb_private::LogIfAnyCategoriesSet(
LIBLLDB_LOG_COMMUNICATION, "%p Communication::StopReadThread ()", this);
m_read_thread_enabled = false;
BroadcastEvent(eBroadcastBitReadThreadShouldExit, nullptr);
// error = m_read_thread.Cancel();
Status error = m_read_thread.Join(nullptr);
return error.Success();
}
bool Communication::JoinReadThread(Status *error_ptr) {
if (!m_read_thread.IsJoinable())
return true;
Status error = m_read_thread.Join(nullptr);
return error.Success();
}
size_t Communication::GetCachedBytes(void *dst, size_t dst_len) {
std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex);
if (!m_bytes.empty()) {
// If DST is nullptr and we have a thread, then return the number
// of bytes that are available so the caller can call again
if (dst == nullptr)
return m_bytes.size();
const size_t len = std::min<size_t>(dst_len, m_bytes.size());
::memcpy(dst, m_bytes.c_str(), len);
m_bytes.erase(m_bytes.begin(), m_bytes.begin() + len);
return len;
}
return 0;
}
void Communication::AppendBytesToCache(const uint8_t *bytes, size_t len,
bool broadcast,
ConnectionStatus status) {
lldb_private::LogIfAnyCategoriesSet(
LIBLLDB_LOG_COMMUNICATION,
"%p Communication::AppendBytesToCache (src = %p, src_len = %" PRIu64
", broadcast = %i)",
this, bytes, (uint64_t)len, broadcast);
if ((bytes == nullptr || len == 0) &&
(status != lldb::eConnectionStatusEndOfFile))
return;
if (m_callback) {
// If the user registered a callback, then call it and do not broadcast
m_callback(m_callback_baton, bytes, len);
} else if (bytes != nullptr && len > 0) {
std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex);
m_bytes.append((const char *)bytes, len);
if (broadcast)
BroadcastEventIfUnique(eBroadcastBitReadThreadGotBytes);
}
}
size_t Communication::ReadFromConnection(void *dst, size_t dst_len,
const Timeout<std::micro> &timeout,
ConnectionStatus &status,
Status *error_ptr) {
lldb::ConnectionSP connection_sp(m_connection_sp);
if (connection_sp)
return connection_sp->Read(dst, dst_len, timeout, status, error_ptr);
if (error_ptr)
error_ptr->SetErrorString("Invalid connection.");
status = eConnectionStatusNoConnection;
return 0;
}
bool Communication::ReadThreadIsRunning() { return m_read_thread_enabled; }
lldb::thread_result_t Communication::ReadThread(lldb::thread_arg_t p) {
Communication *comm = (Communication *)p;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION));
if (log)
log->Printf("%p Communication::ReadThread () thread starting...", p);
uint8_t buf[1024];
Status error;
ConnectionStatus status = eConnectionStatusSuccess;
bool done = false;
while (!done && comm->m_read_thread_enabled) {
size_t bytes_read = comm->ReadFromConnection(
buf, sizeof(buf), std::chrono::seconds(5), status, &error);
if (bytes_read > 0)
comm->AppendBytesToCache(buf, bytes_read, true, status);
else if ((bytes_read == 0) && status == eConnectionStatusEndOfFile) {
if (comm->GetCloseOnEOF())
comm->Disconnect();
comm->AppendBytesToCache(buf, bytes_read, true, status);
}
switch (status) {
case eConnectionStatusSuccess:
break;
case eConnectionStatusEndOfFile:
done = true;
break;
case eConnectionStatusError: // Check GetError() for details
if (error.GetType() == eErrorTypePOSIX && error.GetError() == EIO) {
// EIO on a pipe is usually caused by remote shutdown
comm->Disconnect();
done = true;
}
if (error.Fail())
LLDB_LOG(log, "error: {0}, status = {1}", error,
Communication::ConnectionStatusAsCString(status));
break;
case eConnectionStatusInterrupted: // Synchronization signal from
// SynchronizeWithReadThread()
// The connection returns eConnectionStatusInterrupted only when there is
// no
// input pending to be read, so we can signal that.
comm->BroadcastEvent(eBroadcastBitNoMorePendingInput);
break;
case eConnectionStatusNoConnection: // No connection
case eConnectionStatusLostConnection: // Lost connection while connected to
// a valid connection
done = true;
LLVM_FALLTHROUGH;
case eConnectionStatusTimedOut: // Request timed out
if (error.Fail())
LLDB_LOG(log, "error: {0}, status = {1}", error,
Communication::ConnectionStatusAsCString(status));
break;
}
}
log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION);
if (log)
log->Printf("%p Communication::ReadThread () thread exiting...", p);
comm->m_read_thread_did_exit = true;
// Let clients know that this thread is exiting
comm->BroadcastEvent(eBroadcastBitNoMorePendingInput);
comm->BroadcastEvent(eBroadcastBitReadThreadDidExit);
return NULL;
}
void Communication::SetReadThreadBytesReceivedCallback(
ReadThreadBytesReceived callback, void *callback_baton) {
m_callback = callback;
m_callback_baton = callback_baton;
}
void Communication::SynchronizeWithReadThread() {
// Only one thread can do the synchronization dance at a time.
std::lock_guard<std::mutex> guard(m_synchronize_mutex);
// First start listening for the synchronization event.
ListenerSP listener_sp(
Listener::MakeListener("Communication::SyncronizeWithReadThread"));
listener_sp->StartListeningForEvents(this, eBroadcastBitNoMorePendingInput);
// If the thread is not running, there is no point in synchronizing.
if (!m_read_thread_enabled || m_read_thread_did_exit)
return;
// Notify the read thread.
m_connection_sp->InterruptRead();
// Wait for the synchronization event.
EventSP event_sp;
listener_sp->GetEvent(event_sp, llvm::None);
}
void Communication::SetConnection(Connection *connection) {
Disconnect(nullptr);
StopReadThread(nullptr);
m_connection_sp.reset(connection);
}
const char *
Communication::ConnectionStatusAsCString(lldb::ConnectionStatus status) {
switch (status) {
case eConnectionStatusSuccess:
return "success";
case eConnectionStatusError:
return "error";
case eConnectionStatusTimedOut:
return "timed out";
case eConnectionStatusNoConnection:
return "no connection";
case eConnectionStatusLostConnection:
return "lost connection";
case eConnectionStatusEndOfFile:
return "end of file";
case eConnectionStatusInterrupted:
return "interrupted";
}
static char unknown_state_string[64];
snprintf(unknown_state_string, sizeof(unknown_state_string),
"ConnectionStatus = %i", status);
return unknown_state_string;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,249 @@
//===-- DynamicLoader.cpp ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h" // for ModuleList
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Symbol/ObjectFile.h" // for ObjectFile
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/ConstString.h" // for ConstString
#include "lldb/lldb-private-interfaces.h" // for DynamicLoaderCreateInstance
#include "llvm/ADT/StringRef.h" // for StringRef
#include <memory> // for shared_ptr, unique_ptr
#include <assert.h> // for assert
using namespace lldb;
using namespace lldb_private;
DynamicLoader *DynamicLoader::FindPlugin(Process *process,
const char *plugin_name) {
DynamicLoaderCreateInstance create_callback = nullptr;
if (plugin_name) {
ConstString const_plugin_name(plugin_name);
create_callback =
PluginManager::GetDynamicLoaderCreateCallbackForPluginName(
const_plugin_name);
if (create_callback) {
std::unique_ptr<DynamicLoader> instance_ap(
create_callback(process, true));
if (instance_ap)
return instance_ap.release();
}
} else {
for (uint32_t idx = 0;
(create_callback =
PluginManager::GetDynamicLoaderCreateCallbackAtIndex(idx)) !=
nullptr;
++idx) {
std::unique_ptr<DynamicLoader> instance_ap(
create_callback(process, false));
if (instance_ap)
return instance_ap.release();
}
}
return nullptr;
}
DynamicLoader::DynamicLoader(Process *process) : m_process(process) {}
DynamicLoader::~DynamicLoader() = default;
//----------------------------------------------------------------------
// Accessosors to the global setting as to whether to stop at image
// (shared library) loading/unloading.
//----------------------------------------------------------------------
bool DynamicLoader::GetStopWhenImagesChange() const {
return m_process->GetStopOnSharedLibraryEvents();
}
void DynamicLoader::SetStopWhenImagesChange(bool stop) {
m_process->SetStopOnSharedLibraryEvents(stop);
}
ModuleSP DynamicLoader::GetTargetExecutable() {
Target &target = m_process->GetTarget();
ModuleSP executable = target.GetExecutableModule();
if (executable) {
if (executable->GetFileSpec().Exists()) {
ModuleSpec module_spec(executable->GetFileSpec(),
executable->GetArchitecture());
auto module_sp = std::make_shared<Module>(module_spec);
// Check if the executable has changed and set it to the target executable
// if they differ.
if (module_sp && module_sp->GetUUID().IsValid() &&
executable->GetUUID().IsValid()) {
if (module_sp->GetUUID() != executable->GetUUID())
executable.reset();
} else if (executable->FileHasChanged()) {
executable.reset();
}
if (!executable) {
executable = target.GetSharedModule(module_spec);
if (executable.get() != target.GetExecutableModulePointer()) {
// Don't load dependent images since we are in dyld where we will know
// and find out about all images that are loaded
const bool get_dependent_images = false;
target.SetExecutableModule(executable, get_dependent_images);
}
}
}
}
return executable;
}
void DynamicLoader::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr,
addr_t base_addr,
bool base_addr_is_offset) {
UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset);
}
void DynamicLoader::UpdateLoadedSectionsCommon(ModuleSP module,
addr_t base_addr,
bool base_addr_is_offset) {
bool changed;
module->SetLoadAddress(m_process->GetTarget(), base_addr, base_addr_is_offset,
changed);
}
void DynamicLoader::UnloadSections(const ModuleSP module) {
UnloadSectionsCommon(module);
}
void DynamicLoader::UnloadSectionsCommon(const ModuleSP module) {
Target &target = m_process->GetTarget();
const SectionList *sections = GetSectionListFromModule(module);
assert(sections && "SectionList missing from unloaded module.");
const size_t num_sections = sections->GetSize();
for (size_t i = 0; i < num_sections; ++i) {
SectionSP section_sp(sections->GetSectionAtIndex(i));
target.SetSectionUnloaded(section_sp);
}
}
const SectionList *
DynamicLoader::GetSectionListFromModule(const ModuleSP module) const {
SectionList *sections = nullptr;
if (module) {
ObjectFile *obj_file = module->GetObjectFile();
if (obj_file != nullptr) {
sections = obj_file->GetSectionList();
}
}
return sections;
}
ModuleSP DynamicLoader::LoadModuleAtAddress(const FileSpec &file,
addr_t link_map_addr,
addr_t base_addr,
bool base_addr_is_offset) {
Target &target = m_process->GetTarget();
ModuleList &modules = target.GetImages();
ModuleSpec module_spec(file, target.GetArchitecture());
ModuleSP module_sp;
if ((module_sp = modules.FindFirstModule(module_spec))) {
UpdateLoadedSections(module_sp, link_map_addr, base_addr,
base_addr_is_offset);
return module_sp;
}
if ((module_sp = target.GetSharedModule(module_spec))) {
UpdateLoadedSections(module_sp, link_map_addr, base_addr,
base_addr_is_offset);
return module_sp;
}
bool check_alternative_file_name = true;
if (base_addr_is_offset) {
// Try to fetch the load address of the file from the process as we need
// absolute load
// address to read the file out of the memory instead of a load bias.
bool is_loaded = false;
lldb::addr_t load_addr;
Status error = m_process->GetFileLoadAddress(file, is_loaded, load_addr);
if (error.Success() && is_loaded) {
check_alternative_file_name = false;
base_addr = load_addr;
}
}
// We failed to find the module based on its name. Lets try to check if we can
// find a
// different name based on the memory region info.
if (check_alternative_file_name) {
MemoryRegionInfo memory_info;
Status error = m_process->GetMemoryRegionInfo(base_addr, memory_info);
if (error.Success() && memory_info.GetMapped() &&
memory_info.GetRange().GetRangeBase() == base_addr &&
!(memory_info.GetName().IsEmpty())) {
ModuleSpec new_module_spec(
FileSpec(memory_info.GetName().AsCString(), false),
target.GetArchitecture());
if ((module_sp = modules.FindFirstModule(new_module_spec))) {
UpdateLoadedSections(module_sp, link_map_addr, base_addr, false);
return module_sp;
}
if ((module_sp = target.GetSharedModule(new_module_spec))) {
UpdateLoadedSections(module_sp, link_map_addr, base_addr, false);
return module_sp;
}
}
}
if ((module_sp = m_process->ReadModuleFromMemory(file, base_addr))) {
UpdateLoadedSections(module_sp, link_map_addr, base_addr, false);
target.GetImages().AppendIfNeeded(module_sp);
}
return module_sp;
}
int64_t DynamicLoader::ReadUnsignedIntWithSizeInBytes(addr_t addr,
int size_in_bytes) {
Status error;
uint64_t value =
m_process->ReadUnsignedIntegerFromMemory(addr, size_in_bytes, 0, error);
if (error.Fail())
return -1;
else
return (int64_t)value;
}
addr_t DynamicLoader::ReadPointer(addr_t addr) {
Status error;
addr_t value = m_process->ReadPointerFromMemory(addr, error);
if (error.Fail())
return LLDB_INVALID_ADDRESS;
else
return value;
}
void DynamicLoader::LoadOperatingSystemPlugin(bool flush)
{
if (m_process)
m_process->LoadOperatingSystemPlugin(flush);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,303 @@
//===-- Event.cpp -----------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/Event.h"
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/Endian.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamString.h" // for StreamString
#include "lldb/lldb-enumerations.h" // for Format::eFormatBytes
#include <algorithm>
#include <ctype.h> // for isprint
using namespace lldb;
using namespace lldb_private;
#pragma mark -
#pragma mark Event
//------------------------------------------------------------------
// Event functions
//------------------------------------------------------------------
Event::Event(Broadcaster *broadcaster, uint32_t event_type, EventData *data)
: m_broadcaster_wp(broadcaster->GetBroadcasterImpl()), m_type(event_type),
m_data_sp(data) {}
Event::Event(Broadcaster *broadcaster, uint32_t event_type,
const EventDataSP &event_data_sp)
: m_broadcaster_wp(broadcaster->GetBroadcasterImpl()), m_type(event_type),
m_data_sp(event_data_sp) {}
Event::Event(uint32_t event_type, EventData *data)
: m_broadcaster_wp(), m_type(event_type), m_data_sp(data) {}
Event::Event(uint32_t event_type, const EventDataSP &event_data_sp)
: m_broadcaster_wp(), m_type(event_type), m_data_sp(event_data_sp) {}
Event::~Event() = default;
void Event::Dump(Stream *s) const {
Broadcaster *broadcaster;
Broadcaster::BroadcasterImplSP broadcaster_impl_sp(m_broadcaster_wp.lock());
if (broadcaster_impl_sp)
broadcaster = broadcaster_impl_sp->GetBroadcaster();
else
broadcaster = nullptr;
if (broadcaster) {
StreamString event_name;
if (broadcaster->GetEventNames(event_name, m_type, false))
s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x (%s), data = ",
static_cast<const void *>(this),
static_cast<void *>(broadcaster),
broadcaster->GetBroadcasterName().GetCString(), m_type,
event_name.GetData());
else
s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x, data = ",
static_cast<const void *>(this),
static_cast<void *>(broadcaster),
broadcaster->GetBroadcasterName().GetCString(), m_type);
} else
s->Printf("%p Event: broadcaster = NULL, type = 0x%8.8x, data = ",
static_cast<const void *>(this), m_type);
if (m_data_sp) {
s->PutChar('{');
m_data_sp->Dump(s);
s->PutChar('}');
} else
s->Printf("<NULL>");
}
void Event::DoOnRemoval() {
if (m_data_sp)
m_data_sp->DoOnRemoval(this);
}
#pragma mark -
#pragma mark EventData
//------------------------------------------------------------------
// EventData functions
//------------------------------------------------------------------
EventData::EventData() = default;
EventData::~EventData() = default;
void EventData::Dump(Stream *s) const { s->PutCString("Generic Event Data"); }
#pragma mark -
#pragma mark EventDataBytes
//------------------------------------------------------------------
// EventDataBytes functions
//------------------------------------------------------------------
EventDataBytes::EventDataBytes() : m_bytes() {}
EventDataBytes::EventDataBytes(const char *cstr) : m_bytes() {
SetBytesFromCString(cstr);
}
EventDataBytes::EventDataBytes(llvm::StringRef str) : m_bytes() {
SetBytes(str.data(), str.size());
}
EventDataBytes::EventDataBytes(const void *src, size_t src_len) : m_bytes() {
SetBytes(src, src_len);
}
EventDataBytes::~EventDataBytes() = default;
const ConstString &EventDataBytes::GetFlavorString() {
static ConstString g_flavor("EventDataBytes");
return g_flavor;
}
const ConstString &EventDataBytes::GetFlavor() const {
return EventDataBytes::GetFlavorString();
}
void EventDataBytes::Dump(Stream *s) const {
size_t num_printable_chars =
std::count_if(m_bytes.begin(), m_bytes.end(), isprint);
if (num_printable_chars == m_bytes.size()) {
s->Printf("\"%s\"", m_bytes.c_str());
} else if (!m_bytes.empty()) {
DataExtractor data;
data.SetData(m_bytes.data(), m_bytes.size(), endian::InlHostByteOrder());
DumpDataExtractor(data, s, 0, eFormatBytes, 1, m_bytes.size(), 32,
LLDB_INVALID_ADDRESS, 0, 0);
}
}
const void *EventDataBytes::GetBytes() const {
return (m_bytes.empty() ? nullptr : m_bytes.data());
}
size_t EventDataBytes::GetByteSize() const { return m_bytes.size(); }
void EventDataBytes::SetBytes(const void *src, size_t src_len) {
if (src != nullptr && src_len > 0)
m_bytes.assign((const char *)src, src_len);
else
m_bytes.clear();
}
void EventDataBytes::SetBytesFromCString(const char *cstr) {
if (cstr != nullptr && cstr[0])
m_bytes.assign(cstr);
else
m_bytes.clear();
}
const void *EventDataBytes::GetBytesFromEvent(const Event *event_ptr) {
const EventDataBytes *e = GetEventDataFromEvent(event_ptr);
if (e != nullptr)
return e->GetBytes();
return nullptr;
}
size_t EventDataBytes::GetByteSizeFromEvent(const Event *event_ptr) {
const EventDataBytes *e = GetEventDataFromEvent(event_ptr);
if (e != nullptr)
return e->GetByteSize();
return 0;
}
const EventDataBytes *
EventDataBytes::GetEventDataFromEvent(const Event *event_ptr) {
if (event_ptr != nullptr) {
const EventData *event_data = event_ptr->GetData();
if (event_data &&
event_data->GetFlavor() == EventDataBytes::GetFlavorString())
return static_cast<const EventDataBytes *>(event_data);
}
return nullptr;
}
void EventDataBytes::SwapBytes(std::string &new_bytes) {
m_bytes.swap(new_bytes);
}
#pragma mark -
#pragma mark EventStructuredData
//------------------------------------------------------------------
// EventDataStructuredData definitions
//------------------------------------------------------------------
EventDataStructuredData::EventDataStructuredData()
: EventData(), m_process_sp(), m_object_sp(), m_plugin_sp() {}
EventDataStructuredData::EventDataStructuredData(
const ProcessSP &process_sp, const StructuredData::ObjectSP &object_sp,
const lldb::StructuredDataPluginSP &plugin_sp)
: EventData(), m_process_sp(process_sp), m_object_sp(object_sp),
m_plugin_sp(plugin_sp) {}
EventDataStructuredData::~EventDataStructuredData() {}
//------------------------------------------------------------------
// EventDataStructuredData member functions
//------------------------------------------------------------------
const ConstString &EventDataStructuredData::GetFlavor() const {
return EventDataStructuredData::GetFlavorString();
}
void EventDataStructuredData::Dump(Stream *s) const {
if (!s)
return;
if (m_object_sp)
m_object_sp->Dump(*s);
}
const ProcessSP &EventDataStructuredData::GetProcess() const {
return m_process_sp;
}
const StructuredData::ObjectSP &EventDataStructuredData::GetObject() const {
return m_object_sp;
}
const lldb::StructuredDataPluginSP &
EventDataStructuredData::GetStructuredDataPlugin() const {
return m_plugin_sp;
}
void EventDataStructuredData::SetProcess(const ProcessSP &process_sp) {
m_process_sp = process_sp;
}
void EventDataStructuredData::SetObject(
const StructuredData::ObjectSP &object_sp) {
m_object_sp = object_sp;
}
void EventDataStructuredData::SetStructuredDataPlugin(
const lldb::StructuredDataPluginSP &plugin_sp) {
m_plugin_sp = plugin_sp;
}
//------------------------------------------------------------------
// EventDataStructuredData static functions
//------------------------------------------------------------------
const EventDataStructuredData *
EventDataStructuredData::GetEventDataFromEvent(const Event *event_ptr) {
if (event_ptr == nullptr)
return nullptr;
const EventData *event_data = event_ptr->GetData();
if (!event_data ||
event_data->GetFlavor() != EventDataStructuredData::GetFlavorString())
return nullptr;
return static_cast<const EventDataStructuredData *>(event_data);
}
ProcessSP EventDataStructuredData::GetProcessFromEvent(const Event *event_ptr) {
auto event_data = EventDataStructuredData::GetEventDataFromEvent(event_ptr);
if (event_data)
return event_data->GetProcess();
else
return ProcessSP();
}
StructuredData::ObjectSP
EventDataStructuredData::GetObjectFromEvent(const Event *event_ptr) {
auto event_data = EventDataStructuredData::GetEventDataFromEvent(event_ptr);
if (event_data)
return event_data->GetObject();
else
return StructuredData::ObjectSP();
}
lldb::StructuredDataPluginSP
EventDataStructuredData::GetPluginFromEvent(const Event *event_ptr) {
auto event_data = EventDataStructuredData::GetEventDataFromEvent(event_ptr);
if (event_data)
return event_data->GetStructuredDataPlugin();
else
return StructuredDataPluginSP();
}
const ConstString &EventDataStructuredData::GetFlavorString() {
static ConstString s_flavor("EventDataStructuredData");
return s_flavor;
}

View File

@@ -0,0 +1,93 @@
//===-- FileLineResolver.cpp ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/FileLineResolver.h"
// Project includes
#include "lldb/Core/FileSpecList.h" // for FileSpecList
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Utility/ConstString.h" // for ConstString
#include "lldb/Utility/Stream.h" // for Stream
#include <string> // for string
namespace lldb_private {
class Address;
}
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// FileLineResolver:
//----------------------------------------------------------------------
FileLineResolver::FileLineResolver(const FileSpec &file_spec, uint32_t line_no,
bool check_inlines)
: Searcher(), m_file_spec(file_spec), m_line_number(line_no),
m_inlines(check_inlines) {}
FileLineResolver::~FileLineResolver() {}
Searcher::CallbackReturn
FileLineResolver::SearchCallback(SearchFilter &filter, SymbolContext &context,
Address *addr, bool containing) {
CompileUnit *cu = context.comp_unit;
if (m_inlines ||
m_file_spec.Compare(*cu, m_file_spec, (bool)m_file_spec.GetDirectory())) {
uint32_t start_file_idx = 0;
uint32_t file_idx =
cu->GetSupportFiles().FindFileIndex(start_file_idx, m_file_spec, false);
if (file_idx != UINT32_MAX) {
LineTable *line_table = cu->GetLineTable();
if (line_table) {
if (m_line_number == 0) {
// Match all lines in a file...
const bool append = true;
while (file_idx != UINT32_MAX) {
line_table->FineLineEntriesForFileIndex(file_idx, append,
m_sc_list);
// Get the next file index in case we have multiple file
// entries for the same file
file_idx = cu->GetSupportFiles().FindFileIndex(file_idx + 1,
m_file_spec, false);
}
} else {
// Match a specific line in a file...
}
}
}
}
return Searcher::eCallbackReturnContinue;
}
Searcher::Depth FileLineResolver::GetDepth() {
return Searcher::eDepthCompUnit;
}
void FileLineResolver::GetDescription(Stream *s) {
s->Printf("File and line resolver for file: \"%s\" line: %u",
m_file_spec.GetPath().c_str(), m_line_number);
}
void FileLineResolver::Clear() {
m_file_spec.Clear();
m_line_number = UINT32_MAX;
m_sc_list.Clear();
m_inlines = true;
}
void FileLineResolver::Reset(const FileSpec &file_spec, uint32_t line,
bool check_inlines) {
m_file_spec = file_spec;
m_line_number = line;
m_sc_list.Clear();
m_inlines = check_inlines;
}

View File

@@ -0,0 +1,151 @@
//===-- FileSpecList.cpp ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/FileSpecList.h"
#include "lldb/Utility/ConstString.h" // for ConstString
#include "lldb/Utility/Stream.h"
#include <utility> // for find
#include <stdint.h> // for UINT32_MAX
using namespace lldb_private;
using namespace std;
FileSpecList::FileSpecList() : m_files() {}
FileSpecList::FileSpecList(const FileSpecList &rhs) = default;
FileSpecList::~FileSpecList() = default;
//------------------------------------------------------------------
// Assignment operator
//------------------------------------------------------------------
const FileSpecList &FileSpecList::operator=(const FileSpecList &rhs) {
if (this != &rhs)
m_files = rhs.m_files;
return *this;
}
//------------------------------------------------------------------
// Append the "file_spec" to the end of the file spec list.
//------------------------------------------------------------------
void FileSpecList::Append(const FileSpec &file_spec) {
m_files.push_back(file_spec);
}
//------------------------------------------------------------------
// Only append the "file_spec" if this list doesn't already contain
// it.
//
// Returns true if "file_spec" was added, false if this list already
// contained a copy of "file_spec".
//------------------------------------------------------------------
bool FileSpecList::AppendIfUnique(const FileSpec &file_spec) {
collection::iterator end = m_files.end();
if (find(m_files.begin(), end, file_spec) == end) {
m_files.push_back(file_spec);
return true;
}
return false;
}
//------------------------------------------------------------------
// Clears the file list.
//------------------------------------------------------------------
void FileSpecList::Clear() { m_files.clear(); }
//------------------------------------------------------------------
// Dumps the file list to the supplied stream pointer "s".
//------------------------------------------------------------------
void FileSpecList::Dump(Stream *s, const char *separator_cstr) const {
collection::const_iterator pos, end = m_files.end();
for (pos = m_files.begin(); pos != end; ++pos) {
pos->Dump(s);
if (separator_cstr && ((pos + 1) != end))
s->PutCString(separator_cstr);
}
}
//------------------------------------------------------------------
// Find the index of the file in the file spec list that matches
// "file_spec" starting "start_idx" entries into the file spec list.
//
// Returns the valid index of the file that matches "file_spec" if
// it is found, else std::numeric_limits<uint32_t>::max() is returned.
//------------------------------------------------------------------
size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec,
bool full, bool remove_dots) const {
const size_t num_files = m_files.size();
// When looking for files, we will compare only the filename if the
// FILE_SPEC argument is empty
bool compare_filename_only = file_spec.GetDirectory().IsEmpty();
for (size_t idx = start_idx; idx < num_files; ++idx) {
if (compare_filename_only) {
if (ConstString::Equals(
m_files[idx].GetFilename(), file_spec.GetFilename(),
file_spec.IsCaseSensitive() || m_files[idx].IsCaseSensitive()))
return idx;
} else {
if (FileSpec::Equal(m_files[idx], file_spec, full, remove_dots))
return idx;
}
}
// We didn't find the file, return an invalid index
return UINT32_MAX;
}
//------------------------------------------------------------------
// Returns the FileSpec object at index "idx". If "idx" is out of
// range, then an empty FileSpec object will be returned.
//------------------------------------------------------------------
const FileSpec &FileSpecList::GetFileSpecAtIndex(size_t idx) const {
if (idx < m_files.size())
return m_files[idx];
static FileSpec g_empty_file_spec;
return g_empty_file_spec;
}
const FileSpec *FileSpecList::GetFileSpecPointerAtIndex(size_t idx) const {
if (idx < m_files.size())
return &m_files[idx];
return nullptr;
}
//------------------------------------------------------------------
// Return the size in bytes that this object takes in memory. This
// returns the size in bytes of this object's member variables and
// any FileSpec objects its member variables contain, the result
// doesn't not include the string values for the directories any
// filenames as those are in shared string pools.
//------------------------------------------------------------------
size_t FileSpecList::MemorySize() const {
size_t mem_size = sizeof(FileSpecList);
collection::const_iterator pos, end = m_files.end();
for (pos = m_files.begin(); pos != end; ++pos) {
mem_size += pos->MemorySize();
}
return mem_size;
}
//------------------------------------------------------------------
// Return the number of files in the file spec list.
//------------------------------------------------------------------
size_t FileSpecList::GetSize() const { return m_files.size(); }
size_t FileSpecList::GetFilesMatchingPartialPath(const char *path,
bool dir_okay,
FileSpecList &matches) {
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
103b5ecde94a8b08b92dab6d6be4afc3b0c2e358

View File

@@ -0,0 +1,472 @@
//===-- Listener.cpp --------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/Listener.h"
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Event.h"
#include "lldb/Utility/ConstString.h" // for ConstString
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Logging.h" // for GetLogIfAllCategoriesSet, LIBL...
#include "llvm/ADT/Optional.h" // for Optional
#include <algorithm>
#include <memory> // for make_shared
#include <utility> // for pair, make_pair
using namespace lldb;
using namespace lldb_private;
namespace {
class BroadcasterManagerWPMatcher {
public:
BroadcasterManagerWPMatcher(BroadcasterManagerSP manager_sp)
: m_manager_sp(manager_sp) {}
bool operator()(const BroadcasterManagerWP input_wp) const {
BroadcasterManagerSP input_sp = input_wp.lock();
return (input_sp && input_sp == m_manager_sp);
}
BroadcasterManagerSP m_manager_sp;
};
} // anonymous namespace
Listener::Listener(const char *name)
: m_name(name), m_broadcasters(), m_broadcasters_mutex(), m_events(),
m_events_mutex() {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
if (log != nullptr)
log->Printf("%p Listener::Listener('%s')", static_cast<void *>(this),
m_name.c_str());
}
Listener::~Listener() {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
Clear();
if (log)
log->Printf("%p Listener::%s('%s')", static_cast<void *>(this),
__FUNCTION__, m_name.c_str());
}
void Listener::Clear() {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
std::lock_guard<std::recursive_mutex> broadcasters_guard(
m_broadcasters_mutex);
broadcaster_collection::iterator pos, end = m_broadcasters.end();
for (pos = m_broadcasters.begin(); pos != end; ++pos) {
Broadcaster::BroadcasterImplSP broadcaster_sp(pos->first.lock());
if (broadcaster_sp)
broadcaster_sp->RemoveListener(this, pos->second.event_mask);
}
m_broadcasters.clear();
std::lock_guard<std::mutex> events_guard(m_events_mutex);
m_events.clear();
size_t num_managers = m_broadcaster_managers.size();
for (size_t i = 0; i < num_managers; i++) {
BroadcasterManagerSP manager_sp(m_broadcaster_managers[i].lock());
if (manager_sp)
manager_sp->RemoveListener(this);
}
if (log)
log->Printf("%p Listener::%s('%s')", static_cast<void *>(this),
__FUNCTION__, m_name.c_str());
}
uint32_t Listener::StartListeningForEvents(Broadcaster *broadcaster,
uint32_t event_mask) {
if (broadcaster) {
// Scope for "locker"
// Tell the broadcaster to add this object as a listener
{
std::lock_guard<std::recursive_mutex> broadcasters_guard(
m_broadcasters_mutex);
Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl());
m_broadcasters.insert(
std::make_pair(impl_wp, BroadcasterInfo(event_mask)));
}
uint32_t acquired_mask =
broadcaster->AddListener(this->shared_from_this(), event_mask);
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS));
if (log != nullptr)
log->Printf("%p Listener::StartListeningForEvents (broadcaster = %p, "
"mask = 0x%8.8x) acquired_mask = 0x%8.8x for %s",
static_cast<void *>(this), static_cast<void *>(broadcaster),
event_mask, acquired_mask, m_name.c_str());
return acquired_mask;
}
return 0;
}
uint32_t Listener::StartListeningForEvents(Broadcaster *broadcaster,
uint32_t event_mask,
HandleBroadcastCallback callback,
void *callback_user_data) {
if (broadcaster) {
// Scope for "locker"
// Tell the broadcaster to add this object as a listener
{
std::lock_guard<std::recursive_mutex> broadcasters_guard(
m_broadcasters_mutex);
Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl());
m_broadcasters.insert(std::make_pair(
impl_wp, BroadcasterInfo(event_mask, callback, callback_user_data)));
}
uint32_t acquired_mask =
broadcaster->AddListener(this->shared_from_this(), event_mask);
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS));
if (log != nullptr) {
void **pointer = reinterpret_cast<void **>(&callback);
log->Printf("%p Listener::StartListeningForEvents (broadcaster = %p, "
"mask = 0x%8.8x, callback = %p, user_data = %p) "
"acquired_mask = 0x%8.8x for %s",
static_cast<void *>(this), static_cast<void *>(broadcaster),
event_mask, *pointer, static_cast<void *>(callback_user_data),
acquired_mask, m_name.c_str());
}
return acquired_mask;
}
return 0;
}
bool Listener::StopListeningForEvents(Broadcaster *broadcaster,
uint32_t event_mask) {
if (broadcaster) {
// Scope for "locker"
{
std::lock_guard<std::recursive_mutex> broadcasters_guard(
m_broadcasters_mutex);
m_broadcasters.erase(broadcaster->GetBroadcasterImpl());
}
// Remove the broadcaster from our set of broadcasters
return broadcaster->RemoveListener(this->shared_from_this(), event_mask);
}
return false;
}
// Called when a Broadcaster is in its destructor. We need to remove all
// knowledge of this broadcaster and any events that it may have queued up
void Listener::BroadcasterWillDestruct(Broadcaster *broadcaster) {
// Scope for "broadcasters_locker"
{
std::lock_guard<std::recursive_mutex> broadcasters_guard(
m_broadcasters_mutex);
m_broadcasters.erase(broadcaster->GetBroadcasterImpl());
}
// Scope for "event_locker"
{
std::lock_guard<std::mutex> events_guard(m_events_mutex);
// Remove all events for this broadcaster object.
event_collection::iterator pos = m_events.begin();
while (pos != m_events.end()) {
if ((*pos)->GetBroadcaster() == broadcaster)
pos = m_events.erase(pos);
else
++pos;
}
}
}
void Listener::BroadcasterManagerWillDestruct(BroadcasterManagerSP manager_sp) {
// Just need to remove this broadcast manager from the list of managers:
broadcaster_manager_collection::iterator iter,
end_iter = m_broadcaster_managers.end();
BroadcasterManagerWP manager_wp;
BroadcasterManagerWPMatcher matcher(manager_sp);
iter = std::find_if<broadcaster_manager_collection::iterator,
BroadcasterManagerWPMatcher>(
m_broadcaster_managers.begin(), end_iter, matcher);
if (iter != end_iter)
m_broadcaster_managers.erase(iter);
}
void Listener::AddEvent(EventSP &event_sp) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS));
if (log != nullptr)
log->Printf("%p Listener('%s')::AddEvent (event_sp = {%p})",
static_cast<void *>(this), m_name.c_str(),
static_cast<void *>(event_sp.get()));
std::lock_guard<std::mutex> guard(m_events_mutex);
m_events.push_back(event_sp);
m_events_condition.notify_all();
}
class EventBroadcasterMatches {
public:
EventBroadcasterMatches(Broadcaster *broadcaster)
: m_broadcaster(broadcaster) {}
bool operator()(const EventSP &event_sp) const {
return event_sp->BroadcasterIs(m_broadcaster);
}
private:
Broadcaster *m_broadcaster;
};
class EventMatcher {
public:
EventMatcher(Broadcaster *broadcaster, const ConstString *broadcaster_names,
uint32_t num_broadcaster_names, uint32_t event_type_mask)
: m_broadcaster(broadcaster), m_broadcaster_names(broadcaster_names),
m_num_broadcaster_names(num_broadcaster_names),
m_event_type_mask(event_type_mask) {}
bool operator()(const EventSP &event_sp) const {
if (m_broadcaster && !event_sp->BroadcasterIs(m_broadcaster))
return false;
if (m_broadcaster_names) {
bool found_source = false;
const ConstString &event_broadcaster_name =
event_sp->GetBroadcaster()->GetBroadcasterName();
for (uint32_t i = 0; i < m_num_broadcaster_names; ++i) {
if (m_broadcaster_names[i] == event_broadcaster_name) {
found_source = true;
break;
}
}
if (!found_source)
return false;
}
if (m_event_type_mask == 0 || m_event_type_mask & event_sp->GetType())
return true;
return false;
}
private:
Broadcaster *m_broadcaster;
const ConstString *m_broadcaster_names;
const uint32_t m_num_broadcaster_names;
const uint32_t m_event_type_mask;
};
bool Listener::FindNextEventInternal(
std::unique_lock<std::mutex> &lock,
Broadcaster *broadcaster, // nullptr for any broadcaster
const ConstString *broadcaster_names, // nullptr for any event
uint32_t num_broadcaster_names, uint32_t event_type_mask, EventSP &event_sp,
bool remove) {
// NOTE: callers of this function must lock m_events_mutex using a
// Mutex::Locker
// and pass the locker as the first argument. m_events_mutex is no longer
// recursive.
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS));
if (m_events.empty())
return false;
Listener::event_collection::iterator pos = m_events.end();
if (broadcaster == nullptr && broadcaster_names == nullptr &&
event_type_mask == 0) {
pos = m_events.begin();
} else {
pos = std::find_if(m_events.begin(), m_events.end(),
EventMatcher(broadcaster, broadcaster_names,
num_broadcaster_names, event_type_mask));
}
if (pos != m_events.end()) {
event_sp = *pos;
if (log != nullptr)
log->Printf("%p '%s' Listener::FindNextEventInternal(broadcaster=%p, "
"broadcaster_names=%p[%u], event_type_mask=0x%8.8x, "
"remove=%i) event %p",
static_cast<void *>(this), GetName(),
static_cast<void *>(broadcaster),
static_cast<const void *>(broadcaster_names),
num_broadcaster_names, event_type_mask, remove,
static_cast<void *>(event_sp.get()));
if (remove) {
m_events.erase(pos);
// Unlock the event queue here. We've removed this event and are about to
// return
// it so it should be okay to get the next event off the queue here - and
// it might
// be useful to do that in the "DoOnRemoval".
lock.unlock();
event_sp->DoOnRemoval();
}
return true;
}
event_sp.reset();
return false;
}
Event *Listener::PeekAtNextEvent() {
std::unique_lock<std::mutex> guard(m_events_mutex);
EventSP event_sp;
if (FindNextEventInternal(guard, nullptr, nullptr, 0, 0, event_sp, false))
return event_sp.get();
return nullptr;
}
Event *Listener::PeekAtNextEventForBroadcaster(Broadcaster *broadcaster) {
std::unique_lock<std::mutex> guard(m_events_mutex);
EventSP event_sp;
if (FindNextEventInternal(guard, broadcaster, nullptr, 0, 0, event_sp, false))
return event_sp.get();
return nullptr;
}
Event *
Listener::PeekAtNextEventForBroadcasterWithType(Broadcaster *broadcaster,
uint32_t event_type_mask) {
std::unique_lock<std::mutex> guard(m_events_mutex);
EventSP event_sp;
if (FindNextEventInternal(guard, broadcaster, nullptr, 0, event_type_mask,
event_sp, false))
return event_sp.get();
return nullptr;
}
bool Listener::GetEventInternal(
const Timeout<std::micro> &timeout,
Broadcaster *broadcaster, // nullptr for any broadcaster
const ConstString *broadcaster_names, // nullptr for any event
uint32_t num_broadcaster_names, uint32_t event_type_mask,
EventSP &event_sp) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS));
LLDB_LOG(log, "this = {0}, timeout = {1} for {2}", this, timeout, m_name);
std::unique_lock<std::mutex> lock(m_events_mutex);
while (true) {
if (FindNextEventInternal(lock, broadcaster, broadcaster_names,
num_broadcaster_names, event_type_mask, event_sp,
true)) {
return true;
} else {
std::cv_status result = std::cv_status::no_timeout;
if (!timeout)
m_events_condition.wait(lock);
else
result = m_events_condition.wait_for(lock, *timeout);
if (result == std::cv_status::timeout) {
log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS);
if (log)
log->Printf("%p Listener::GetEventInternal() timed out for %s",
static_cast<void *>(this), m_name.c_str());
return false;
} else if (result != std::cv_status::no_timeout) {
log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS);
if (log)
log->Printf("%p Listener::GetEventInternal() unknown error for %s",
static_cast<void *>(this), m_name.c_str());
return false;
}
}
}
return false;
}
bool Listener::GetEventForBroadcasterWithType(
Broadcaster *broadcaster, uint32_t event_type_mask, EventSP &event_sp,
const Timeout<std::micro> &timeout) {
return GetEventInternal(timeout, broadcaster, nullptr, 0, event_type_mask,
event_sp);
}
bool Listener::GetEventForBroadcaster(Broadcaster *broadcaster,
EventSP &event_sp,
const Timeout<std::micro> &timeout) {
return GetEventInternal(timeout, broadcaster, nullptr, 0, 0, event_sp);
}
bool Listener::GetEvent(EventSP &event_sp, const Timeout<std::micro> &timeout) {
return GetEventInternal(timeout, nullptr, nullptr, 0, 0, event_sp);
}
size_t Listener::HandleBroadcastEvent(EventSP &event_sp) {
size_t num_handled = 0;
std::lock_guard<std::recursive_mutex> guard(m_broadcasters_mutex);
Broadcaster *broadcaster = event_sp->GetBroadcaster();
if (!broadcaster)
return 0;
broadcaster_collection::iterator pos;
broadcaster_collection::iterator end = m_broadcasters.end();
Broadcaster::BroadcasterImplSP broadcaster_impl_sp(
broadcaster->GetBroadcasterImpl());
for (pos = m_broadcasters.find(broadcaster_impl_sp);
pos != end && pos->first.lock() == broadcaster_impl_sp; ++pos) {
BroadcasterInfo info = pos->second;
if (event_sp->GetType() & info.event_mask) {
if (info.callback != nullptr) {
info.callback(event_sp, info.callback_user_data);
++num_handled;
}
}
}
return num_handled;
}
uint32_t
Listener::StartListeningForEventSpec(BroadcasterManagerSP manager_sp,
const BroadcastEventSpec &event_spec) {
if (!manager_sp)
return 0;
// The BroadcasterManager mutex must be locked before m_broadcasters_mutex
// to avoid violating the lock hierarchy (manager before broadcasters).
std::lock_guard<std::recursive_mutex> manager_guard(
manager_sp->m_manager_mutex);
std::lock_guard<std::recursive_mutex> guard(m_broadcasters_mutex);
uint32_t bits_acquired = manager_sp->RegisterListenerForEvents(
this->shared_from_this(), event_spec);
if (bits_acquired) {
broadcaster_manager_collection::iterator iter,
end_iter = m_broadcaster_managers.end();
BroadcasterManagerWP manager_wp(manager_sp);
BroadcasterManagerWPMatcher matcher(manager_sp);
iter = std::find_if<broadcaster_manager_collection::iterator,
BroadcasterManagerWPMatcher>(
m_broadcaster_managers.begin(), end_iter, matcher);
if (iter == end_iter)
m_broadcaster_managers.push_back(manager_wp);
}
return bits_acquired;
}
bool Listener::StopListeningForEventSpec(BroadcasterManagerSP manager_sp,
const BroadcastEventSpec &event_spec) {
if (!manager_sp)
return false;
std::lock_guard<std::recursive_mutex> guard(m_broadcasters_mutex);
return manager_sp->UnregisterListenerForEvents(this->shared_from_this(),
event_spec);
}
ListenerSP Listener::MakeListener(const char *name) {
return ListenerSP(new Listener(name));
}

View File

@@ -0,0 +1,461 @@
//===-- Mangled.cpp ---------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/Mangled.h"
#if defined(_WIN32)
#include "lldb/Host/windows/windows.h"
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")
#endif
#ifdef LLDB_USE_BUILTIN_DEMANGLER
// Provide a fast-path demangler implemented in FastDemangle.cpp until it can
// replace the existing C++ demangler with a complete implementation
#include "lldb/Utility/FastDemangle.h"
#include "llvm/Demangle/Demangle.h"
#else
// FreeBSD9-STABLE requires this to know about size_t in cxxabi.
#include <cstddef>
#include <cxxabi.h>
#endif
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Logging.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/Timer.h"
#include "lldb/lldb-enumerations.h" // for LanguageType
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "llvm/ADT/StringRef.h" // for StringRef
#include "llvm/Support/Compiler.h" // for LLVM_PRETT...
#include <mutex> // for mutex, loc...
#include <string> // for string
#include <utility> // for pair
#include <stdlib.h>
#include <string.h>
using namespace lldb_private;
#if defined(_MSC_VER)
static DWORD safeUndecorateName(const char *Mangled, char *Demangled,
DWORD DemangledLength) {
static std::mutex M;
std::lock_guard<std::mutex> Lock(M);
return ::UnDecorateSymbolName(
Mangled, Demangled, DemangledLength,
UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected
// keywords
UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall,
// etc keywords
UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications
UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc
// specifiers
UNDNAME_NO_MS_KEYWORDS // Strip all MS extension keywords
);
}
#endif
static inline Mangled::ManglingScheme cstring_mangling_scheme(const char *s) {
if (s) {
if (s[0] == '?')
return Mangled::eManglingSchemeMSVC;
if (s[0] == '_' && s[1] == 'Z')
return Mangled::eManglingSchemeItanium;
}
return Mangled::eManglingSchemeNone;
}
static inline bool cstring_is_mangled(const char *s) {
return cstring_mangling_scheme(s) != Mangled::eManglingSchemeNone;
}
static const ConstString &
get_demangled_name_without_arguments(ConstString mangled,
ConstString demangled) {
// This pair is <mangled name, demangled name without function arguments>
static std::pair<ConstString, ConstString>
g_most_recent_mangled_to_name_sans_args;
// Need to have the mangled & demangled names we're currently examining as
// statics
// so we can return a const ref to them at the end of the func if we don't
// have
// anything better.
static ConstString g_last_mangled;
static ConstString g_last_demangled;
if (mangled && g_most_recent_mangled_to_name_sans_args.first == mangled) {
return g_most_recent_mangled_to_name_sans_args.second;
}
g_last_demangled = demangled;
g_last_mangled = mangled;
const char *mangled_name_cstr = mangled.GetCString();
if (demangled && mangled_name_cstr && mangled_name_cstr[0]) {
if (mangled_name_cstr[0] == '_' && mangled_name_cstr[1] == 'Z' &&
(mangled_name_cstr[2] != 'T' && // avoid virtual table, VTT structure,
// typeinfo structure, and typeinfo
// mangled_name
mangled_name_cstr[2] != 'G' && // avoid guard variables
mangled_name_cstr[2] != 'Z')) // named local entities (if we eventually
// handle eSymbolTypeData, we will want
// this back)
{
CPlusPlusLanguage::MethodName cxx_method(demangled);
if (!cxx_method.GetBasename().empty()) {
std::string shortname;
if (!cxx_method.GetContext().empty())
shortname = cxx_method.GetContext().str() + "::";
shortname += cxx_method.GetBasename().str();
ConstString result(shortname.c_str());
g_most_recent_mangled_to_name_sans_args.first = mangled;
g_most_recent_mangled_to_name_sans_args.second = result;
return g_most_recent_mangled_to_name_sans_args.second;
}
}
}
if (demangled)
return g_last_demangled;
return g_last_mangled;
}
#pragma mark Mangled
//----------------------------------------------------------------------
// Default constructor
//----------------------------------------------------------------------
Mangled::Mangled() : m_mangled(), m_demangled() {}
//----------------------------------------------------------------------
// Constructor with an optional string and a boolean indicating if it is
// the mangled version.
//----------------------------------------------------------------------
Mangled::Mangled(const ConstString &s, bool mangled)
: m_mangled(), m_demangled() {
if (s)
SetValue(s, mangled);
}
Mangled::Mangled(llvm::StringRef name, bool is_mangled) {
if (!name.empty())
SetValue(ConstString(name), is_mangled);
}
Mangled::Mangled(const ConstString &s) : m_mangled(), m_demangled() {
if (s)
SetValue(s);
}
Mangled::Mangled(llvm::StringRef name) {
if (!name.empty())
SetValue(ConstString(name));
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
Mangled::~Mangled() {}
//----------------------------------------------------------------------
// Convert to pointer operator. This allows code to check any Mangled
// objects to see if they contain anything valid using code such as:
//
// Mangled mangled(...);
// if (mangled)
// { ...
//----------------------------------------------------------------------
Mangled::operator void *() const {
return (m_mangled) ? const_cast<Mangled *>(this) : NULL;
}
//----------------------------------------------------------------------
// Logical NOT operator. This allows code to check any Mangled
// objects to see if they are invalid using code such as:
//
// Mangled mangled(...);
// if (!file_spec)
// { ...
//----------------------------------------------------------------------
bool Mangled::operator!() const { return !m_mangled; }
//----------------------------------------------------------------------
// Clear the mangled and demangled values.
//----------------------------------------------------------------------
void Mangled::Clear() {
m_mangled.Clear();
m_demangled.Clear();
}
//----------------------------------------------------------------------
// Compare the string values.
//----------------------------------------------------------------------
int Mangled::Compare(const Mangled &a, const Mangled &b) {
return ConstString::Compare(
a.GetName(lldb::eLanguageTypeUnknown, ePreferMangled),
a.GetName(lldb::eLanguageTypeUnknown, ePreferMangled));
}
//----------------------------------------------------------------------
// Set the string value in this objects. If "mangled" is true, then
// the mangled named is set with the new value in "s", else the
// demangled name is set.
//----------------------------------------------------------------------
void Mangled::SetValue(const ConstString &s, bool mangled) {
if (s) {
if (mangled) {
m_demangled.Clear();
m_mangled = s;
} else {
m_demangled = s;
m_mangled.Clear();
}
} else {
m_demangled.Clear();
m_mangled.Clear();
}
}
void Mangled::SetValue(const ConstString &name) {
if (name) {
if (cstring_is_mangled(name.GetCString())) {
m_demangled.Clear();
m_mangled = name;
} else {
m_demangled = name;
m_mangled.Clear();
}
} else {
m_demangled.Clear();
m_mangled.Clear();
}
}
//----------------------------------------------------------------------
// Generate the demangled name on demand using this accessor. Code in
// this class will need to use this accessor if it wishes to decode
// the demangled name. The result is cached and will be kept until a
// new string value is supplied to this object, or until the end of the
// object's lifetime.
//----------------------------------------------------------------------
const ConstString &
Mangled::GetDemangledName(lldb::LanguageType language) const {
// Check to make sure we have a valid mangled name and that we
// haven't already decoded our mangled name.
if (m_mangled && !m_demangled) {
// We need to generate and cache the demangled name.
static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(func_cat, "Mangled::GetDemangledName (m_mangled = %s)",
m_mangled.GetCString());
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE);
// Don't bother running anything that isn't mangled
const char *mangled_name = m_mangled.GetCString();
ManglingScheme mangling_scheme{cstring_mangling_scheme(mangled_name)};
if (mangling_scheme != eManglingSchemeNone &&
!m_mangled.GetMangledCounterpart(m_demangled)) {
// We didn't already mangle this name, demangle it and if all goes well
// add it to our map.
char *demangled_name = nullptr;
switch (mangling_scheme) {
case eManglingSchemeMSVC: {
#if defined(_MSC_VER)
if (log)
log->Printf("demangle msvc: %s", mangled_name);
const size_t demangled_length = 2048;
demangled_name = static_cast<char *>(::malloc(demangled_length));
::ZeroMemory(demangled_name, demangled_length);
DWORD result =
safeUndecorateName(mangled_name, demangled_name, demangled_length);
if (log) {
if (demangled_name && demangled_name[0])
log->Printf("demangled msvc: %s -> \"%s\"", mangled_name,
demangled_name);
else
log->Printf("demangled msvc: %s -> error: 0x%lu", mangled_name,
result);
}
if (result == 0) {
free(demangled_name);
demangled_name = nullptr;
}
#endif
break;
}
case eManglingSchemeItanium: {
#ifdef LLDB_USE_BUILTIN_DEMANGLER
if (log)
log->Printf("demangle itanium: %s", mangled_name);
// Try to use the fast-path demangler first for the
// performance win, falling back to the full demangler only
// when necessary
demangled_name = FastDemangle(mangled_name, m_mangled.GetLength());
if (!demangled_name)
demangled_name =
llvm::itaniumDemangle(mangled_name, NULL, NULL, NULL);
#else
demangled_name = abi::__cxa_demangle(mangled_name, NULL, NULL, NULL);
#endif
if (log) {
if (demangled_name)
log->Printf("demangled itanium: %s -> \"%s\"", mangled_name,
demangled_name);
else
log->Printf("demangled itanium: %s -> error: failed to demangle",
mangled_name);
}
break;
}
case eManglingSchemeNone:
break;
}
if (demangled_name) {
m_demangled.SetCStringWithMangledCounterpart(demangled_name, m_mangled);
free(demangled_name);
}
}
if (!m_demangled) {
// Set the demangled string to the empty string to indicate we
// tried to parse it once and failed.
m_demangled.SetCString("");
}
}
return m_demangled;
}
ConstString
Mangled::GetDisplayDemangledName(lldb::LanguageType language) const {
return GetDemangledName(language);
}
bool Mangled::NameMatches(const RegularExpression &regex,
lldb::LanguageType language) const {
if (m_mangled && regex.Execute(m_mangled.AsCString()))
return true;
ConstString demangled = GetDemangledName(language);
if (demangled && regex.Execute(demangled.AsCString()))
return true;
return false;
}
//----------------------------------------------------------------------
// Get the demangled name if there is one, else return the mangled name.
//----------------------------------------------------------------------
ConstString Mangled::GetName(lldb::LanguageType language,
Mangled::NamePreference preference) const {
if (preference == ePreferMangled && m_mangled)
return m_mangled;
ConstString demangled = GetDemangledName(language);
if (preference == ePreferDemangledWithoutArguments) {
return get_demangled_name_without_arguments(m_mangled, demangled);
}
if (preference == ePreferDemangled) {
// Call the accessor to make sure we get a demangled name in case
// it hasn't been demangled yet...
if (demangled)
return demangled;
return m_mangled;
}
return demangled;
}
//----------------------------------------------------------------------
// Dump a Mangled object to stream "s". We don't force our
// demangled name to be computed currently (we don't use the accessor).
//----------------------------------------------------------------------
void Mangled::Dump(Stream *s) const {
if (m_mangled) {
*s << ", mangled = " << m_mangled;
}
if (m_demangled) {
const char *demangled = m_demangled.AsCString();
s->Printf(", demangled = %s", demangled[0] ? demangled : "<error>");
}
}
//----------------------------------------------------------------------
// Dumps a debug version of this string with extra object and state
// information to stream "s".
//----------------------------------------------------------------------
void Mangled::DumpDebug(Stream *s) const {
s->Printf("%*p: Mangled mangled = ", static_cast<int>(sizeof(void *) * 2),
static_cast<const void *>(this));
m_mangled.DumpDebug(s);
s->Printf(", demangled = ");
m_demangled.DumpDebug(s);
}
//----------------------------------------------------------------------
// Return the size in byte that this object takes in memory. The size
// includes the size of the objects it owns, and not the strings that
// it references because they are shared strings.
//----------------------------------------------------------------------
size_t Mangled::MemorySize() const {
return m_mangled.MemorySize() + m_demangled.MemorySize();
}
//----------------------------------------------------------------------
// We "guess" the language because we can't determine a symbol's language
// from it's name. For example, a Pascal symbol can be mangled using the
// C++ Itanium scheme, and defined in a compilation unit within the same
// module as other C++ units. In addition, different targets could have
// different ways of mangling names from a given language, likewise the
// compilation units within those targets.
//----------------------------------------------------------------------
lldb::LanguageType Mangled::GuessLanguage() const {
ConstString mangled = GetMangledName();
if (mangled) {
if (GetDemangledName(lldb::eLanguageTypeUnknown)) {
const char *mangled_name = mangled.GetCString();
if (CPlusPlusLanguage::IsCPPMangledName(mangled_name))
return lldb::eLanguageTypeC_plus_plus;
else if (ObjCLanguage::IsPossibleObjCMethodName(mangled_name))
return lldb::eLanguageTypeObjC;
}
} else {
// ObjC names aren't really mangled, so they won't necessarily be in the
// mangled name slot.
ConstString demangled_name = GetDemangledName(lldb::eLanguageTypeUnknown);
if (demangled_name
&& ObjCLanguage::IsPossibleObjCMethodName(demangled_name.GetCString()))
return lldb::eLanguageTypeObjC;
}
return lldb::eLanguageTypeUnknown;
}
//----------------------------------------------------------------------
// Dump OBJ to the supplied stream S.
//----------------------------------------------------------------------
Stream &operator<<(Stream &s, const Mangled &obj) {
if (obj.GetMangledName())
s << "mangled = '" << obj.GetMangledName() << "'";
const ConstString &demangled =
obj.GetDemangledName(lldb::eLanguageTypeUnknown);
if (demangled)
s << ", demangled = '" << demangled << '\'';
else
s << ", demangled = <error>";
return s;
}

Some files were not shown because too many files have changed in this diff Show More