summaryrefslogtreecommitdiffstats
path: root/source/Core
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
committeremaste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
commitdcd15f81789e389c1cb27d264fcdddfd0a6002bd (patch)
treef561dabc721ad515599172c16da3a4400b7f4aec /source/Core
downloadFreeBSD-src-dcd15f81789e389c1cb27d264fcdddfd0a6002bd.zip
FreeBSD-src-dcd15f81789e389c1cb27d264fcdddfd0a6002bd.tar.gz
Import lldb as of SVN r188801
(A number of files not required for the FreeBSD build have been removed.) Sponsored by: DARPA, AFRL
Diffstat (limited to 'source/Core')
-rw-r--r--source/Core/Address.cpp1045
-rw-r--r--source/Core/AddressRange.cpp208
-rw-r--r--source/Core/AddressResolver.cpp67
-rw-r--r--source/Core/AddressResolverFileLine.cpp102
-rw-r--r--source/Core/AddressResolverName.cpp255
-rw-r--r--source/Core/ArchSpec.cpp893
-rw-r--r--source/Core/Baton.cpp24
-rw-r--r--source/Core/Broadcaster.cpp499
-rw-r--r--source/Core/Communication.cpp431
-rw-r--r--source/Core/Connection.cpp24
-rw-r--r--source/Core/ConnectionFileDescriptor.cpp1528
-rw-r--r--source/Core/ConnectionMachPort.cpp323
-rw-r--r--source/Core/ConnectionSharedMemory.cpp131
-rw-r--r--source/Core/ConstString.cpp342
-rw-r--r--source/Core/DataBufferHeap.cpp111
-rw-r--r--source/Core/DataBufferMemoryMap.cpp258
-rw-r--r--source/Core/DataEncoder.cpp335
-rw-r--r--source/Core/DataExtractor.cpp2179
-rw-r--r--source/Core/Debugger.cpp2695
-rw-r--r--source/Core/Disassembler.cpp1269
-rw-r--r--source/Core/DynamicLoader.cpp76
-rw-r--r--source/Core/EmulateInstruction.cpp670
-rw-r--r--source/Core/Error.cpp399
-rw-r--r--source/Core/Event.cpp225
-rw-r--r--source/Core/FileLineResolver.cpp117
-rw-r--r--source/Core/FileSpecList.cpp234
-rw-r--r--source/Core/History.cpp26
-rw-r--r--source/Core/InputReader.cpp387
-rw-r--r--source/Core/InputReaderEZ.cpp91
-rw-r--r--source/Core/InputReaderStack.cpp80
-rw-r--r--source/Core/Language.cpp151
-rw-r--r--source/Core/Listener.cpp557
-rw-r--r--source/Core/Log.cpp529
-rw-r--r--source/Core/Mangled.cpp313
-rw-r--r--source/Core/Module.cpp1609
-rw-r--r--source/Core/ModuleChild.cpp46
-rw-r--r--source/Core/ModuleList.cpp1103
-rw-r--r--source/Core/Opcode.cpp134
-rw-r--r--source/Core/PluginManager.cpp2064
-rw-r--r--source/Core/RegisterValue.cpp1272
-rw-r--r--source/Core/RegularExpression.cpp279
-rw-r--r--source/Core/Scalar.cpp2279
-rw-r--r--source/Core/SearchFilter.cpp816
-rw-r--r--source/Core/Section.cpp562
-rw-r--r--source/Core/SourceManager.cpp651
-rw-r--r--source/Core/State.cpp115
-rw-r--r--source/Core/Stream.cpp786
-rw-r--r--source/Core/StreamAsynchronousIO.cpp52
-rw-r--r--source/Core/StreamCallback.cpp64
-rw-r--r--source/Core/StreamFile.cpp72
-rw-r--r--source/Core/StreamString.cpp100
-rw-r--r--source/Core/StringList.cpp290
-rw-r--r--source/Core/Timer.cpp250
-rw-r--r--source/Core/UUID.cpp279
-rw-r--r--source/Core/UserID.cpp23
-rw-r--r--source/Core/UserSettingsController.cpp111
-rw-r--r--source/Core/VMRange.cpp112
-rw-r--r--source/Core/Value.cpp761
-rw-r--r--source/Core/ValueObject.cpp4199
-rw-r--r--source/Core/ValueObjectCast.cpp129
-rw-r--r--source/Core/ValueObjectChild.cpp234
-rw-r--r--source/Core/ValueObjectConstResult.cpp354
-rw-r--r--source/Core/ValueObjectConstResultChild.cpp80
-rw-r--r--source/Core/ValueObjectConstResultImpl.cpp236
-rw-r--r--source/Core/ValueObjectDynamicValue.cpp372
-rw-r--r--source/Core/ValueObjectList.cpp166
-rw-r--r--source/Core/ValueObjectMemory.cpp275
-rw-r--r--source/Core/ValueObjectRegister.cpp431
-rw-r--r--source/Core/ValueObjectSyntheticFilter.cpp270
-rw-r--r--source/Core/ValueObjectVariable.cpp386
70 files changed, 37536 insertions, 0 deletions
diff --git a/source/Core/Address.cpp b/source/Core/Address.cpp
new file mode 100644
index 0000000..8d599d8
--- /dev/null
+++ b/source/Core/Address.cpp
@@ -0,0 +1,1045 @@
+//===-- Address.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/Address.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+#include "llvm/ADT/Triple.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static size_t
+ReadBytes (ExecutionContextScope *exe_scope, const Address &address, void *dst, size_t dst_len)
+{
+ if (exe_scope == NULL)
+ return 0;
+
+ TargetSP target_sp (exe_scope->CalculateTarget());
+ if (target_sp)
+ {
+ Error error;
+ bool prefer_file_cache = false;
+ return target_sp->ReadMemory (address, prefer_file_cache, dst, dst_len, error);
+ }
+ return 0;
+}
+
+static bool
+GetByteOrderAndAddressSize (ExecutionContextScope *exe_scope, const Address &address, ByteOrder& byte_order, uint32_t& addr_size)
+{
+ byte_order = eByteOrderInvalid;
+ addr_size = 0;
+ if (exe_scope == NULL)
+ return false;
+
+ TargetSP target_sp (exe_scope->CalculateTarget());
+ if (target_sp)
+ {
+ byte_order = target_sp->GetArchitecture().GetByteOrder();
+ addr_size = target_sp->GetArchitecture().GetAddressByteSize();
+ }
+
+ if (byte_order == eByteOrderInvalid || addr_size == 0)
+ {
+ ModuleSP module_sp (address.GetModule());
+ if (module_sp)
+ {
+ byte_order = module_sp->GetArchitecture().GetByteOrder();
+ addr_size = module_sp->GetArchitecture().GetAddressByteSize();
+ }
+ }
+ return byte_order != eByteOrderInvalid && addr_size != 0;
+}
+
+static uint64_t
+ReadUIntMax64 (ExecutionContextScope *exe_scope, const Address &address, uint32_t byte_size, bool &success)
+{
+ uint64_t uval64 = 0;
+ if (exe_scope == NULL || byte_size > sizeof(uint64_t))
+ {
+ success = false;
+ return 0;
+ }
+ uint64_t buf = 0;
+
+ success = ReadBytes (exe_scope, address, &buf, byte_size) == byte_size;
+ if (success)
+ {
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t addr_size = 0;
+ if (GetByteOrderAndAddressSize (exe_scope, address, byte_order, addr_size))
+ {
+ DataExtractor data (&buf, sizeof(buf), byte_order, addr_size);
+ lldb::offset_t offset = 0;
+ uval64 = data.GetU64(&offset);
+ }
+ else
+ success = false;
+ }
+ return uval64;
+}
+
+static bool
+ReadAddress (ExecutionContextScope *exe_scope, const Address &address, uint32_t pointer_size, Address &deref_so_addr)
+{
+ if (exe_scope == NULL)
+ return false;
+
+
+ bool success = false;
+ addr_t deref_addr = ReadUIntMax64 (exe_scope, address, pointer_size, success);
+ if (success)
+ {
+ ExecutionContext exe_ctx;
+ exe_scope->CalculateExecutionContext(exe_ctx);
+ // If we have any sections that are loaded, try and resolve using the
+ // section load list
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target && !target->GetSectionLoadList().IsEmpty())
+ {
+ if (target->GetSectionLoadList().ResolveLoadAddress (deref_addr, deref_so_addr))
+ return true;
+ }
+ else
+ {
+ // If we were not running, yet able to read an integer, we must
+ // have a module
+ ModuleSP module_sp (address.GetModule());
+
+ assert (module_sp);
+ if (module_sp->ResolveFileAddress(deref_addr, deref_so_addr))
+ return true;
+ }
+
+ // We couldn't make "deref_addr" into a section offset value, but we were
+ // able to read the address, so we return a section offset address with
+ // no section and "deref_addr" as the offset (address).
+ deref_so_addr.SetRawAddress(deref_addr);
+ return true;
+ }
+ return false;
+}
+
+static bool
+DumpUInt (ExecutionContextScope *exe_scope, const Address &address, uint32_t byte_size, Stream* strm)
+{
+ if (exe_scope == NULL || byte_size == 0)
+ return 0;
+ std::vector<uint8_t> buf(byte_size, 0);
+
+ if (ReadBytes (exe_scope, address, &buf[0], buf.size()) == buf.size())
+ {
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t addr_size = 0;
+ if (GetByteOrderAndAddressSize (exe_scope, address, byte_order, addr_size))
+ {
+ DataExtractor data (&buf.front(), buf.size(), byte_order, addr_size);
+
+ data.Dump (strm,
+ 0, // Start offset in "data"
+ eFormatHex, // Print as characters
+ buf.size(), // Size of item
+ 1, // Items count
+ UINT32_MAX, // num per line
+ LLDB_INVALID_ADDRESS,// base address
+ 0, // bitfield bit size
+ 0); // bitfield bit offset
+
+ return true;
+ }
+ }
+ return false;
+}
+
+
+static size_t
+ReadCStringFromMemory (ExecutionContextScope *exe_scope, const Address &address, Stream *strm)
+{
+ if (exe_scope == NULL)
+ return 0;
+ const size_t k_buf_len = 256;
+ char buf[k_buf_len+1];
+ buf[k_buf_len] = '\0'; // NULL terminate
+
+ // Byte order and address size don't matter for C string dumping..
+ DataExtractor data (buf, sizeof(buf), lldb::endian::InlHostByteOrder(), 4);
+ size_t total_len = 0;
+ size_t bytes_read;
+ Address curr_address(address);
+ strm->PutChar ('"');
+ while ((bytes_read = ReadBytes (exe_scope, curr_address, buf, k_buf_len)) > 0)
+ {
+ size_t len = strlen(buf);
+ if (len == 0)
+ break;
+ if (len > bytes_read)
+ len = bytes_read;
+
+ data.Dump (strm,
+ 0, // Start offset in "data"
+ eFormatChar, // Print as characters
+ 1, // Size of item (1 byte for a char!)
+ len, // How many bytes to print?
+ UINT32_MAX, // num per line
+ LLDB_INVALID_ADDRESS,// base address
+ 0, // bitfield bit size
+
+ 0); // bitfield bit offset
+
+ total_len += bytes_read;
+
+ if (len < k_buf_len)
+ break;
+ curr_address.SetOffset (curr_address.GetOffset() + bytes_read);
+ }
+ strm->PutChar ('"');
+ return total_len;
+}
+
+Address::Address (lldb::addr_t abs_addr) :
+ m_section_wp (),
+ m_offset (abs_addr)
+{
+}
+
+Address::Address (addr_t address, const SectionList *section_list) :
+ m_section_wp (),
+ m_offset (LLDB_INVALID_ADDRESS)
+{
+ ResolveAddressUsingFileSections(address, section_list);
+}
+
+const Address&
+Address::operator= (const Address& rhs)
+{
+ if (this != &rhs)
+ {
+ m_section_wp = rhs.m_section_wp;
+ m_offset = rhs.m_offset.load();
+ }
+ return *this;
+}
+
+bool
+Address::ResolveAddressUsingFileSections (addr_t file_addr, const SectionList *section_list)
+{
+ if (section_list)
+ {
+ SectionSP section_sp (section_list->FindSectionContainingFileAddress(file_addr));
+ m_section_wp = section_sp;
+ if (section_sp)
+ {
+ assert( section_sp->ContainsFileAddress(file_addr) );
+ m_offset = file_addr - section_sp->GetFileAddress();
+ return true; // Successfully transformed addr into a section offset address
+ }
+ }
+ m_offset = file_addr;
+ return false; // Failed to resolve this address to a section offset value
+}
+
+ModuleSP
+Address::GetModule () const
+{
+ lldb::ModuleSP module_sp;
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ module_sp = section_sp->GetModule();
+ return module_sp;
+}
+
+addr_t
+Address::GetFileAddress () const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ addr_t sect_file_addr = section_sp->GetFileAddress();
+ if (sect_file_addr == LLDB_INVALID_ADDRESS)
+ {
+ // Section isn't resolved, we can't return a valid file address
+ return LLDB_INVALID_ADDRESS;
+ }
+ // We have a valid file range, so we can return the file based
+ // address by adding the file base address to our offset
+ return sect_file_addr + m_offset;
+ }
+ // No section, we just return the offset since it is the value in this case
+ return m_offset;
+}
+
+addr_t
+Address::GetLoadAddress (Target *target) const
+{
+ SectionSP section_sp (GetSection());
+ if (!section_sp)
+ {
+ // No section, we just return the offset since it is the value in this case
+ return m_offset;
+ }
+
+ if (target)
+ {
+ addr_t sect_load_addr = section_sp->GetLoadBaseAddress (target);
+
+ if (sect_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ // We have a valid file range, so we can return the file based
+ // address by adding the file base address to our offset
+ return sect_load_addr + m_offset;
+ }
+ }
+ // The section isn't resolved or no process was supplied so we can't
+ // return a valid file address.
+ return LLDB_INVALID_ADDRESS;
+}
+
+addr_t
+Address::GetCallableLoadAddress (Target *target, bool is_indirect) const
+{
+ if (is_indirect && target) {
+ ProcessSP processSP = target->GetProcessSP();
+ Error error;
+ if (processSP.get())
+ return processSP->ResolveIndirectFunction(this, error);
+ }
+
+ addr_t code_addr = GetLoadAddress (target);
+
+ if (target)
+ return target->GetCallableLoadAddress (code_addr, GetAddressClass());
+ return code_addr;
+}
+
+bool
+Address::SetCallableLoadAddress (lldb::addr_t load_addr, Target *target)
+{
+ if (SetLoadAddress (load_addr, target))
+ {
+ if (target)
+ m_offset = target->GetCallableLoadAddress(m_offset, GetAddressClass());
+ return true;
+ }
+ return false;
+}
+
+addr_t
+Address::GetOpcodeLoadAddress (Target *target) const
+{
+ addr_t code_addr = GetLoadAddress (target);
+ if (code_addr != LLDB_INVALID_ADDRESS)
+ code_addr = target->GetOpcodeLoadAddress (code_addr, GetAddressClass());
+ return code_addr;
+}
+
+bool
+Address::SetOpcodeLoadAddress (lldb::addr_t load_addr, Target *target)
+{
+ if (SetLoadAddress (load_addr, target))
+ {
+ if (target)
+ m_offset = target->GetOpcodeLoadAddress (m_offset, GetAddressClass());
+ return true;
+ }
+ return false;
+}
+
+bool
+Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style, uint32_t addr_size) const
+{
+ // If the section was NULL, only load address is going to work unless we are
+ // trying to deref a pointer
+ SectionSP section_sp (GetSection());
+ if (!section_sp && style != DumpStyleResolvedPointerDescription)
+ style = DumpStyleLoadAddress;
+
+ ExecutionContext exe_ctx (exe_scope);
+ Target *target = exe_ctx.GetTargetPtr();
+ // If addr_byte_size is UINT32_MAX, then determine the correct address
+ // byte size for the process or default to the size of addr_t
+ if (addr_size == UINT32_MAX)
+ {
+ if (target)
+ addr_size = target->GetArchitecture().GetAddressByteSize ();
+ else
+ addr_size = sizeof(addr_t);
+ }
+
+ Address so_addr;
+ switch (style)
+ {
+ case DumpStyleInvalid:
+ return false;
+
+ case DumpStyleSectionNameOffset:
+ if (section_sp)
+ {
+ section_sp->DumpName(s);
+ s->Printf (" + %" PRIu64, m_offset.load());
+ }
+ else
+ {
+ s->Address(m_offset, addr_size);
+ }
+ break;
+
+ case DumpStyleSectionPointerOffset:
+ s->Printf("(Section *)%p + ", section_sp.get());
+ s->Address(m_offset, addr_size);
+ break;
+
+ case DumpStyleModuleWithFileAddress:
+ if (section_sp)
+ s->Printf("%s[", section_sp->GetModule()->GetFileSpec().GetFilename().AsCString());
+ // Fall through
+ case DumpStyleFileAddress:
+ {
+ addr_t file_addr = GetFileAddress();
+ if (file_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
+ return false;
+ }
+ s->Address (file_addr, addr_size);
+ if (style == DumpStyleModuleWithFileAddress && section_sp)
+ s->PutChar(']');
+ }
+ break;
+
+ case DumpStyleLoadAddress:
+ {
+ addr_t load_addr = GetLoadAddress (target);
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
+ return false;
+ }
+ s->Address (load_addr, addr_size);
+ }
+ break;
+
+ case DumpStyleResolvedDescription:
+ case DumpStyleResolvedDescriptionNoModule:
+ if (IsSectionOffset())
+ {
+ uint32_t pointer_size = 4;
+ ModuleSP module_sp (GetModule());
+ if (target)
+ pointer_size = target->GetArchitecture().GetAddressByteSize();
+ else if (module_sp)
+ pointer_size = module_sp->GetArchitecture().GetAddressByteSize();
+
+ bool showed_info = false;
+ if (section_sp)
+ {
+ SectionType sect_type = section_sp->GetType();
+ switch (sect_type)
+ {
+ case eSectionTypeData:
+ if (module_sp)
+ {
+ SymbolVendor *sym_vendor = module_sp->GetSymbolVendor();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ {
+ const addr_t file_Addr = GetFileAddress();
+ Symbol *symbol = symtab->FindSymbolContainingFileAddress (file_Addr);
+ if (symbol)
+ {
+ const char *symbol_name = symbol->GetName().AsCString();
+ if (symbol_name)
+ {
+ s->PutCString(symbol_name);
+ addr_t delta = file_Addr - symbol->GetAddress().GetFileAddress();
+ if (delta)
+ s->Printf(" + %" PRIu64, delta);
+ showed_info = true;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case eSectionTypeDataCString:
+ // Read the C string from memory and display it
+ showed_info = true;
+ ReadCStringFromMemory (exe_scope, *this, s);
+ break;
+
+ case eSectionTypeDataCStringPointers:
+ {
+ if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
+ {
+#if VERBOSE_OUTPUT
+ s->PutCString("(char *)");
+ so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+ s->PutCString(": ");
+#endif
+ showed_info = true;
+ ReadCStringFromMemory (exe_scope, so_addr, s);
+ }
+ }
+ break;
+
+ case eSectionTypeDataObjCMessageRefs:
+ {
+ if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
+ {
+ if (target && so_addr.IsSectionOffset())
+ {
+ SymbolContext func_sc;
+ target->GetImages().ResolveSymbolContextForAddress (so_addr,
+ eSymbolContextEverything,
+ func_sc);
+ if (func_sc.function || func_sc.symbol)
+ {
+ showed_info = true;
+#if VERBOSE_OUTPUT
+ s->PutCString ("(objc_msgref *) -> { (func*)");
+ so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+#else
+ s->PutCString ("{ ");
+#endif
+ Address cstr_addr(*this);
+ cstr_addr.SetOffset(cstr_addr.GetOffset() + pointer_size);
+ func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, false);
+ if (ReadAddress (exe_scope, cstr_addr, pointer_size, so_addr))
+ {
+#if VERBOSE_OUTPUT
+ s->PutCString("), (char *)");
+ so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+ s->PutCString(" (");
+#else
+ s->PutCString(", ");
+#endif
+ ReadCStringFromMemory (exe_scope, so_addr, s);
+ }
+#if VERBOSE_OUTPUT
+ s->PutCString(") }");
+#else
+ s->PutCString(" }");
+#endif
+ }
+ }
+ }
+ }
+ break;
+
+ case eSectionTypeDataObjCCFStrings:
+ {
+ Address cfstring_data_addr(*this);
+ cfstring_data_addr.SetOffset(cfstring_data_addr.GetOffset() + (2 * pointer_size));
+ if (ReadAddress (exe_scope, cfstring_data_addr, pointer_size, so_addr))
+ {
+#if VERBOSE_OUTPUT
+ s->PutCString("(CFString *) ");
+ cfstring_data_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+ s->PutCString(" -> @");
+#else
+ s->PutChar('@');
+#endif
+ if (so_addr.Dump(s, exe_scope, DumpStyleResolvedDescription))
+ showed_info = true;
+ }
+ }
+ break;
+
+ case eSectionTypeData4:
+ // Read the 4 byte data and display it
+ showed_info = true;
+ s->PutCString("(uint32_t) ");
+ DumpUInt (exe_scope, *this, 4, s);
+ break;
+
+ case eSectionTypeData8:
+ // Read the 8 byte data and display it
+ showed_info = true;
+ s->PutCString("(uint64_t) ");
+ DumpUInt (exe_scope, *this, 8, s);
+ break;
+
+ case eSectionTypeData16:
+ // Read the 16 byte data and display it
+ showed_info = true;
+ s->PutCString("(uint128_t) ");
+ DumpUInt (exe_scope, *this, 16, s);
+ break;
+
+ case eSectionTypeDataPointers:
+ // Read the pointer data and display it
+ {
+ if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
+ {
+ s->PutCString ("(void *)");
+ so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+
+ showed_info = true;
+ if (so_addr.IsSectionOffset())
+ {
+ SymbolContext pointer_sc;
+ if (target)
+ {
+ target->GetImages().ResolveSymbolContextForAddress (so_addr,
+ eSymbolContextEverything,
+ pointer_sc);
+ if (pointer_sc.function || pointer_sc.symbol)
+ {
+ s->PutCString(": ");
+ pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, false);
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!showed_info)
+ {
+ if (module_sp)
+ {
+ SymbolContext sc;
+ module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc);
+ if (sc.function || sc.symbol)
+ {
+ bool show_stop_context = true;
+ const bool show_module = (style == DumpStyleResolvedDescription);
+ const bool show_fullpaths = false;
+ const bool show_inlined_frames = true;
+ if (sc.function == NULL && sc.symbol != NULL)
+ {
+ // If we have just a symbol make sure it is in the right section
+ if (sc.symbol->ValueIsAddress())
+ {
+ if (sc.symbol->GetAddress().GetSection() != GetSection())
+ {
+ // don't show the module if the symbol is a trampoline symbol
+ show_stop_context = false;
+ }
+ }
+ }
+ if (show_stop_context)
+ {
+ // We have a function or a symbol from the same
+ // sections as this address.
+ sc.DumpStopContext (s,
+ exe_scope,
+ *this,
+ show_fullpaths,
+ show_module,
+ show_inlined_frames);
+ }
+ else
+ {
+ // We found a symbol but it was in a different
+ // section so it isn't the symbol we should be
+ // showing, just show the section name + offset
+ Dump (s, exe_scope, DumpStyleSectionNameOffset);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
+ return false;
+ }
+ break;
+
+ case DumpStyleDetailedSymbolContext:
+ if (IsSectionOffset())
+ {
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ {
+ SymbolContext sc;
+ module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc);
+ if (sc.symbol)
+ {
+ // If we have just a symbol make sure it is in the same section
+ // as our address. If it isn't, then we might have just found
+ // the last symbol that came before the address that we are
+ // looking up that has nothing to do with our address lookup.
+ if (sc.symbol->ValueIsAddress() && sc.symbol->GetAddress().GetSection() != GetSection())
+ sc.symbol = NULL;
+ }
+ sc.GetDescription(s, eDescriptionLevelBrief, target);
+
+ if (sc.block)
+ {
+ bool can_create = true;
+ bool get_parent_variables = true;
+ bool stop_if_block_is_inlined_function = false;
+ VariableList variable_list;
+ sc.block->AppendVariables (can_create,
+ get_parent_variables,
+ stop_if_block_is_inlined_function,
+ &variable_list);
+
+ const size_t num_variables = variable_list.GetSize();
+ for (size_t var_idx = 0; var_idx < num_variables; ++var_idx)
+ {
+ Variable *var = variable_list.GetVariableAtIndex (var_idx).get();
+ if (var && var->LocationIsValidForAddress (*this))
+ {
+ s->Indent();
+ s->Printf (" Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\", type= \"%s\", location =",
+ var->GetID(),
+ var->GetName().GetCString(),
+ var->GetType()->GetName().GetCString());
+ var->DumpLocationForAddress(s, *this);
+ s->PutCString(", decl = ");
+ var->GetDeclaration().DumpStopContext(s, false);
+ s->EOL();
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
+ return false;
+ }
+ break;
+ case DumpStyleResolvedPointerDescription:
+ {
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ addr_t load_addr = GetLoadAddress (target);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ Error memory_error;
+ addr_t dereferenced_load_addr = process->ReadPointerFromMemory(load_addr, memory_error);
+ if (dereferenced_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ Address dereferenced_addr;
+ if (dereferenced_addr.SetLoadAddress(dereferenced_load_addr, target))
+ {
+ StreamString strm;
+ if (dereferenced_addr.Dump (&strm, exe_scope, DumpStyleResolvedDescription, DumpStyleInvalid, addr_size))
+ {
+ s->Address (dereferenced_load_addr, addr_size, " -> ", " ");
+ s->Write(strm.GetData(), strm.GetSize());
+ return true;
+ }
+ }
+ }
+ }
+ }
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
+ return false;
+ }
+ break;
+ }
+
+ return true;
+}
+
+uint32_t
+Address::CalculateSymbolContext (SymbolContext *sc, uint32_t resolve_scope) const
+{
+ sc->Clear(false);
+ // Absolute addresses don't have enough information to reconstruct even their target.
+
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ ModuleSP module_sp (section_sp->GetModule());
+ if (module_sp)
+ {
+ sc->module_sp = module_sp;
+ if (sc->module_sp)
+ return sc->module_sp->ResolveSymbolContextForAddress (*this, resolve_scope, *sc);
+ }
+ }
+ return 0;
+}
+
+ModuleSP
+Address::CalculateSymbolContextModule () const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ return section_sp->GetModule();
+ return ModuleSP();
+}
+
+CompileUnit *
+Address::CalculateSymbolContextCompileUnit () const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ SymbolContext sc;
+ sc.module_sp = section_sp->GetModule();
+ if (sc.module_sp)
+ {
+ sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextCompUnit, sc);
+ return sc.comp_unit;
+ }
+ }
+ return NULL;
+}
+
+Function *
+Address::CalculateSymbolContextFunction () const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ SymbolContext sc;
+ sc.module_sp = section_sp->GetModule();
+ if (sc.module_sp)
+ {
+ sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextFunction, sc);
+ return sc.function;
+ }
+ }
+ return NULL;
+}
+
+Block *
+Address::CalculateSymbolContextBlock () const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ SymbolContext sc;
+ sc.module_sp = section_sp->GetModule();
+ if (sc.module_sp)
+ {
+ sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextBlock, sc);
+ return sc.block;
+ }
+ }
+ return NULL;
+}
+
+Symbol *
+Address::CalculateSymbolContextSymbol () const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ SymbolContext sc;
+ sc.module_sp = section_sp->GetModule();
+ if (sc.module_sp)
+ {
+ sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextSymbol, sc);
+ return sc.symbol;
+ }
+ }
+ return NULL;
+}
+
+bool
+Address::CalculateSymbolContextLineEntry (LineEntry &line_entry) const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ SymbolContext sc;
+ sc.module_sp = section_sp->GetModule();
+ if (sc.module_sp)
+ {
+ sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextLineEntry, sc);
+ if (sc.line_entry.IsValid())
+ {
+ line_entry = sc.line_entry;
+ return true;
+ }
+ }
+ }
+ line_entry.Clear();
+ return false;
+}
+
+int
+Address::CompareFileAddress (const Address& a, const Address& b)
+{
+ addr_t a_file_addr = a.GetFileAddress();
+ addr_t b_file_addr = b.GetFileAddress();
+ if (a_file_addr < b_file_addr)
+ return -1;
+ if (a_file_addr > b_file_addr)
+ return +1;
+ return 0;
+}
+
+
+int
+Address::CompareLoadAddress (const Address& a, const Address& b, Target *target)
+{
+ assert (target != NULL);
+ addr_t a_load_addr = a.GetLoadAddress (target);
+ addr_t b_load_addr = b.GetLoadAddress (target);
+ if (a_load_addr < b_load_addr)
+ return -1;
+ if (a_load_addr > b_load_addr)
+ return +1;
+ return 0;
+}
+
+int
+Address::CompareModulePointerAndOffset (const Address& a, const Address& b)
+{
+ ModuleSP a_module_sp (a.GetModule());
+ ModuleSP b_module_sp (b.GetModule());
+ Module *a_module = a_module_sp.get();
+ Module *b_module = b_module_sp.get();
+ if (a_module < b_module)
+ return -1;
+ if (a_module > b_module)
+ return +1;
+ // Modules are the same, just compare the file address since they should
+ // be unique
+ addr_t a_file_addr = a.GetFileAddress();
+ addr_t b_file_addr = b.GetFileAddress();
+ if (a_file_addr < b_file_addr)
+ return -1;
+ if (a_file_addr > b_file_addr)
+ return +1;
+ return 0;
+}
+
+
+size_t
+Address::MemorySize () const
+{
+ // Noting special for the memory size of a single Address object,
+ // it is just the size of itself.
+ return sizeof(Address);
+}
+
+
+//----------------------------------------------------------------------
+// NOTE: Be careful using this operator. It can correctly compare two
+// addresses from the same Module correctly. It can't compare two
+// addresses from different modules in any meaningful way, but it will
+// compare the module pointers.
+//
+// To sum things up:
+// - works great for addresses within the same module
+// - it works for addresses across multiple modules, but don't expect the
+// address results to make much sense
+//
+// This basically lets Address objects be used in ordered collection
+// classes.
+//----------------------------------------------------------------------
+
+bool
+lldb_private::operator< (const Address& lhs, const Address& rhs)
+{
+ ModuleSP lhs_module_sp (lhs.GetModule());
+ ModuleSP rhs_module_sp (rhs.GetModule());
+ Module *lhs_module = lhs_module_sp.get();
+ Module *rhs_module = rhs_module_sp.get();
+ if (lhs_module == rhs_module)
+ {
+ // Addresses are in the same module, just compare the file addresses
+ return lhs.GetFileAddress() < rhs.GetFileAddress();
+ }
+ else
+ {
+ // The addresses are from different modules, just use the module
+ // pointer value to get consistent ordering
+ return lhs_module < rhs_module;
+ }
+}
+
+bool
+lldb_private::operator> (const Address& lhs, const Address& rhs)
+{
+ ModuleSP lhs_module_sp (lhs.GetModule());
+ ModuleSP rhs_module_sp (rhs.GetModule());
+ Module *lhs_module = lhs_module_sp.get();
+ Module *rhs_module = rhs_module_sp.get();
+ if (lhs_module == rhs_module)
+ {
+ // Addresses are in the same module, just compare the file addresses
+ return lhs.GetFileAddress() > rhs.GetFileAddress();
+ }
+ else
+ {
+ // The addresses are from different modules, just use the module
+ // pointer value to get consistent ordering
+ return lhs_module > rhs_module;
+ }
+}
+
+
+// The operator == checks for exact equality only (same section, same offset)
+bool
+lldb_private::operator== (const Address& a, const Address& rhs)
+{
+ return a.GetOffset() == rhs.GetOffset() &&
+ a.GetSection() == rhs.GetSection();
+}
+// The operator != checks for exact inequality only (differing section, or
+// different offset)
+bool
+lldb_private::operator!= (const Address& a, const Address& rhs)
+{
+ return a.GetOffset() != rhs.GetOffset() ||
+ a.GetSection() != rhs.GetSection();
+}
+
+AddressClass
+Address::GetAddressClass () const
+{
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ {
+ ObjectFile *obj_file = module_sp->GetObjectFile();
+ if (obj_file)
+ {
+ // Give the symbol vendor a chance to add to the unified section list.
+ module_sp->GetSymbolVendor();
+ return obj_file->GetAddressClass (GetFileAddress());
+ }
+ }
+ return eAddressClassUnknown;
+}
+
+bool
+Address::SetLoadAddress (lldb::addr_t load_addr, Target *target)
+{
+ if (target && target->GetSectionLoadList().ResolveLoadAddress(load_addr, *this))
+ return true;
+ m_section_wp.reset();
+ m_offset = load_addr;
+ return false;
+}
+
diff --git a/source/Core/AddressRange.cpp b/source/Core/AddressRange.cpp
new file mode 100644
index 0000000..835a01d
--- /dev/null
+++ b/source/Core/AddressRange.cpp
@@ -0,0 +1,208 @@
+//===-- 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/Core/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+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;
+ // fall through
+ 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());
+ }
+ 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", this, 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;
+//}
diff --git a/source/Core/AddressResolver.cpp b/source/Core/AddressResolver.cpp
new file mode 100644
index 0000000..5369d96
--- /dev/null
+++ b/source/Core/AddressResolver.cpp
@@ -0,0 +1,67 @@
+//===-- 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"
+
+
+// Project includes
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/lldb-private-log.h"
+
+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];
+}
diff --git a/source/Core/AddressResolverFileLine.cpp b/source/Core/AddressResolverFileLine.cpp
new file mode 100644
index 0000000..f7004c8
--- /dev/null
+++ b/source/Core/AddressResolverFileLine.cpp
@@ -0,0 +1,102 @@
+//===-- 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"
+
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/lldb-private-log.h"
+
+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(), m_line_number);
+}
+
+
diff --git a/source/Core/AddressResolverName.cpp b/source/Core/AddressResolverName.cpp
new file mode 100644
index 0000000..dd22e17
--- /dev/null
+++ b/source/Core/AddressResolverName.cpp
@@ -0,0 +1,255 @@
+//===-- 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"
+
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/lldb-private-log.h"
+
+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 (NULL),
+ m_regex (),
+ m_match_type (type)
+{
+ if (m_match_type == AddressResolver::Regexp)
+ {
+ if (!m_regex.Compile (m_func_name.AsCString()))
+ {
+ 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 (NULL),
+ m_class_name (NULL),
+ 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 ()
+{
+}
+
+// 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,
+ NULL,
+ 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 funcion list and the symbol list
+ if (func_list.GetSize())
+ {
+ for (i = 0; i < func_list.GetSize(); i++)
+ {
+ if (func_list.GetContextAtIndex(i, sc) == false)
+ continue;
+
+ if (sc.function == NULL)
+ 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->GetAddress())
+ {
+ 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->GetAddress();
+ 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());
+ else
+ s->Printf("'%s'", m_func_name.AsCString());
+}
+
diff --git a/source/Core/ArchSpec.cpp b/source/Core/ArchSpec.cpp
new file mode 100644
index 0000000..27d62c3
--- /dev/null
+++ b/source/Core/ArchSpec.cpp
@@ -0,0 +1,893 @@
+//===-- ArchSpec.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/ArchSpec.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <string>
+
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MachO.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Platform.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define ARCH_SPEC_SEPARATOR_CHAR '-'
+
+
+static bool cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_inverse, bool enforce_exact_match);
+
+namespace lldb_private {
+
+ struct CoreDefinition
+ {
+ ByteOrder default_byte_order;
+ uint32_t addr_byte_size;
+ uint32_t min_opcode_byte_size;
+ uint32_t max_opcode_byte_size;
+ llvm::Triple::ArchType machine;
+ ArchSpec::Core core;
+ const char *name;
+ };
+
+}
+
+// This core information can be looked using the ArchSpec::Core as the index
+static const CoreDefinition g_core_definitions[ArchSpec::kNumCores] =
+{
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_generic , "arm" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv4 , "armv4" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv4t , "armv4t" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv5 , "armv5" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv5e , "armv5e" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv5t , "armv5t" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv6 , "armv6" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7 , "armv7" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7f , "armv7f" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7s , "armv7s" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7k , "armv7k" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7m , "armv7m" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7em , "armv7em" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_xscale , "xscale" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumb , "thumb" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv4t , "thumbv4t" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv5 , "thumbv5" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv5e , "thumbv5e" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv6 , "thumbv6" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7 , "thumbv7" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7f , "thumbv7f" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7s , "thumbv7s" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7k , "thumbv7k" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7m , "thumbv7m" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7em , "thumbv7em" },
+
+
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_generic , "ppc" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc601 , "ppc601" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc602 , "ppc602" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc603 , "ppc603" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc603e , "ppc603e" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc603ev , "ppc603ev" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc604 , "ppc604" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc604e , "ppc604e" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc620 , "ppc620" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc750 , "ppc750" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc7400 , "ppc7400" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc7450 , "ppc7450" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc970 , "ppc970" },
+
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_generic , "ppc64" },
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_ppc970_64 , "ppc970-64" },
+
+ { eByteOrderLittle, 4, 4, 4, llvm::Triple::sparc , ArchSpec::eCore_sparc_generic , "sparc" },
+ { eByteOrderLittle, 8, 4, 4, llvm::Triple::sparcv9, ArchSpec::eCore_sparc9_generic , "sparcv9" },
+
+ { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i386 , "i386" },
+ { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i486 , "i486" },
+ { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i486sx , "i486sx" },
+
+ { eByteOrderLittle, 8, 1, 15, llvm::Triple::x86_64 , ArchSpec::eCore_x86_64_x86_64 , "x86_64" },
+ { eByteOrderLittle, 4, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach32 , "unknown-mach-32" },
+ { eByteOrderLittle, 8, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach64 , "unknown-mach-64" }
+};
+
+struct ArchDefinitionEntry
+{
+ ArchSpec::Core core;
+ uint32_t cpu;
+ uint32_t sub;
+ uint32_t cpu_mask;
+ uint32_t sub_mask;
+};
+
+struct ArchDefinition
+{
+ ArchitectureType type;
+ size_t num_entries;
+ const ArchDefinitionEntry *entries;
+ const char *name;
+};
+
+
+size_t
+ArchSpec::AutoComplete (const char *name, StringList &matches)
+{
+ uint32_t i;
+ if (name && name[0])
+ {
+ for (i = 0; i < ArchSpec::kNumCores; ++i)
+ {
+ if (NameMatches(g_core_definitions[i].name, eNameMatchStartsWith, name))
+ matches.AppendString (g_core_definitions[i].name);
+ }
+ }
+ else
+ {
+ for (i = 0; i < ArchSpec::kNumCores; ++i)
+ matches.AppendString (g_core_definitions[i].name);
+ }
+ return matches.GetSize();
+}
+
+
+
+#define CPU_ANY (UINT32_MAX)
+
+//===----------------------------------------------------------------------===//
+// A table that gets searched linearly for matches. This table is used to
+// convert cpu type and subtypes to architecture names, and to convert
+// architecture names to cpu types and subtypes. The ordering is important and
+// allows the precedence to be set when the table is built.
+#define SUBTYPE_MASK 0x00FFFFFFu
+static const ArchDefinitionEntry g_macho_arch_entries[] =
+{
+ { ArchSpec::eCore_arm_generic , llvm::MachO::CPUTypeARM , CPU_ANY, UINT32_MAX , UINT32_MAX },
+ { ArchSpec::eCore_arm_generic , llvm::MachO::CPUTypeARM , 0 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv4 , llvm::MachO::CPUTypeARM , 5 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv4t , llvm::MachO::CPUTypeARM , 5 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv6 , llvm::MachO::CPUTypeARM , 6 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv5 , llvm::MachO::CPUTypeARM , 7 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv5e , llvm::MachO::CPUTypeARM , 7 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv5t , llvm::MachO::CPUTypeARM , 7 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_xscale , llvm::MachO::CPUTypeARM , 8 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv7 , llvm::MachO::CPUTypeARM , 9 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv7f , llvm::MachO::CPUTypeARM , 10 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv7s , llvm::MachO::CPUTypeARM , 11 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv7k , llvm::MachO::CPUTypeARM , 12 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv7m , llvm::MachO::CPUTypeARM , 15 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv7em , llvm::MachO::CPUTypeARM , 16 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumb , llvm::MachO::CPUTypeARM , 0 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv4t , llvm::MachO::CPUTypeARM , 5 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv5 , llvm::MachO::CPUTypeARM , 7 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv5e , llvm::MachO::CPUTypeARM , 7 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv6 , llvm::MachO::CPUTypeARM , 6 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv7 , llvm::MachO::CPUTypeARM , 9 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv7f , llvm::MachO::CPUTypeARM , 10 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv7s , llvm::MachO::CPUTypeARM , 11 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv7k , llvm::MachO::CPUTypeARM , 12 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv7m , llvm::MachO::CPUTypeARM , 15 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv7em , llvm::MachO::CPUTypeARM , 16 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_generic , llvm::MachO::CPUTypePowerPC , CPU_ANY, UINT32_MAX , UINT32_MAX },
+ { ArchSpec::eCore_ppc_generic , llvm::MachO::CPUTypePowerPC , 0 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc601 , llvm::MachO::CPUTypePowerPC , 1 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc602 , llvm::MachO::CPUTypePowerPC , 2 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc603 , llvm::MachO::CPUTypePowerPC , 3 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc603e , llvm::MachO::CPUTypePowerPC , 4 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc603ev , llvm::MachO::CPUTypePowerPC , 5 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc604 , llvm::MachO::CPUTypePowerPC , 6 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc604e , llvm::MachO::CPUTypePowerPC , 7 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc620 , llvm::MachO::CPUTypePowerPC , 8 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc750 , llvm::MachO::CPUTypePowerPC , 9 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc7400 , llvm::MachO::CPUTypePowerPC , 10 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc7450 , llvm::MachO::CPUTypePowerPC , 11 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc970 , llvm::MachO::CPUTypePowerPC , 100 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc64_generic , llvm::MachO::CPUTypePowerPC64 , 0 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc64_ppc970_64 , llvm::MachO::CPUTypePowerPC64 , 100 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_x86_32_i386 , llvm::MachO::CPUTypeI386 , 3 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_x86_32_i486 , llvm::MachO::CPUTypeI386 , 4 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_x86_32_i486sx , llvm::MachO::CPUTypeI386 , 0x84 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_x86_32_i386 , llvm::MachO::CPUTypeI386 , CPU_ANY, UINT32_MAX , UINT32_MAX },
+ { ArchSpec::eCore_x86_64_x86_64 , llvm::MachO::CPUTypeX86_64 , 3 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_x86_64_x86_64 , llvm::MachO::CPUTypeX86_64 , 4 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_x86_64_x86_64 , llvm::MachO::CPUTypeX86_64 , CPU_ANY, UINT32_MAX , UINT32_MAX },
+ // Catch any unknown mach architectures so we can always use the object and symbol mach-o files
+ { ArchSpec::eCore_uknownMach32 , 0 , 0 , 0xFF000000u, 0x00000000u },
+ { ArchSpec::eCore_uknownMach64 , llvm::MachO::CPUArchABI64 , 0 , 0xFF000000u, 0x00000000u }
+};
+static const ArchDefinition g_macho_arch_def = {
+ eArchTypeMachO,
+ sizeof(g_macho_arch_entries)/sizeof(g_macho_arch_entries[0]),
+ g_macho_arch_entries,
+ "mach-o"
+};
+
+//===----------------------------------------------------------------------===//
+// A table that gets searched linearly for matches. This table is used to
+// convert cpu type and subtypes to architecture names, and to convert
+// architecture names to cpu types and subtypes. The ordering is important and
+// allows the precedence to be set when the table is built.
+static const ArchDefinitionEntry g_elf_arch_entries[] =
+{
+ { ArchSpec::eCore_sparc_generic , llvm::ELF::EM_SPARC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Sparc
+ { ArchSpec::eCore_x86_32_i386 , llvm::ELF::EM_386 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 80386
+ { ArchSpec::eCore_x86_32_i486 , llvm::ELF::EM_486 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 486 (deprecated)
+ { ArchSpec::eCore_ppc_generic , llvm::ELF::EM_PPC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC
+ { ArchSpec::eCore_ppc64_generic , llvm::ELF::EM_PPC64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC64
+ { ArchSpec::eCore_arm_generic , llvm::ELF::EM_ARM , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM
+ { ArchSpec::eCore_sparc9_generic , llvm::ELF::EM_SPARCV9, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // SPARC V9
+ { ArchSpec::eCore_x86_64_x86_64 , llvm::ELF::EM_X86_64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu } // AMD64
+};
+
+static const ArchDefinition g_elf_arch_def = {
+ eArchTypeELF,
+ sizeof(g_elf_arch_entries)/sizeof(g_elf_arch_entries[0]),
+ g_elf_arch_entries,
+ "elf",
+};
+
+//===----------------------------------------------------------------------===//
+// Table of all ArchDefinitions
+static const ArchDefinition *g_arch_definitions[] = {
+ &g_macho_arch_def,
+ &g_elf_arch_def
+};
+
+static const size_t k_num_arch_definitions =
+ sizeof(g_arch_definitions) / sizeof(g_arch_definitions[0]);
+
+//===----------------------------------------------------------------------===//
+// Static helper functions.
+
+
+// Get the architecture definition for a given object type.
+static const ArchDefinition *
+FindArchDefinition (ArchitectureType arch_type)
+{
+ for (unsigned int i = 0; i < k_num_arch_definitions; ++i)
+ {
+ const ArchDefinition *def = g_arch_definitions[i];
+ if (def->type == arch_type)
+ return def;
+ }
+ return NULL;
+}
+
+// Get an architecture definition by name.
+static const CoreDefinition *
+FindCoreDefinition (llvm::StringRef name)
+{
+ for (unsigned int i = 0; i < ArchSpec::kNumCores; ++i)
+ {
+ if (name.equals_lower(g_core_definitions[i].name))
+ return &g_core_definitions[i];
+ }
+ return NULL;
+}
+
+static inline const CoreDefinition *
+FindCoreDefinition (ArchSpec::Core core)
+{
+ if (core >= 0 && core < ArchSpec::kNumCores)
+ return &g_core_definitions[core];
+ return NULL;
+}
+
+// Get a definition entry by cpu type and subtype.
+static const ArchDefinitionEntry *
+FindArchDefinitionEntry (const ArchDefinition *def, uint32_t cpu, uint32_t sub)
+{
+ if (def == NULL)
+ return NULL;
+
+ const ArchDefinitionEntry *entries = def->entries;
+ for (size_t i = 0; i < def->num_entries; ++i)
+ {
+ if (entries[i].cpu == (cpu & entries[i].cpu_mask))
+ if (entries[i].sub == (sub & entries[i].sub_mask))
+ return &entries[i];
+ }
+ return NULL;
+}
+
+static const ArchDefinitionEntry *
+FindArchDefinitionEntry (const ArchDefinition *def, ArchSpec::Core core)
+{
+ if (def == NULL)
+ return NULL;
+
+ const ArchDefinitionEntry *entries = def->entries;
+ for (size_t i = 0; i < def->num_entries; ++i)
+ {
+ if (entries[i].core == core)
+ return &entries[i];
+ }
+ return NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// Constructors and destructors.
+
+ArchSpec::ArchSpec() :
+ m_triple (),
+ m_core (kCore_invalid),
+ m_byte_order (eByteOrderInvalid)
+{
+}
+
+ArchSpec::ArchSpec (const char *triple_cstr, Platform *platform) :
+ m_triple (),
+ m_core (kCore_invalid),
+ m_byte_order (eByteOrderInvalid)
+{
+ if (triple_cstr)
+ SetTriple(triple_cstr, platform);
+}
+
+
+ArchSpec::ArchSpec (const char *triple_cstr) :
+ m_triple (),
+ m_core (kCore_invalid),
+ m_byte_order (eByteOrderInvalid)
+{
+ if (triple_cstr)
+ SetTriple(triple_cstr);
+}
+
+ArchSpec::ArchSpec(const llvm::Triple &triple) :
+ m_triple (),
+ m_core (kCore_invalid),
+ m_byte_order (eByteOrderInvalid)
+{
+ SetTriple(triple);
+}
+
+ArchSpec::ArchSpec (ArchitectureType arch_type, uint32_t cpu, uint32_t subtype) :
+ m_triple (),
+ m_core (kCore_invalid),
+ m_byte_order (eByteOrderInvalid)
+{
+ SetArchitecture (arch_type, cpu, subtype);
+}
+
+ArchSpec::~ArchSpec()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// Assignment and initialization.
+
+const ArchSpec&
+ArchSpec::operator= (const ArchSpec& rhs)
+{
+ if (this != &rhs)
+ {
+ m_triple = rhs.m_triple;
+ m_core = rhs.m_core;
+ m_byte_order = rhs.m_byte_order;
+ }
+ return *this;
+}
+
+void
+ArchSpec::Clear()
+{
+ m_triple = llvm::Triple();
+ m_core = kCore_invalid;
+ m_byte_order = eByteOrderInvalid;
+}
+
+//===----------------------------------------------------------------------===//
+// Predicates.
+
+
+const char *
+ArchSpec::GetArchitectureName () const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ return core_def->name;
+ return "unknown";
+}
+
+uint32_t
+ArchSpec::GetMachOCPUType () const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ {
+ const ArchDefinitionEntry *arch_def = FindArchDefinitionEntry (&g_macho_arch_def, core_def->core);
+ if (arch_def)
+ {
+ return arch_def->cpu;
+ }
+ }
+ return LLDB_INVALID_CPUTYPE;
+}
+
+uint32_t
+ArchSpec::GetMachOCPUSubType () const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ {
+ const ArchDefinitionEntry *arch_def = FindArchDefinitionEntry (&g_macho_arch_def, core_def->core);
+ if (arch_def)
+ {
+ return arch_def->sub;
+ }
+ }
+ return LLDB_INVALID_CPUTYPE;
+}
+
+llvm::Triple::ArchType
+ArchSpec::GetMachine () const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ return core_def->machine;
+
+ return llvm::Triple::UnknownArch;
+}
+
+uint32_t
+ArchSpec::GetAddressByteSize() const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ return core_def->addr_byte_size;
+ return 0;
+}
+
+ByteOrder
+ArchSpec::GetDefaultEndian () const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ return core_def->default_byte_order;
+ return eByteOrderInvalid;
+}
+
+lldb::ByteOrder
+ArchSpec::GetByteOrder () const
+{
+ if (m_byte_order == eByteOrderInvalid)
+ return GetDefaultEndian();
+ return m_byte_order;
+}
+
+//===----------------------------------------------------------------------===//
+// Mutators.
+
+bool
+ArchSpec::SetTriple (const llvm::Triple &triple)
+{
+ m_triple = triple;
+
+ llvm::StringRef arch_name (m_triple.getArchName());
+ const CoreDefinition *core_def = FindCoreDefinition (arch_name);
+ if (core_def)
+ {
+ m_core = core_def->core;
+ // Set the byte order to the default byte order for an architecture.
+ // This can be modified if needed for cases when cores handle both
+ // big and little endian
+ m_byte_order = core_def->default_byte_order;
+ }
+ else
+ {
+ Clear();
+ }
+
+
+ return IsValid();
+}
+
+static bool
+ParseMachCPUDashSubtypeTriple (const char *triple_cstr, ArchSpec &arch)
+{
+ // Accept "12-10" or "12.10" as cpu type/subtype
+ if (isdigit(triple_cstr[0]))
+ {
+ char *end = NULL;
+ errno = 0;
+ uint32_t cpu = (uint32_t)::strtoul (triple_cstr, &end, 0);
+ if (errno == 0 && cpu != 0 && end && ((*end == '-') || (*end == '.')))
+ {
+ errno = 0;
+ uint32_t sub = (uint32_t)::strtoul (end + 1, &end, 0);
+ if (errno == 0 && end && ((*end == '-') || (*end == '.') || (*end == '\0')))
+ {
+ if (arch.SetArchitecture (eArchTypeMachO, cpu, sub))
+ {
+ if (*end == '-')
+ {
+ llvm::StringRef vendor_os (end + 1);
+ size_t dash_pos = vendor_os.find('-');
+ if (dash_pos != llvm::StringRef::npos)
+ {
+ llvm::StringRef vendor_str(vendor_os.substr(0, dash_pos));
+ arch.GetTriple().setVendorName(vendor_str);
+ const size_t vendor_start_pos = dash_pos+1;
+ dash_pos = vendor_os.find('-', vendor_start_pos);
+ if (dash_pos == llvm::StringRef::npos)
+ {
+ if (vendor_start_pos < vendor_os.size())
+ arch.GetTriple().setOSName(vendor_os.substr(vendor_start_pos));
+ }
+ else
+ {
+ arch.GetTriple().setOSName(vendor_os.substr(vendor_start_pos, dash_pos - vendor_start_pos));
+ }
+ }
+ }
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+bool
+ArchSpec::SetTriple (const char *triple_cstr)
+{
+ if (triple_cstr && triple_cstr[0])
+ {
+ if (ParseMachCPUDashSubtypeTriple (triple_cstr, *this))
+ return true;
+
+ llvm::StringRef triple_stref (triple_cstr);
+ if (triple_stref.startswith (LLDB_ARCH_DEFAULT))
+ {
+ // Special case for the current host default architectures...
+ if (triple_stref.equals (LLDB_ARCH_DEFAULT_32BIT))
+ *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture32);
+ else if (triple_stref.equals (LLDB_ARCH_DEFAULT_64BIT))
+ *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture64);
+ else if (triple_stref.equals (LLDB_ARCH_DEFAULT))
+ *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
+ }
+ else
+ {
+ std::string normalized_triple_sstr (llvm::Triple::normalize(triple_stref));
+ triple_stref = normalized_triple_sstr;
+ SetTriple (llvm::Triple (triple_stref));
+ }
+ }
+ else
+ Clear();
+ return IsValid();
+}
+
+bool
+ArchSpec::SetTriple (const char *triple_cstr, Platform *platform)
+{
+ if (triple_cstr && triple_cstr[0])
+ {
+ if (ParseMachCPUDashSubtypeTriple (triple_cstr, *this))
+ return true;
+
+ llvm::StringRef triple_stref (triple_cstr);
+ if (triple_stref.startswith (LLDB_ARCH_DEFAULT))
+ {
+ // Special case for the current host default architectures...
+ if (triple_stref.equals (LLDB_ARCH_DEFAULT_32BIT))
+ *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture32);
+ else if (triple_stref.equals (LLDB_ARCH_DEFAULT_64BIT))
+ *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture64);
+ else if (triple_stref.equals (LLDB_ARCH_DEFAULT))
+ *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
+ }
+ else
+ {
+ ArchSpec raw_arch (triple_cstr);
+
+ std::string normalized_triple_sstr (llvm::Triple::normalize(triple_stref));
+ triple_stref = normalized_triple_sstr;
+ llvm::Triple normalized_triple (triple_stref);
+
+ const bool os_specified = normalized_triple.getOSName().size() > 0;
+ const bool vendor_specified = normalized_triple.getVendorName().size() > 0;
+ const bool env_specified = normalized_triple.getEnvironmentName().size() > 0;
+
+ // If we got an arch only, then default the vendor, os, environment
+ // to match the platform if one is supplied
+ if (!(os_specified || vendor_specified || env_specified))
+ {
+ if (platform)
+ {
+ // If we were given a platform, use the platform's system
+ // architecture. If this is not available (might not be
+ // connected) use the first supported architecture.
+ ArchSpec compatible_arch;
+ if (platform->IsCompatibleArchitecture (raw_arch, false, &compatible_arch))
+ {
+ if (compatible_arch.IsValid())
+ {
+ const llvm::Triple &compatible_triple = compatible_arch.GetTriple();
+ if (!vendor_specified)
+ normalized_triple.setVendor(compatible_triple.getVendor());
+ if (!os_specified)
+ normalized_triple.setOS(compatible_triple.getOS());
+ if (!env_specified && compatible_triple.getEnvironmentName().size())
+ normalized_triple.setEnvironment(compatible_triple.getEnvironment());
+ }
+ }
+ else
+ {
+ *this = raw_arch;
+ return IsValid();
+ }
+ }
+ else
+ {
+ // No platform specified, fall back to the host system for
+ // the default vendor, os, and environment.
+ llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple());
+ if (!vendor_specified)
+ normalized_triple.setVendor(host_triple.getVendor());
+ if (!vendor_specified)
+ normalized_triple.setOS(host_triple.getOS());
+ if (!env_specified && host_triple.getEnvironmentName().size())
+ normalized_triple.setEnvironment(host_triple.getEnvironment());
+ }
+ }
+ SetTriple (normalized_triple);
+ }
+ }
+ else
+ Clear();
+ return IsValid();
+}
+
+bool
+ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t sub)
+{
+ m_core = kCore_invalid;
+ bool update_triple = true;
+ const ArchDefinition *arch_def = FindArchDefinition(arch_type);
+ if (arch_def)
+ {
+ const ArchDefinitionEntry *arch_def_entry = FindArchDefinitionEntry (arch_def, cpu, sub);
+ if (arch_def_entry)
+ {
+ const CoreDefinition *core_def = FindCoreDefinition (arch_def_entry->core);
+ if (core_def)
+ {
+ m_core = core_def->core;
+ update_triple = false;
+ // Always use the architecture name because it might be more descriptive
+ // than the architecture enum ("armv7" -> llvm::Triple::arm).
+ m_triple.setArchName(llvm::StringRef(core_def->name));
+ if (arch_type == eArchTypeMachO)
+ {
+ m_triple.setVendor (llvm::Triple::Apple);
+
+ switch (core_def->machine)
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ m_triple.setOS (llvm::Triple::IOS);
+ break;
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ default:
+ m_triple.setOS (llvm::Triple::MacOSX);
+ break;
+ }
+ }
+ else
+ {
+ m_triple.setVendor (llvm::Triple::UnknownVendor);
+ m_triple.setOS (llvm::Triple::UnknownOS);
+ }
+ // Fall back onto setting the machine type if the arch by name failed...
+ if (m_triple.getArch () == llvm::Triple::UnknownArch)
+ m_triple.setArch (core_def->machine);
+ }
+ }
+ }
+ CoreUpdated(update_triple);
+ return IsValid();
+}
+
+uint32_t
+ArchSpec::GetMinimumOpcodeByteSize() const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ return core_def->min_opcode_byte_size;
+ return 0;
+}
+
+uint32_t
+ArchSpec::GetMaximumOpcodeByteSize() const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ return core_def->max_opcode_byte_size;
+ return 0;
+}
+
+bool
+ArchSpec::IsExactMatch (const ArchSpec& rhs) const
+{
+ return IsEqualTo (rhs, true);
+}
+
+bool
+ArchSpec::IsCompatibleMatch (const ArchSpec& rhs) const
+{
+ return IsEqualTo (rhs, false);
+}
+
+bool
+ArchSpec::IsEqualTo (const ArchSpec& rhs, bool exact_match) const
+{
+ if (GetByteOrder() != rhs.GetByteOrder())
+ return false;
+
+ const ArchSpec::Core lhs_core = GetCore ();
+ const ArchSpec::Core rhs_core = rhs.GetCore ();
+
+ const bool core_match = cores_match (lhs_core, rhs_core, true, exact_match);
+
+ if (core_match)
+ {
+ const llvm::Triple &lhs_triple = GetTriple();
+ const llvm::Triple &rhs_triple = rhs.GetTriple();
+
+ const llvm::Triple::VendorType lhs_triple_vendor = lhs_triple.getVendor();
+ const llvm::Triple::VendorType rhs_triple_vendor = rhs_triple.getVendor();
+ if (lhs_triple_vendor != rhs_triple_vendor)
+ {
+ if (exact_match)
+ {
+ const bool rhs_vendor_specified = rhs.TripleVendorWasSpecified();
+ const bool lhs_vendor_specified = TripleVendorWasSpecified();
+ // Both architectures had the vendor specified, so if they aren't
+ // equal then we return false
+ if (rhs_vendor_specified && lhs_vendor_specified)
+ return false;
+ }
+
+ // Only fail if both vendor types are not unknown
+ if (lhs_triple_vendor != llvm::Triple::UnknownVendor &&
+ rhs_triple_vendor != llvm::Triple::UnknownVendor)
+ return false;
+ }
+
+ const llvm::Triple::OSType lhs_triple_os = lhs_triple.getOS();
+ const llvm::Triple::OSType rhs_triple_os = rhs_triple.getOS();
+ if (lhs_triple_os != rhs_triple_os)
+ {
+ if (exact_match)
+ {
+ const bool rhs_os_specified = rhs.TripleOSWasSpecified();
+ const bool lhs_os_specified = TripleOSWasSpecified();
+ // Both architectures had the OS specified, so if they aren't
+ // equal then we return false
+ if (rhs_os_specified && lhs_os_specified)
+ return false;
+ }
+ // Only fail if both os types are not unknown
+ if (lhs_triple_os != llvm::Triple::UnknownOS &&
+ rhs_triple_os != llvm::Triple::UnknownOS)
+ return false;
+ }
+
+ const llvm::Triple::EnvironmentType lhs_triple_env = lhs_triple.getEnvironment();
+ const llvm::Triple::EnvironmentType rhs_triple_env = rhs_triple.getEnvironment();
+
+ if (lhs_triple_env != rhs_triple_env)
+ {
+ // Only fail if both environment types are not unknown
+ if (lhs_triple_env != llvm::Triple::UnknownEnvironment &&
+ rhs_triple_env != llvm::Triple::UnknownEnvironment)
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Helper methods.
+
+void
+ArchSpec::CoreUpdated (bool update_triple)
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ {
+ if (update_triple)
+ m_triple = llvm::Triple(core_def->name, "unknown", "unknown");
+ m_byte_order = core_def->default_byte_order;
+ }
+ else
+ {
+ if (update_triple)
+ m_triple = llvm::Triple();
+ m_byte_order = eByteOrderInvalid;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Operators.
+
+static bool
+cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_inverse, bool enforce_exact_match)
+{
+ if (core1 == core2)
+ return true;
+
+ switch (core1)
+ {
+ case ArchSpec::kCore_any:
+ return true;
+
+ case ArchSpec::kCore_arm_any:
+ if (core2 >= ArchSpec::kCore_arm_first && core2 <= ArchSpec::kCore_arm_last)
+ return true;
+ if (core2 >= ArchSpec::kCore_thumb_first && core2 <= ArchSpec::kCore_thumb_last)
+ return true;
+ if (core2 == ArchSpec::kCore_arm_any)
+ return true;
+ break;
+
+ case ArchSpec::kCore_x86_32_any:
+ if ((core2 >= ArchSpec::kCore_x86_32_first && core2 <= ArchSpec::kCore_x86_32_last) || (core2 == ArchSpec::kCore_x86_32_any))
+ return true;
+ break;
+
+ case ArchSpec::kCore_ppc_any:
+ if ((core2 >= ArchSpec::kCore_ppc_first && core2 <= ArchSpec::kCore_ppc_last) || (core2 == ArchSpec::kCore_ppc_any))
+ return true;
+ break;
+
+ case ArchSpec::kCore_ppc64_any:
+ if ((core2 >= ArchSpec::kCore_ppc64_first && core2 <= ArchSpec::kCore_ppc64_last) || (core2 == ArchSpec::kCore_ppc64_any))
+ return true;
+ break;
+
+ case ArchSpec::eCore_arm_armv7m:
+ case ArchSpec::eCore_arm_armv7em:
+ case ArchSpec::eCore_arm_armv7f:
+ case ArchSpec::eCore_arm_armv7k:
+ case ArchSpec::eCore_arm_armv7s:
+ if (!enforce_exact_match)
+ {
+ try_inverse = false;
+ if (core2 == ArchSpec::eCore_arm_armv7)
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (try_inverse)
+ return cores_match (core2, core1, false, enforce_exact_match);
+ return false;
+}
+
+bool
+lldb_private::operator<(const ArchSpec& lhs, const ArchSpec& rhs)
+{
+ const ArchSpec::Core lhs_core = lhs.GetCore ();
+ const ArchSpec::Core rhs_core = rhs.GetCore ();
+ return lhs_core < rhs_core;
+}
diff --git a/source/Core/Baton.cpp b/source/Core/Baton.cpp
new file mode 100644
index 0000000..8bed01b
--- /dev/null
+++ b/source/Core/Baton.cpp
@@ -0,0 +1,24 @@
+//===-- Baton.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/Baton.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+Baton::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+}
diff --git a/source/Core/Broadcaster.cpp b/source/Core/Broadcaster.cpp
new file mode 100644
index 0000000..5af7497
--- /dev/null
+++ b/source/Core/Broadcaster.cpp
@@ -0,0 +1,499 @@
+//===-- 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"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Broadcaster::Broadcaster (BroadcasterManager *manager, const char *name) :
+ m_broadcaster_name (name),
+ m_listeners (),
+ m_listeners_mutex (Mutex::eMutexTypeRecursive),
+ m_hijacking_listeners(),
+ m_hijacking_masks(),
+ m_manager (manager)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Broadcaster::Broadcaster(\"%s\")", this, m_broadcaster_name.AsCString());
+
+}
+
+Broadcaster::~Broadcaster()
+{
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Broadcaster::~Broadcaster(\"%s\")", this, m_broadcaster_name.AsCString());
+
+ Clear();
+}
+
+void
+Broadcaster::CheckInWithManager ()
+{
+ if (m_manager != NULL)
+ {
+ m_manager->SignUpListenersForBroadcaster(*this);
+ }
+}
+
+void
+Broadcaster::Clear()
+{
+ Mutex::Locker listeners_locker(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.
+
+ collection::iterator pos, end = m_listeners.end();
+ for (pos = m_listeners.begin(); pos != end; ++pos)
+ pos->first->BroadcasterWillDestruct (this);
+
+ m_listeners.clear();
+}
+const ConstString &
+Broadcaster::GetBroadcasterName ()
+{
+ return m_broadcaster_name;
+}
+
+bool
+Broadcaster::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 (m_broadcaster_name.GetCString());
+ s.PutChar('.');
+ }
+ s.PutCString(pos->second.c_str());
+ ++num_names_added;
+ }
+ }
+ }
+ }
+ return num_names_added > 0;
+}
+
+void
+Broadcaster::AddInitialEventsToListener (Listener *listener, uint32_t requested_events)
+{
+
+}
+
+uint32_t
+Broadcaster::AddListener (Listener* listener, uint32_t event_mask)
+{
+ if (listener == NULL)
+ return 0;
+
+ Mutex::Locker locker(m_listeners_mutex);
+ collection::iterator pos, end = m_listeners.end();
+
+ collection::iterator existing_pos = end;
+ // See if we already have this listener, and if so, update its mask
+ uint32_t taken_event_types = 0;
+ for (pos = m_listeners.begin(); pos != end; ++pos)
+ {
+ if (pos->first == listener)
+ existing_pos = pos;
+ // For now don't descriminate on who gets what
+ // FIXME: Implement "unique listener for this bit" mask
+ // taken_event_types |= pos->second;
+ }
+
+ // Each event bit in a Broadcaster object can only be used
+ // by one listener
+ uint32_t available_event_types = ~taken_event_types & event_mask;
+
+ if (available_event_types)
+ {
+ // If we didn't find our listener, add it
+ if (existing_pos == end)
+ {
+ // Grant a new listener the available event bits
+ m_listeners.push_back(std::make_pair(listener, available_event_types));
+ }
+ else
+ {
+ // Grant the existing listener the available event bits
+ existing_pos->second |= available_event_types;
+ }
+
+ // Individual broadcasters decide whether they have outstanding data when a
+ // listener attaches, and insert it into the listener with this method.
+
+ AddInitialEventsToListener (listener, available_event_types);
+ }
+
+ // Return the event bits that were granted to the listener
+ return available_event_types;
+}
+
+bool
+Broadcaster::EventTypeHasListeners (uint32_t event_type)
+{
+ Mutex::Locker locker (m_listeners_mutex);
+
+ if (m_hijacking_listeners.size() > 0 && event_type & m_hijacking_masks.back())
+ return true;
+
+ if (m_listeners.empty())
+ return false;
+
+ collection::iterator pos, end = m_listeners.end();
+ for (pos = m_listeners.begin(); pos != end; ++pos)
+ {
+ if (pos->second & event_type)
+ return true;
+ }
+ return false;
+}
+
+bool
+Broadcaster::RemoveListener (Listener* listener, uint32_t event_mask)
+{
+ Mutex::Locker locker(m_listeners_mutex);
+ collection::iterator pos, end = m_listeners.end();
+ // See if we already have this listener, and if so, update its mask
+ for (pos = m_listeners.begin(); pos != end; ++pos)
+ {
+ if (pos->first == listener)
+ {
+ // Relinquish all event bits in "event_mask"
+ pos->second &= ~event_mask;
+ // If all bits have been relinquished then remove this listener
+ if (pos->second == 0)
+ m_listeners.erase (pos);
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+Broadcaster::BroadcastEvent (EventSP &event_sp)
+{
+ return PrivateBroadcastEvent (event_sp, false);
+}
+
+void
+Broadcaster::BroadcastEventIfUnique (EventSP &event_sp)
+{
+ return PrivateBroadcastEvent (event_sp, true);
+}
+
+void
+Broadcaster::PrivateBroadcastEvent (EventSP &event_sp, bool unique)
+{
+ // Can't add a NULL event...
+ if (event_sp.get() == NULL)
+ return;
+
+ // Update the broadcaster on this event
+ event_sp->SetBroadcaster (this);
+
+ const uint32_t event_type = event_sp->GetType();
+
+ Mutex::Locker event_types_locker(m_listeners_mutex);
+
+ Listener *hijacking_listener = NULL;
+ if (!m_hijacking_listeners.empty())
+ {
+ assert (!m_hijacking_masks.empty());
+ hijacking_listener = m_hijacking_listeners.back();
+ if ((event_type & m_hijacking_masks.back()) == 0)
+ hijacking_listener = NULL;
+ }
+
+ 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",
+ this,
+ m_broadcaster_name.AsCString(""),
+ event_description.GetData(),
+ unique,
+ hijacking_listener);
+ }
+
+ if (hijacking_listener)
+ {
+ if (unique && hijacking_listener->PeekAtNextEventForBroadcasterWithType (this, event_type))
+ return;
+ hijacking_listener->AddEvent (event_sp);
+ }
+ else
+ {
+ collection::iterator pos, end = m_listeners.end();
+
+
+ // Iterate through all listener/mask pairs
+ for (pos = m_listeners.begin(); pos != end; ++pos)
+ {
+ // If the listener's mask matches any bits that we just set, then
+ // put the new event on its event queue.
+ if (event_type & pos->second)
+ {
+ if (unique && pos->first->PeekAtNextEventForBroadcasterWithType (this, event_type))
+ continue;
+ pos->first->AddEvent (event_sp);
+ }
+ }
+ }
+}
+
+void
+Broadcaster::BroadcastEvent (uint32_t event_type, EventData *event_data)
+{
+ EventSP event_sp (new Event (event_type, event_data));
+ PrivateBroadcastEvent (event_sp, false);
+}
+
+void
+Broadcaster::BroadcastEventIfUnique (uint32_t event_type, EventData *event_data)
+{
+ EventSP event_sp (new Event (event_type, event_data));
+ PrivateBroadcastEvent (event_sp, true);
+}
+
+bool
+Broadcaster::HijackBroadcaster (Listener *listener, uint32_t event_mask)
+{
+ Mutex::Locker event_types_locker(m_listeners_mutex);
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EVENTS));
+ if (log)
+ {
+ log->Printf ("%p Broadcaster(\"%s\")::HijackBroadcaster (listener(\"%s\")=%p)",
+ this,
+ m_broadcaster_name.AsCString(""),
+ listener->m_name.c_str(),
+ listener);
+ }
+ m_hijacking_listeners.push_back(listener);
+ m_hijacking_masks.push_back(event_mask);
+ return true;
+}
+
+void
+Broadcaster::RestoreBroadcaster ()
+{
+ Mutex::Locker event_types_locker(m_listeners_mutex);
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EVENTS));
+ if (log)
+ {
+ Listener *listener = m_hijacking_listeners.back();
+ log->Printf ("%p Broadcaster(\"%s\")::RestoreBroadcaster (about to pop listener(\"%s\")=%p)",
+ this,
+ m_broadcaster_name.AsCString(""),
+ listener->m_name.c_str(),
+ listener);
+ }
+ m_hijacking_listeners.pop_back();
+ m_hijacking_masks.pop_back();
+}
+
+ConstString &
+Broadcaster::GetBroadcasterClass() const
+{
+ static ConstString class_name ("lldb.anonymous");
+ return class_name;
+}
+
+BroadcastEventSpec::BroadcastEventSpec (const BroadcastEventSpec &rhs) :
+ m_broadcaster_class (rhs.m_broadcaster_class),
+ m_event_bits (rhs.m_event_bits)
+{
+}
+
+bool
+BroadcastEventSpec::operator< (const BroadcastEventSpec &rhs) const
+{
+ if (GetBroadcasterClass() == rhs.GetBroadcasterClass())
+ {
+ return GetEventBits() < rhs.GetEventBits();
+ }
+ else
+ {
+ return GetBroadcasterClass() < rhs.GetBroadcasterClass();
+ }
+}
+
+const BroadcastEventSpec &
+BroadcastEventSpec::operator= (const BroadcastEventSpec &rhs)
+{
+ m_broadcaster_class = rhs.m_broadcaster_class;
+ m_event_bits = rhs.m_event_bits;
+ return *this;
+}
+
+BroadcasterManager::BroadcasterManager() :
+ m_manager_mutex(Mutex::eMutexTypeRecursive)
+{
+
+}
+
+uint32_t
+BroadcasterManager::RegisterListenerForEvents (Listener &listener, BroadcastEventSpec event_spec)
+{
+ Mutex::Locker locker(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));
+ m_listeners.insert(&listener);
+ }
+
+ return available_bits;
+}
+
+bool
+BroadcasterManager::UnregisterListenerForEvents (Listener &listener, BroadcastEventSpec event_spec)
+{
+ Mutex::Locker locker(m_manager_mutex);
+ bool removed_some = false;
+
+ if (m_listeners.erase(&listener) == 0)
+ return false;
+
+ ListenerMatchesAndSharedBits predicate (event_spec, listener);
+ 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 (1)
+ {
+ 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));
+ }
+
+ return removed_some;
+}
+
+Listener *
+BroadcasterManager::GetListenerForEventSpec (BroadcastEventSpec event_spec) const
+{
+ Mutex::Locker locker(*(const_cast<Mutex *> (&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 NULL;
+}
+
+void
+BroadcasterManager::RemoveListener (Listener &listener)
+{
+ Mutex::Locker locker(m_manager_mutex);
+ ListenerMatches predicate (listener);
+
+
+ if (m_listeners.erase (&listener) == 0)
+ return;
+
+ while (1)
+ {
+ 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)
+{
+ Mutex::Locker locker(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 ()
+{
+ Mutex::Locker locker(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);
+ m_listeners.clear();
+ m_event_map.clear();
+
+}
diff --git a/source/Core/Communication.cpp b/source/Core/Communication.cpp
new file mode 100644
index 0000000..7f40e65
--- /dev/null
+++ b/source/Core/Communication.cpp
@@ -0,0 +1,431 @@
+//===-- Communication.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Connection.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Host/Host.h"
+#include <string.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+ConstString &
+Communication::GetStaticBroadcasterClass ()
+{
+ static ConstString class_name ("lldb.communication");
+ return class_name;
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+Communication::Communication(const char *name) :
+ Broadcaster (NULL, name),
+ m_connection_sp (),
+ m_read_thread (LLDB_INVALID_HOST_THREAD),
+ m_read_thread_enabled (false),
+ m_bytes(),
+ m_bytes_mutex (Mutex::eMutexTypeRecursive),
+ m_write_mutex (Mutex::eMutexTypeNormal),
+ m_callback (NULL),
+ m_callback_baton (NULL),
+ 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");
+
+ CheckInWithManager();
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Communication::~Communication()
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::~Communication (name = %s)",
+ this, m_broadcaster_name.AsCString(""));
+ Clear();
+}
+
+void
+Communication::Clear()
+{
+ SetReadThreadBytesReceivedCallback (NULL, NULL);
+ Disconnect (NULL);
+ StopReadThread (NULL);
+}
+
+ConnectionStatus
+Communication::Connect (const char *url, Error *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.get())
+ return connection_sp->Connect (url, error_ptr);
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid connection.");
+ return eConnectionStatusNoConnection;
+}
+
+ConnectionStatus
+Communication::Disconnect (Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::Disconnect ()", this);
+
+ lldb::ConnectionSP connection_sp (m_connection_sp);
+ if (connection_sp.get())
+ {
+ 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);
+ if (connection_sp.get())
+ return connection_sp->IsConnected ();
+ return false;
+}
+
+bool
+Communication::HasConnection () const
+{
+ return m_connection_sp.get() != NULL;
+}
+
+size_t
+Communication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::Read (dst = %p, dst_len = %" PRIu64 ", timeout = %u usec) connection = %p",
+ this,
+ dst,
+ (uint64_t)dst_len,
+ timeout_usec,
+ 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_usec == 0)
+ {
+ status = eConnectionStatusSuccess;
+ return cached_bytes;
+ }
+
+ if (m_connection_sp.get() == NULL)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid connection.");
+ status = eConnectionStatusNoConnection;
+ return 0;
+ }
+ // Set the timeout appropriately
+ TimeValue timeout_time;
+ if (timeout_usec != UINT32_MAX)
+ {
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithMicroSeconds (timeout_usec);
+ }
+
+ Listener listener ("Communication::Read");
+ listener.StartListeningForEvents (this, eBroadcastBitReadThreadGotBytes | eBroadcastBitReadThreadDidExit);
+ EventSP event_sp;
+ while (listener.WaitForEvent (timeout_time.IsValid() ? &timeout_time : NULL, event_sp))
+ {
+ const uint32_t event_type = event_sp->GetType();
+ if (event_type & eBroadcastBitReadThreadGotBytes)
+ {
+ return GetCachedBytes (dst, dst_len);
+ }
+
+ if (event_type & eBroadcastBitReadThreadDidExit)
+ {
+ Disconnect (NULL);
+ break;
+ }
+ }
+ return 0;
+ }
+
+ // We aren't using a read thread, just read the data synchronously in this
+ // thread.
+ lldb::ConnectionSP connection_sp (m_connection_sp);
+ if (connection_sp.get())
+ {
+ return connection_sp->Read (dst, dst_len, timeout_usec, status, error_ptr);
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid connection.");
+ status = eConnectionStatusNoConnection;
+ return 0;
+}
+
+
+size_t
+Communication::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
+{
+ lldb::ConnectionSP connection_sp (m_connection_sp);
+
+ Mutex::Locker locker(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.get())
+ 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 (Error *error_ptr)
+{
+ if (error_ptr)
+ error_ptr->Clear();
+
+ if (IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ 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>", m_broadcaster_name.AsCString());
+
+ m_read_thread_enabled = true;
+ m_read_thread = Host::ThreadCreate (thread_name, Communication::ReadThread, this, error_ptr);
+ if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ m_read_thread_enabled = false;
+ return m_read_thread_enabled;
+}
+
+bool
+Communication::StopReadThread (Error *error_ptr)
+{
+ if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ return true;
+
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::StopReadThread ()", this);
+
+ m_read_thread_enabled = false;
+
+ BroadcastEvent (eBroadcastBitReadThreadShouldExit, NULL);
+
+ //Host::ThreadCancel (m_read_thread, error_ptr);
+
+ bool status = Host::ThreadJoin (m_read_thread, NULL, error_ptr);
+ m_read_thread = LLDB_INVALID_HOST_THREAD;
+ return status;
+}
+
+
+size_t
+Communication::GetCachedBytes (void *dst, size_t dst_len)
+{
+ Mutex::Locker locker(m_bytes_mutex);
+ if (m_bytes.size() > 0)
+ {
+ // If DST is NULL and we have a thread, then return the number
+ // of bytes that are available so the caller can call again
+ if (dst == NULL)
+ 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 == NULL || 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 != NULL && len > 0)
+ {
+ Mutex::Locker locker(m_bytes_mutex);
+ m_bytes.append ((const char *)bytes, len);
+ if (broadcast)
+ BroadcastEventIfUnique (eBroadcastBitReadThreadGotBytes);
+ }
+}
+
+size_t
+Communication::ReadFromConnection (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ ConnectionStatus &status,
+ Error *error_ptr)
+{
+ lldb::ConnectionSP connection_sp (m_connection_sp);
+ if (connection_sp.get())
+ return connection_sp->Read (dst, dst_len, timeout_usec, status, error_ptr);
+ return 0;
+}
+
+bool
+Communication::ReadThreadIsRunning ()
+{
+ return m_read_thread_enabled;
+}
+
+void *
+Communication::ReadThread (void *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];
+
+ Error error;
+ ConnectionStatus status = eConnectionStatusSuccess;
+ bool done = false;
+ while (!done && comm->m_read_thread_enabled)
+ {
+ size_t bytes_read = comm->ReadFromConnection (buf, sizeof(buf), 5 * TimeValue::MicroSecPerSec, 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:
+ if (comm->GetCloseOnEOF())
+ done = true;
+ break;
+ case eConnectionStatusNoConnection: // No connection
+ case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
+ done = true;
+ // Fall through...
+ case eConnectionStatusError: // Check GetError() for details
+ case eConnectionStatusTimedOut: // Request timed out
+ if (log)
+ error.LogIfError (log,
+ "%p Communication::ReadFromConnection () => status = %s",
+ p,
+ Communication::ConnectionStatusAsCString (status));
+ break;
+ }
+ }
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION);
+ if (log)
+ log->Printf ("%p Communication::ReadThread () thread exiting...", p);
+
+ // Let clients know that this thread is exiting
+ comm->BroadcastEvent (eBroadcastBitReadThreadDidExit);
+ return NULL;
+}
+
+void
+Communication::SetReadThreadBytesReceivedCallback
+(
+ ReadThreadBytesReceived callback,
+ void *callback_baton
+)
+{
+ m_callback = callback;
+ m_callback_baton = callback_baton;
+}
+
+void
+Communication::SetConnection (Connection *connection)
+{
+ Disconnect (NULL);
+ StopReadThread(NULL);
+ 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";
+ }
+
+ static char unknown_state_string[64];
+ snprintf(unknown_state_string, sizeof (unknown_state_string), "ConnectionStatus = %i", status);
+ return unknown_state_string;
+}
diff --git a/source/Core/Connection.cpp b/source/Core/Connection.cpp
new file mode 100644
index 0000000..3c9bb8b
--- /dev/null
+++ b/source/Core/Connection.cpp
@@ -0,0 +1,24 @@
+//===-- Connection.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Connection.h"
+
+using namespace lldb_private;
+
+Connection::Connection ()
+{
+}
+
+Connection::~Connection ()
+{
+}
diff --git a/source/Core/ConnectionFileDescriptor.cpp b/source/Core/ConnectionFileDescriptor.cpp
new file mode 100644
index 0000000..e320bda
--- /dev/null
+++ b/source/Core/ConnectionFileDescriptor.cpp
@@ -0,0 +1,1528 @@
+//===-- ConnectionFileDescriptor.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+// Enable this special support for Apple builds where we can have unlimited
+// select bounds. We tried switching to poll() and kqueue and we were panicing
+// the kernel, so we have to stick with select for now.
+#define _DARWIN_UNLIMITED_SELECT
+#endif
+
+#include "lldb/Core/ConnectionFileDescriptor.h"
+
+// C Includes
+#include <errno.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#if defined(__APPLE__)
+#include "llvm/ADT/SmallVector.h"
+#endif
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Timer.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static bool
+DecodeHostAndPort (const char *host_and_port,
+ std::string &host_str,
+ std::string &port_str,
+ int32_t& port,
+ Error *error_ptr)
+{
+ static RegularExpression g_regex ("([^:]+):([0-9]+)");
+ RegularExpression::Match regex_match(2);
+ if (g_regex.Execute (host_and_port, &regex_match))
+ {
+ if (regex_match.GetMatchAtIndex (host_and_port, 1, host_str) &&
+ regex_match.GetMatchAtIndex (host_and_port, 2, port_str))
+ {
+ port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN);
+ if (port != INT32_MIN)
+ {
+ if (error_ptr)
+ error_ptr->Clear();
+ return true;
+ }
+ }
+ }
+ host_str.clear();
+ port_str.clear();
+ port = INT32_MIN;
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port);
+ return false;
+}
+
+ConnectionFileDescriptor::ConnectionFileDescriptor () :
+ Connection(),
+ m_fd_send (-1),
+ m_fd_recv (-1),
+ m_fd_send_type (eFDTypeFile),
+ m_fd_recv_type (eFDTypeFile),
+ m_udp_send_sockaddr (),
+ m_should_close_fd (false),
+ m_socket_timeout_usec(0),
+ m_pipe_read(-1),
+ m_pipe_write(-1),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_shutting_down (false)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", this);
+}
+
+ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) :
+ Connection(),
+ m_fd_send (fd),
+ m_fd_recv (fd),
+ m_fd_send_type (eFDTypeFile),
+ m_fd_recv_type (eFDTypeFile),
+ m_udp_send_sockaddr (),
+ m_should_close_fd (owns_fd),
+ m_socket_timeout_usec(0),
+ m_pipe_read(-1),
+ m_pipe_write(-1),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_shutting_down (false)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", this, fd, owns_fd);
+ OpenCommandPipe ();
+}
+
+
+ConnectionFileDescriptor::~ConnectionFileDescriptor ()
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", this);
+ Disconnect (NULL);
+ CloseCommandPipe ();
+}
+
+void
+ConnectionFileDescriptor::OpenCommandPipe ()
+{
+ CloseCommandPipe();
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ // Make the command file descriptor here:
+ int filedes[2];
+ int result = pipe (filedes);
+ if (result != 0)
+ {
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor () - could not make pipe: %s",
+ this,
+ strerror(errno));
+ }
+ else
+ {
+ m_pipe_read = filedes[0];
+ m_pipe_write = filedes[1];
+ }
+}
+
+void
+ConnectionFileDescriptor::CloseCommandPipe ()
+{
+ if (m_pipe_read != -1)
+ {
+ close (m_pipe_read);
+ m_pipe_read = -1;
+ }
+
+ if (m_pipe_write != -1)
+ {
+ close (m_pipe_write);
+ m_pipe_write = -1;
+ }
+}
+
+bool
+ConnectionFileDescriptor::IsConnected () const
+{
+ return m_fd_send >= 0 || m_fd_recv >= 0;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
+{
+ Mutex::Locker locker (m_mutex);
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Connect (url = '%s')", this, s);
+
+ OpenCommandPipe();
+
+ if (s && s[0])
+ {
+ char *end = NULL;
+ if (strstr(s, "listen://"))
+ {
+ // listen://HOST:PORT
+ unsigned long listen_port = ::strtoul(s + strlen("listen://"), &end, 0);
+ return SocketListen (listen_port, error_ptr);
+ }
+ else if (strstr(s, "unix-accept://"))
+ {
+ // unix://SOCKNAME
+ return NamedSocketAccept (s + strlen("unix-accept://"), error_ptr);
+ }
+ else if (strstr(s, "connect://"))
+ {
+ return ConnectTCP (s + strlen("connect://"), error_ptr);
+ }
+ else if (strstr(s, "tcp-connect://"))
+ {
+ return ConnectTCP (s + strlen("tcp-connect://"), error_ptr);
+ }
+ else if (strstr(s, "udp://"))
+ {
+ return ConnectUDP (s + strlen("udp://"), error_ptr);
+ }
+ else if (strstr(s, "fd://"))
+ {
+ // Just passing a native file descriptor within this current process
+ // that is already opened (possibly from a service or other source).
+ s += strlen ("fd://");
+ bool success = false;
+ m_fd_send = m_fd_recv = Args::StringToSInt32 (s, -1, 0, &success);
+
+ if (success)
+ {
+ // We have what looks to be a valid file descriptor, but we
+ // should make sure it is. We currently are doing this by trying to
+ // get the flags from the file descriptor and making sure it
+ // isn't a bad fd.
+ errno = 0;
+ int flags = ::fcntl (m_fd_send, F_GETFL, 0);
+ if (flags == -1 || errno == EBADF)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("stale file descriptor: %s", s);
+ m_fd_send = m_fd_recv = -1;
+ return eConnectionStatusError;
+ }
+ else
+ {
+ // Try and get a socket option from this file descriptor to
+ // see if this is a socket and set m_is_socket accordingly.
+ int resuse;
+ bool is_socket = GetSocketOption (m_fd_send, SOL_SOCKET, SO_REUSEADDR, resuse) == 0;
+ if (is_socket)
+ m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
+ // Don't take ownership of a file descriptor that gets passed
+ // to us since someone else opened the file descriptor and
+ // handed it to us.
+ // TODO: Since are using a URL to open connection we should
+ // eventually parse options using the web standard where we
+ // have "fd://123?opt1=value;opt2=value" and we can have an
+ // option be "owns=1" or "owns=0" or something like this to
+ // allow us to specify this. For now, we assume we must
+ // assume we don't own it.
+ m_should_close_fd = false;
+ return eConnectionStatusSuccess;
+ }
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("invalid file descriptor: \"fd://%s\"", s);
+ m_fd_send = m_fd_recv = -1;
+ return eConnectionStatusError;
+ }
+ else if (strstr(s, "file://"))
+ {
+ // file:///PATH
+ const char *path = s + strlen("file://");
+ do
+ {
+ m_fd_send = m_fd_recv = ::open (path, O_RDWR);
+ } while (m_fd_send == -1 && errno == EINTR);
+ if (m_fd_send == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ if (::isatty(m_fd_send))
+ {
+ // Set up serial terminal emulation
+ struct termios options;
+ ::tcgetattr (m_fd_send, &options);
+
+ // Set port speed to maximum
+ ::cfsetospeed (&options, B115200);
+ ::cfsetispeed (&options, B115200);
+
+ // Raw input, disable echo and signals
+ options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+
+ // Make sure only one character is needed to return from a read
+ options.c_cc[VMIN] = 1;
+ options.c_cc[VTIME] = 0;
+
+ ::tcsetattr (m_fd_send, TCSANOW, &options);
+ }
+
+ int flags = ::fcntl (m_fd_send, F_GETFL, 0);
+ if (flags >= 0)
+ {
+ if ((flags & O_NONBLOCK) == 0)
+ {
+ flags |= O_NONBLOCK;
+ ::fcntl (m_fd_send, F_SETFL, flags);
+ }
+ }
+ m_should_close_fd = true;
+ return eConnectionStatusSuccess;
+ }
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s);
+ return eConnectionStatusError;
+ }
+ if (error_ptr)
+ error_ptr->SetErrorString("invalid connect arguments");
+ return eConnectionStatusError;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::Disconnect (Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Disconnect ()", this);
+
+ ConnectionStatus status = eConnectionStatusSuccess;
+
+ if (m_fd_send < 0 && m_fd_recv < 0)
+ {
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect", this);
+ return eConnectionStatusSuccess;
+ }
+
+ // Try to get the ConnectionFileDescriptor's mutex. If we fail, that is quite likely
+ // because somebody is doing a blocking read on our file descriptor. If that's the case,
+ // then send the "q" char to the command file channel so the read will wake up and the connection
+ // will then know to shut down.
+
+ m_shutting_down = true;
+
+ Mutex::Locker locker;
+ bool got_lock= locker.TryLock (m_mutex);
+
+ if (!got_lock)
+ {
+ if (m_pipe_write != -1 )
+ {
+ write (m_pipe_write, "q", 1);
+ close (m_pipe_write);
+ m_pipe_write = -1;
+ }
+ locker.Lock (m_mutex);
+ }
+
+ if (m_should_close_fd == true)
+ {
+ if (m_fd_send == m_fd_recv)
+ {
+ status = Close (m_fd_send, error_ptr);
+ }
+ else
+ {
+ // File descriptors are the different, close both if needed
+ if (m_fd_send >= 0)
+ status = Close (m_fd_send, error_ptr);
+ if (m_fd_recv >= 0)
+ {
+ ConnectionStatus recv_status = Close (m_fd_recv, error_ptr);
+ if (status == eConnectionStatusSuccess)
+ status = recv_status;
+ }
+ }
+ }
+
+ // Now set all our descriptors to invalid values.
+
+ m_fd_send = m_fd_recv = -1;
+
+ if (status != eConnectionStatusSuccess)
+ {
+
+ return status;
+ }
+
+ m_shutting_down = false;
+ return eConnectionStatusSuccess;
+}
+
+size_t
+ConnectionFileDescriptor::Read (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ ConnectionStatus &status,
+ Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %" PRIu64 ")...",
+ this, m_fd_recv, dst, (uint64_t)dst_len);
+
+ Mutex::Locker locker;
+ bool got_lock = locker.TryLock (m_mutex);
+ if (!got_lock)
+ {
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Read () failed to get the connection lock.",
+ this);
+ if (error_ptr)
+ error_ptr->SetErrorString ("failed to get the connection lock for read.");
+
+ status = eConnectionStatusTimedOut;
+ return 0;
+ }
+ else if (m_shutting_down)
+ return eConnectionStatusError;
+
+ ssize_t bytes_read = 0;
+
+ status = BytesAvailable (timeout_usec, error_ptr);
+ if (status == eConnectionStatusSuccess)
+ {
+ do
+ {
+ bytes_read = ::read (m_fd_recv, dst, dst_len);
+ } while (bytes_read < 0 && errno == EINTR);
+ }
+
+ if (status != eConnectionStatusSuccess)
+ return 0;
+
+ Error error;
+ if (bytes_read == 0)
+ {
+ error.Clear(); // End-of-file. Do not automatically close; pass along for the end-of-file handlers.
+ status = eConnectionStatusEndOfFile;
+ }
+ else if (bytes_read < 0)
+ {
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ error.Clear();
+ }
+
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %" PRIu64 ") => %" PRIi64 ", error = %s",
+ this,
+ m_fd_recv,
+ dst,
+ (uint64_t)dst_len,
+ (int64_t)bytes_read,
+ error.AsCString());
+
+ if (error_ptr)
+ *error_ptr = error;
+
+ if (error.Fail())
+ {
+ uint32_t error_value = error.GetError();
+ switch (error_value)
+ {
+ case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read.
+ if (m_fd_recv_type == eFDTypeSocket || m_fd_recv_type == eFDTypeSocketUDP)
+ status = eConnectionStatusTimedOut;
+ else
+ status = eConnectionStatusSuccess;
+ return 0;
+
+ case EFAULT: // Buf points outside the allocated address space.
+ case EINTR: // A read from a slow device was interrupted before any data arrived by the delivery of a signal.
+ case EINVAL: // The pointer associated with fildes was negative.
+ case EIO: // An I/O error occurred while reading from the file system.
+ // The process group is orphaned.
+ // The file is a regular file, nbyte is greater than 0,
+ // the starting position is before the end-of-file, and
+ // the starting position is greater than or equal to the
+ // offset maximum established for the open file
+ // descriptor associated with fildes.
+ case EISDIR: // An attempt is made to read a directory.
+ case ENOBUFS: // An attempt to allocate a memory buffer fails.
+ case ENOMEM: // Insufficient memory is available.
+ status = eConnectionStatusError;
+ break; // Break to close....
+
+ case ENOENT: // no such file or directory
+ case EBADF: // fildes is not a valid file or socket descriptor open for reading.
+ case ENXIO: // An action is requested of a device that does not exist..
+ // A requested action cannot be performed by the device.
+ case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket.
+ case ENOTCONN: // A read is attempted on an unconnected socket.
+ status = eConnectionStatusLostConnection;
+ break; // Break to close....
+
+ case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket.
+ status = eConnectionStatusTimedOut;
+ return 0;
+ }
+
+ return 0;
+ }
+ return bytes_read;
+}
+
+size_t
+ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", this, src, (uint64_t)src_len);
+
+ if (!IsConnected ())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("not connected");
+ status = eConnectionStatusNoConnection;
+ return 0;
+ }
+
+
+ Error error;
+
+ ssize_t bytes_sent = 0;
+
+ switch (m_fd_send_type)
+ {
+ case eFDTypeFile: // Other FD requireing read/write
+ do
+ {
+ bytes_sent = ::write (m_fd_send, src, src_len);
+ } while (bytes_sent < 0 && errno == EINTR);
+ break;
+
+ case eFDTypeSocket: // Socket requiring send/recv
+ do
+ {
+ bytes_sent = ::send (m_fd_send, src, src_len, 0);
+ } while (bytes_sent < 0 && errno == EINTR);
+ break;
+
+ case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom
+ assert (m_udp_send_sockaddr.GetFamily() != 0);
+ do
+ {
+ bytes_sent = ::sendto (m_fd_send,
+ src,
+ src_len,
+ 0,
+ m_udp_send_sockaddr,
+ m_udp_send_sockaddr.GetLength());
+ } while (bytes_sent < 0 && errno == EINTR);
+ break;
+ }
+
+ if (bytes_sent < 0)
+ error.SetErrorToErrno ();
+ else
+ error.Clear ();
+
+ if (log)
+ {
+ switch (m_fd_send_type)
+ {
+ case eFDTypeFile: // Other FD requireing read/write
+ log->Printf ("%p ConnectionFileDescriptor::Write() ::write (fd = %i, src = %p, src_len = %" PRIu64 ") => %" PRIi64 " (error = %s)",
+ this,
+ m_fd_send,
+ src,
+ (uint64_t)src_len,
+ (int64_t)bytes_sent,
+ error.AsCString());
+ break;
+
+ case eFDTypeSocket: // Socket requiring send/recv
+ log->Printf ("%p ConnectionFileDescriptor::Write() ::send (socket = %i, src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)",
+ this,
+ m_fd_send,
+ src,
+ (uint64_t)src_len,
+ (int64_t)bytes_sent,
+ error.AsCString());
+ break;
+
+ case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom
+ log->Printf ("%p ConnectionFileDescriptor::Write() ::sendto (socket = %i, src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)",
+ this,
+ m_fd_send,
+ src,
+ (uint64_t)src_len,
+ (int64_t)bytes_sent,
+ error.AsCString());
+ break;
+ }
+ }
+
+ if (error_ptr)
+ *error_ptr = error;
+
+ if (error.Fail())
+ {
+ switch (error.GetError())
+ {
+ case EAGAIN:
+ case EINTR:
+ status = eConnectionStatusSuccess;
+ return 0;
+
+ case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket.
+ case ENOTCONN: // A read is attempted on an unconnected socket.
+ status = eConnectionStatusLostConnection;
+ break; // Break to close....
+
+ default:
+ status = eConnectionStatusError;
+ break; // Break to close....
+ }
+
+ return 0;
+ }
+
+ status = eConnectionStatusSuccess;
+ return bytes_sent;
+}
+
+
+
+#if defined(__APPLE__)
+
+// This ConnectionFileDescriptor::BytesAvailable() uses select().
+//
+// PROS:
+// - select is consistent across most unix platforms
+// - this Apple specific version allows for unlimited fds in the fd_sets by
+// setting the _DARWIN_UNLIMITED_SELECT define prior to including the
+// required header files.
+
+// CONS:
+// - Darwin only
+
+ConnectionStatus
+ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ // Don't need to take the mutex here separately since we are only called from Read. If we
+ // ever get used more generally we will need to lock here as well.
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
+ struct timeval *tv_ptr;
+ struct timeval tv;
+ if (timeout_usec == UINT32_MAX)
+ {
+ // Infinite wait...
+ tv_ptr = NULL;
+ }
+ else
+ {
+ TimeValue time_value;
+ time_value.OffsetWithMicroSeconds (timeout_usec);
+ tv = time_value.GetAsTimeVal();
+ tv_ptr = &tv;
+ }
+
+ // Make a copy of the file descriptors to make sure we don't
+ // have another thread change these values out from under us
+ // and cause problems in the loop below where like in FS_SET()
+ const int data_fd = m_fd_recv;
+ const int pipe_fd = m_pipe_read;
+
+ if (data_fd >= 0)
+ {
+ const bool have_pipe_fd = pipe_fd >= 0;
+
+ while (data_fd == m_fd_recv)
+ {
+ const int nfds = std::max<int>(data_fd, pipe_fd) + 1;
+ llvm::SmallVector<fd_set, 1> read_fds;
+ read_fds.resize((nfds/FD_SETSIZE) + 1);
+ for (size_t i=0; i<read_fds.size(); ++i)
+ FD_ZERO (&read_fds[i]);
+ // FD_SET doesn't bounds check, it just happily walks off the end
+ // but we have taken care of making the extra storage with our
+ // SmallVector of fd_set objects
+ FD_SET (data_fd, read_fds.data());
+ if (have_pipe_fd)
+ FD_SET (pipe_fd, read_fds.data());
+
+ Error error;
+
+ if (log)
+ {
+ if (have_pipe_fd)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...",
+ this, nfds, data_fd, pipe_fd, tv_ptr);
+ else
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...",
+ this, nfds, data_fd, tv_ptr);
+ }
+
+ const int num_set_fds = ::select (nfds, read_fds.data(), NULL, NULL, tv_ptr);
+ if (num_set_fds < 0)
+ error.SetErrorToErrno();
+ else
+ error.Clear();
+
+ if (log)
+ {
+ if (have_pipe_fd)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) => %d, error = %s",
+ this, nfds, data_fd, pipe_fd, tv_ptr, num_set_fds, error.AsCString());
+ else
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => %d, error = %s",
+ this, nfds, data_fd, tv_ptr, num_set_fds, error.AsCString());
+ }
+
+ if (error_ptr)
+ *error_ptr = error;
+
+ if (error.Fail())
+ {
+ switch (error.GetError())
+ {
+ case EBADF: // One of the descriptor sets specified an invalid descriptor.
+ return eConnectionStatusLostConnection;
+
+ case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
+ default: // Other unknown error
+ return eConnectionStatusError;
+
+ case EAGAIN: // The kernel was (perhaps temporarily) unable to
+ // allocate the requested number of file descriptors,
+ // or we have non-blocking IO
+ case EINTR: // A signal was delivered before the time limit
+ // expired and before any of the selected events
+ // occurred.
+ break; // Lets keep reading to until we timeout
+ }
+ }
+ else if (num_set_fds == 0)
+ {
+ return eConnectionStatusTimedOut;
+ }
+ else if (num_set_fds > 0)
+ {
+ // FD_ISSET is happy to deal with a something larger than
+ // a single fd_set.
+ if (FD_ISSET(data_fd, read_fds.data()))
+ return eConnectionStatusSuccess;
+ if (have_pipe_fd && FD_ISSET(pipe_fd, read_fds.data()))
+ {
+ // We got a command to exit. Read the data from that pipe:
+ char buffer[16];
+ ssize_t bytes_read;
+
+ do
+ {
+ bytes_read = ::read (pipe_fd, buffer, sizeof(buffer));
+ } while (bytes_read < 0 && errno == EINTR);
+ assert (bytes_read == 1 && buffer[0] == 'q');
+
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
+ this, (int) bytes_read, buffer);
+
+ return eConnectionStatusEndOfFile;
+ }
+ }
+ }
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorString("not connected");
+ return eConnectionStatusLostConnection;
+}
+
+#else
+
+// This ConnectionFileDescriptor::BytesAvailable() uses select().
+//
+// PROS:
+// - select is consistent across most unix platforms
+// CONS:
+// - only supports file descriptors up to FD_SETSIZE. This implementation
+// will assert if it runs into that hard limit to let users know that
+// another ConnectionFileDescriptor::BytesAvailable() should be used
+// or a new version of ConnectionFileDescriptor::BytesAvailable() should
+// be written for the system that is running into the limitations. MacOSX
+// uses kqueues, and there is a poll() based implementation below.
+
+ConnectionStatus
+ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ // Don't need to take the mutex here separately since we are only called from Read. If we
+ // ever get used more generally we will need to lock here as well.
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
+ struct timeval *tv_ptr;
+ struct timeval tv;
+ if (timeout_usec == UINT32_MAX)
+ {
+ // Infinite wait...
+ tv_ptr = NULL;
+ }
+ else
+ {
+ TimeValue time_value;
+ time_value.OffsetWithMicroSeconds (timeout_usec);
+ tv = time_value.GetAsTimeVal();
+ tv_ptr = &tv;
+ }
+
+ // Make a copy of the file descriptors to make sure we don't
+ // have another thread change these values out from under us
+ // and cause problems in the loop below where like in FS_SET()
+ const int data_fd = m_fd_recv;
+ const int pipe_fd = m_pipe_read;
+
+ if (data_fd >= 0)
+ {
+ // If this assert fires off on MacOSX, we will need to switch to using
+ // libdispatch to read from file descriptors because poll() is causing
+ // kernel panics and if we exceed FD_SETSIZE we will have no choice...
+ assert (data_fd < FD_SETSIZE);
+
+ const bool have_pipe_fd = pipe_fd >= 0;
+
+ if (have_pipe_fd)
+ {
+ assert (pipe_fd < FD_SETSIZE);
+ }
+
+ while (data_fd == m_fd_recv)
+ {
+ fd_set read_fds;
+ FD_ZERO (&read_fds);
+ FD_SET (data_fd, &read_fds);
+ if (have_pipe_fd)
+ FD_SET (pipe_fd, &read_fds);
+
+ const int nfds = std::max<int>(data_fd, pipe_fd) + 1;
+
+ Error error;
+
+ if (log)
+ {
+ if (have_pipe_fd)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...",
+ this, nfds, data_fd, pipe_fd, tv_ptr);
+ else
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...",
+ this, nfds, data_fd, tv_ptr);
+ }
+
+ const int num_set_fds = ::select (nfds, &read_fds, NULL, NULL, tv_ptr);
+ if (num_set_fds < 0)
+ error.SetErrorToErrno();
+ else
+ error.Clear();
+
+ if (log)
+ {
+ if (have_pipe_fd)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) => %d, error = %s",
+ this, nfds, data_fd, pipe_fd, tv_ptr, num_set_fds, error.AsCString());
+ else
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => %d, error = %s",
+ this, nfds, data_fd, tv_ptr, num_set_fds, error.AsCString());
+ }
+
+ if (error_ptr)
+ *error_ptr = error;
+
+ if (error.Fail())
+ {
+ switch (error.GetError())
+ {
+ case EBADF: // One of the descriptor sets specified an invalid descriptor.
+ return eConnectionStatusLostConnection;
+
+ case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
+ default: // Other unknown error
+ return eConnectionStatusError;
+
+ case EAGAIN: // The kernel was (perhaps temporarily) unable to
+ // allocate the requested number of file descriptors,
+ // or we have non-blocking IO
+ case EINTR: // A signal was delivered before the time limit
+ // expired and before any of the selected events
+ // occurred.
+ break; // Lets keep reading to until we timeout
+ }
+ }
+ else if (num_set_fds == 0)
+ {
+ return eConnectionStatusTimedOut;
+ }
+ else if (num_set_fds > 0)
+ {
+ if (FD_ISSET(data_fd, &read_fds))
+ return eConnectionStatusSuccess;
+ if (have_pipe_fd && FD_ISSET(pipe_fd, &read_fds))
+ {
+ // We got a command to exit. Read the data from that pipe:
+ char buffer[16];
+ ssize_t bytes_read;
+
+ do
+ {
+ bytes_read = ::read (pipe_fd, buffer, sizeof(buffer));
+ } while (bytes_read < 0 && errno == EINTR);
+ assert (bytes_read == 1 && buffer[0] == 'q');
+
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
+ this, (int) bytes_read, buffer);
+
+ return eConnectionStatusEndOfFile;
+ }
+ }
+ }
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorString("not connected");
+ return eConnectionStatusLostConnection;
+}
+
+#endif
+
+#if 0
+#include <poll.h>
+
+// This ConnectionFileDescriptor::BytesAvailable() uses poll(). poll() should NOT
+// be used on MacOSX as it has all sorts of restrictions on the types of file descriptors
+// that it doesn't support.
+//
+// There may be some systems that properly support poll() that could use this
+// implementation. I will let each system opt into this on their own.
+//
+// PROS:
+// - no restrictions on the fd value that is used
+// CONS:
+// - varies wildly from platform to platform in its implementation restrictions
+
+ConnectionStatus
+ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ // Don't need to take the mutex here separately since we are only called from Read. If we
+ // ever get used more generally we will need to lock here as well.
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
+ int timeout_msec = 0;
+ if (timeout_usec == UINT32_MAX)
+ {
+ // Infinite wait...
+ timeout_msec = -1;
+ }
+ else if (timeout_usec == 0)
+ {
+ // Return immediately, don't wait
+ timeout_msec = 0;
+ }
+ else
+ {
+ // Convert usec to msec
+ timeout_msec = (timeout_usec + 999) / 1000;
+ }
+
+ // Make a copy of the file descriptors to make sure we don't
+ // have another thread change these values out from under us
+ // and cause problems in the loop below where like in FS_SET()
+ const int data_fd = m_fd_recv;
+ const int pipe_fd = m_pipe_read;
+
+ // Make sure the file descriptor can be used with select as it
+ // must be in range
+ if (data_fd >= 0)
+ {
+ const bool have_pipe_fd = pipe_fd >= 0;
+ struct pollfd fds[2] =
+ {
+ { data_fd, POLLIN, 0 },
+ { pipe_fd, POLLIN, 0 }
+ };
+ const int nfds = have_pipe_fd ? 2 : 1;
+ Error error;
+ while (data_fd == m_fd_recv)
+ {
+ const int num_set_fds = ::poll (fds, nfds, timeout_msec);
+
+ if (num_set_fds < 0)
+ error.SetErrorToErrno();
+ else
+ error.Clear();
+
+ if (error_ptr)
+ *error_ptr = error;
+
+ if (log)
+ {
+ if (have_pipe_fd)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::poll (fds={{%i,POLLIN},{%i,POLLIN}}, nfds=%i, timeout_ms=%i) => %d, error = %s\n",
+ this,
+ data_fd,
+ pipe_fd,
+ nfds,
+ timeout_msec,
+ num_set_fds,
+ error.AsCString());
+ else
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::poll (fds={{%i,POLLIN}}, nfds=%i, timeout_ms=%i) => %d, error = %s\n",
+ this,
+ data_fd,
+ nfds,
+ timeout_msec,
+ num_set_fds,
+ error.AsCString());
+ }
+
+ if (error.Fail())
+ {
+ switch (error.GetError())
+ {
+ case EBADF: // One of the descriptor sets specified an invalid descriptor.
+ return eConnectionStatusLostConnection;
+
+ case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
+ default: // Other unknown error
+ return eConnectionStatusError;
+
+ case EAGAIN: // The kernel was (perhaps temporarily) unable to
+ // allocate the requested number of file descriptors,
+ // or we have non-blocking IO
+ case EINTR: // A signal was delivered before the time limit
+ // expired and before any of the selected events
+ // occurred.
+ break; // Lets keep reading to until we timeout
+ }
+ }
+ else if (num_set_fds == 0)
+ {
+ return eConnectionStatusTimedOut;
+ }
+ else if (num_set_fds > 0)
+ {
+ if (fds[0].revents & POLLIN)
+ return eConnectionStatusSuccess;
+ if (fds[1].revents & POLLIN)
+ {
+ // We got a command to exit. Read the data from that pipe:
+ char buffer[16];
+ ssize_t bytes_read;
+
+ do
+ {
+ bytes_read = ::read (pipe_fd, buffer, sizeof(buffer));
+ } while (bytes_read < 0 && errno == EINTR);
+ assert (bytes_read == 1 && buffer[0] == 'q');
+
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
+ this, (int) bytes_read, buffer);
+
+ return eConnectionStatusEndOfFile;
+ }
+ }
+ }
+ }
+ if (error_ptr)
+ error_ptr->SetErrorString("not connected");
+ return eConnectionStatusLostConnection;
+}
+
+#endif
+
+ConnectionStatus
+ConnectionFileDescriptor::Close (int& fd, Error *error_ptr)
+{
+ if (error_ptr)
+ error_ptr->Clear();
+ bool success = true;
+ // Avoid taking a lock if we can
+ if (fd >= 0)
+ {
+ Mutex::Locker locker (m_mutex);
+ // Check the FD after the lock is taken to ensure only one thread
+ // can get into the close scope below
+ if (fd >= 0)
+ {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Close (fd = %i)", this,fd);
+
+ success = ::close (fd) == 0;
+ // A reference to a FD was passed in, set it to an invalid value
+ fd = -1;
+ if (!success && error_ptr)
+ {
+ // Only set the error if we have been asked to since something else
+ // might have caused us to try and shut down the connection and may
+ // have already set the error.
+ error_ptr->SetErrorToErrno();
+ }
+ }
+ }
+ if (success)
+ return eConnectionStatusSuccess;
+ else
+ return eConnectionStatusError;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *error_ptr)
+{
+ ConnectionStatus result = eConnectionStatusError;
+ struct sockaddr_un saddr_un;
+
+ m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
+
+ int listen_socket = ::socket (AF_UNIX, SOCK_STREAM, 0);
+ if (listen_socket == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ saddr_un.sun_family = AF_UNIX;
+ ::strncpy(saddr_un.sun_path, socket_name, sizeof(saddr_un.sun_path) - 1);
+ saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
+#if defined(__APPLE__) || defined(__FreeBSD__)
+ saddr_un.sun_len = SUN_LEN (&saddr_un);
+#endif
+
+ if (::bind (listen_socket, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0)
+ {
+ if (::listen (listen_socket, 5) == 0)
+ {
+ m_fd_send = m_fd_recv = ::accept (listen_socket, NULL, 0);
+ if (m_fd_send > 0)
+ {
+ m_should_close_fd = true;
+
+ if (error_ptr)
+ error_ptr->Clear();
+ result = eConnectionStatusSuccess;
+ }
+ }
+ }
+
+ if (result != eConnectionStatusSuccess)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ }
+ // We are done with the listen port
+ Close (listen_socket, NULL);
+ return result;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *error_ptr)
+{
+ Disconnect (NULL);
+ m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
+
+ // Open the socket that was passed in as an option
+ struct sockaddr_un saddr_un;
+ m_fd_send = m_fd_recv = ::socket (AF_UNIX, SOCK_STREAM, 0);
+ if (m_fd_send == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ saddr_un.sun_family = AF_UNIX;
+ ::strncpy(saddr_un.sun_path, socket_name, sizeof(saddr_un.sun_path) - 1);
+ saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
+#if defined(__APPLE__) || defined(__FreeBSD__)
+ saddr_un.sun_len = SUN_LEN (&saddr_un);
+#endif
+
+ if (::connect (m_fd_send, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Disconnect (NULL);
+ return eConnectionStatusError;
+ }
+ if (error_ptr)
+ error_ptr->Clear();
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::SocketListen (port = %i)", this, listen_port_num);
+
+ Disconnect (NULL);
+ m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
+ int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (listen_port == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ // enable local address reuse
+ SetSocketOption (listen_port, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ SocketAddress localhost;
+ if (localhost.SetToLocalhost (AF_INET, listen_port_num))
+ {
+ int err = ::bind (listen_port, localhost, localhost.GetLength());
+ if (err == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Close (listen_port, NULL);
+ return eConnectionStatusError;
+ }
+
+ err = ::listen (listen_port, 1);
+ if (err == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Close (listen_port, NULL);
+ return eConnectionStatusError;
+ }
+
+ m_fd_send = m_fd_recv = ::accept (listen_port, NULL, 0);
+ if (m_fd_send == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Close (listen_port, NULL);
+ return eConnectionStatusError;
+ }
+ }
+
+ // We are done with the listen port
+ Close (listen_port, NULL);
+
+ m_should_close_fd = true;
+
+ // Keep our TCP packets coming without any delays.
+ SetSocketOption (m_fd_send, IPPROTO_TCP, TCP_NODELAY, 1);
+ if (error_ptr)
+ error_ptr->Clear();
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::ConnectTCP (const char *host_and_port, Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::ConnectTCP (host/port = %s)", this, host_and_port);
+ Disconnect (NULL);
+
+ m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
+ std::string host_str;
+ std::string port_str;
+ int32_t port = INT32_MIN;
+ if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr))
+ return eConnectionStatusError;
+
+ // Create the socket
+ m_fd_send = m_fd_recv = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (m_fd_send == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ m_should_close_fd = true;
+
+ // Enable local address reuse
+ SetSocketOption (m_fd_send, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ struct sockaddr_in sa;
+ ::memset (&sa, 0, sizeof (sa));
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons (port);
+
+ int inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr);
+
+ if (inet_pton_result <= 0)
+ {
+ struct hostent *host_entry = gethostbyname (host_str.c_str());
+ if (host_entry)
+ host_str = ::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list);
+ inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr);
+ if (inet_pton_result <= 0)
+ {
+
+ if (error_ptr)
+ {
+ if (inet_pton_result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str());
+ }
+ Disconnect (NULL);
+
+ return eConnectionStatusError;
+ }
+ }
+
+ if (-1 == ::connect (m_fd_send, (const struct sockaddr *)&sa, sizeof(sa)))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Disconnect (NULL);
+
+ return eConnectionStatusError;
+ }
+
+ // Keep our TCP packets coming without any delays.
+ SetSocketOption (m_fd_send, IPPROTO_TCP, TCP_NODELAY, 1);
+ if (error_ptr)
+ error_ptr->Clear();
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::ConnectUDP (const char *host_and_port, Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::ConnectUDP (host/port = %s)", this, host_and_port);
+ Disconnect (NULL);
+
+ m_fd_send_type = m_fd_recv_type = eFDTypeSocketUDP;
+
+ std::string host_str;
+ std::string port_str;
+ int32_t port = INT32_MIN;
+ if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr))
+ return eConnectionStatusError;
+
+ // Setup the receiving end of the UDP connection on this localhost
+ // on port zero. After we bind to port zero we can read the port.
+ m_fd_recv = ::socket (AF_INET, SOCK_DGRAM, 0);
+ if (m_fd_recv == -1)
+ {
+ // Socket creation failed...
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ }
+ else
+ {
+ // Socket was created, now lets bind to the requested port
+ SocketAddress addr;
+ addr.SetToLocalhost (AF_INET, 0);
+
+ if (::bind (m_fd_recv, addr, addr.GetLength()) == -1)
+ {
+ // Bind failed...
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Disconnect (NULL);
+ }
+ }
+
+ if (m_fd_recv == -1)
+ return eConnectionStatusError;
+
+ // At this point we have setup the recieve port, now we need to
+ // setup the UDP send socket
+
+ struct addrinfo hints;
+ struct addrinfo *service_info_list = NULL;
+
+ ::memset (&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ int err = ::getaddrinfo (host_str.c_str(), port_str.c_str(), &hints, &service_info_list);
+ if (err != 0)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)",
+ host_str.c_str(),
+ port_str.c_str(),
+ err,
+ gai_strerror(err));
+ Disconnect (NULL);
+ return eConnectionStatusError;
+ }
+
+ for (struct addrinfo *service_info_ptr = service_info_list;
+ service_info_ptr != NULL;
+ service_info_ptr = service_info_ptr->ai_next)
+ {
+ m_fd_send = ::socket (service_info_ptr->ai_family,
+ service_info_ptr->ai_socktype,
+ service_info_ptr->ai_protocol);
+
+ if (m_fd_send != -1)
+ {
+ m_udp_send_sockaddr = service_info_ptr;
+ break;
+ }
+ else
+ continue;
+ }
+
+ :: freeaddrinfo (service_info_list);
+
+ if (m_fd_send == -1)
+ {
+ Disconnect (NULL);
+ return eConnectionStatusError;
+ }
+
+ if (error_ptr)
+ error_ptr->Clear();
+
+ m_should_close_fd = true;
+ return eConnectionStatusSuccess;
+}
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+typedef const char * set_socket_option_arg_type;
+typedef char * get_socket_option_arg_type;
+#else // #if defined(__MINGW32__) || defined(__MINGW64__)
+typedef const void * set_socket_option_arg_type;
+typedef void * get_socket_option_arg_type;
+#endif // #if defined(__MINGW32__) || defined(__MINGW64__)
+
+int
+ConnectionFileDescriptor::GetSocketOption(int fd, int level, int option_name, int &option_value)
+{
+ get_socket_option_arg_type option_value_p = static_cast<get_socket_option_arg_type>(&option_value);
+ socklen_t option_value_size = sizeof(int);
+ return ::getsockopt(fd, level, option_name, option_value_p, &option_value_size);
+}
+
+int
+ConnectionFileDescriptor::SetSocketOption(int fd, int level, int option_name, int option_value)
+{
+ set_socket_option_arg_type option_value_p = static_cast<get_socket_option_arg_type>(&option_value);
+ return ::setsockopt(fd, level, option_name, option_value_p, sizeof(option_value));
+}
+
+bool
+ConnectionFileDescriptor::SetSocketReceiveTimeout (uint32_t timeout_usec)
+{
+ switch (m_fd_recv_type)
+ {
+ case eFDTypeFile: // Other FD requireing read/write
+ break;
+
+ case eFDTypeSocket: // Socket requiring send/recv
+ case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom
+ {
+ // Check in case timeout for m_fd has already been set to this value
+ if (timeout_usec == m_socket_timeout_usec)
+ return true;
+ //printf ("ConnectionFileDescriptor::SetSocketReceiveTimeout (timeout_usec = %u)\n", timeout_usec);
+
+ struct timeval timeout;
+ if (timeout_usec == UINT32_MAX)
+ {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ }
+ else if (timeout_usec == 0)
+ {
+ // Sending in zero does an infinite timeout, so set this as low
+ // as we can go to get an effective zero timeout...
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 1;
+ }
+ else
+ {
+ timeout.tv_sec = timeout_usec / TimeValue::MicroSecPerSec;
+ timeout.tv_usec = timeout_usec % TimeValue::MicroSecPerSec;
+ }
+ if (::setsockopt (m_fd_recv, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == 0)
+ {
+ m_socket_timeout_usec = timeout_usec;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+in_port_t
+ConnectionFileDescriptor::GetSocketPort (int fd)
+{
+ // We bound to port zero, so we need to figure out which port we actually bound to
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength ();
+ if (::getsockname (fd, sock_addr, &sock_addr_len) == 0)
+ return sock_addr.GetPort ();
+
+ return 0;
+}
+
+// If the read file descriptor is a socket, then return
+// the port number that is being used by the socket.
+in_port_t
+ConnectionFileDescriptor::GetReadPort () const
+{
+ return ConnectionFileDescriptor::GetSocketPort (m_fd_recv);
+}
+
+// If the write file descriptor is a socket, then return
+// the port number that is being used by the socket.
+in_port_t
+ConnectionFileDescriptor::GetWritePort () const
+{
+ return ConnectionFileDescriptor::GetSocketPort (m_fd_send);
+}
+
+
diff --git a/source/Core/ConnectionMachPort.cpp b/source/Core/ConnectionMachPort.cpp
new file mode 100644
index 0000000..ca818d4
--- /dev/null
+++ b/source/Core/ConnectionMachPort.cpp
@@ -0,0 +1,323 @@
+//===-- ConnectionMachPort.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#if defined(__APPLE__)
+
+#include "lldb/Core/ConnectionMachPort.h"
+
+// C Includes
+#include <servers/bootstrap.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+struct MessageType
+{
+ mach_msg_header_t head;
+ ConnectionMachPort::PayloadType payload;
+};
+
+
+
+ConnectionMachPort::ConnectionMachPort () :
+ Connection(),
+ m_task(mach_task_self()),
+ m_port(MACH_PORT_TYPE_NONE)
+{
+}
+
+ConnectionMachPort::~ConnectionMachPort ()
+{
+ Disconnect (NULL);
+}
+
+bool
+ConnectionMachPort::IsConnected () const
+{
+ return m_port != MACH_PORT_TYPE_NONE;
+}
+
+ConnectionStatus
+ConnectionMachPort::Connect (const char *s, Error *error_ptr)
+{
+ if (IsConnected())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("already connected");
+ return eConnectionStatusError;
+ }
+
+ if (s == NULL || s[0] == '\0')
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("empty connect URL");
+ return eConnectionStatusError;
+ }
+
+ ConnectionStatus status = eConnectionStatusError;
+
+ if (strncmp (s, "bootstrap-checkin://", strlen("bootstrap-checkin://")))
+ {
+ s += strlen("bootstrap-checkin://");
+
+ if (*s)
+ {
+ status = BootstrapCheckIn (s, error_ptr);
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("bootstrap port name is empty");
+ }
+ }
+ else if (strncmp (s, "bootstrap-lookup://", strlen("bootstrap-lookup://")))
+ {
+ s += strlen("bootstrap-lookup://");
+ if (*s)
+ {
+ status = BootstrapLookup (s, error_ptr);
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("bootstrap port name is empty");
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s);
+ }
+
+
+ if (status == eConnectionStatusSuccess)
+ {
+ if (error_ptr)
+ error_ptr->Clear();
+ }
+ else
+ {
+ Disconnect(NULL);
+ }
+
+ return status;
+}
+
+ConnectionStatus
+ConnectionMachPort::BootstrapCheckIn (const char *port, Error *error_ptr)
+{
+ mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE;
+
+ /* Getting bootstrap server port */
+ kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
+ if (kret == KERN_SUCCESS)
+ {
+ name_t port_name;
+ int len = snprintf(port_name, sizeof(port_name), "%s", port);
+ if (len < sizeof(port_name))
+ {
+ kret = ::bootstrap_check_in (bootstrap_port,
+ port_name,
+ &m_port);
+ }
+ else
+ {
+ Disconnect(NULL);
+ if (error_ptr)
+ error_ptr->SetErrorString ("bootstrap is too long");
+ return eConnectionStatusError;
+ }
+ }
+
+ if (kret != KERN_SUCCESS)
+ {
+ Disconnect(NULL);
+ if (error_ptr)
+ error_ptr->SetError (kret, eErrorTypeMachKernel);
+ return eConnectionStatusError;
+ }
+ return eConnectionStatusSuccess;
+}
+
+lldb::ConnectionStatus
+ConnectionMachPort::BootstrapLookup (const char *port,
+ Error *error_ptr)
+{
+ name_t port_name;
+
+ if (port && port[0])
+ {
+ if (::snprintf (port_name, sizeof (port_name), "%s", port) >= sizeof (port_name))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("port netname is too long");
+ return eConnectionStatusError;
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("empty port netname");
+ return eConnectionStatusError;
+ }
+
+ mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE;
+
+ /* Getting bootstrap server port */
+ kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
+ if (kret == KERN_SUCCESS)
+ {
+ kret = ::bootstrap_look_up (bootstrap_port,
+ port_name,
+ &m_port);
+ }
+
+ if (kret != KERN_SUCCESS)
+ {
+ if (error_ptr)
+ error_ptr->SetError (kret, eErrorTypeMachKernel);
+ return eConnectionStatusError;
+ }
+
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionMachPort::Disconnect (Error *error_ptr)
+{
+ kern_return_t kret;
+
+ // TODO: verify if we need to netname_check_out for
+ // either or both
+ if (m_port != MACH_PORT_TYPE_NONE)
+ {
+ kret = ::mach_port_deallocate (m_task, m_port);
+ if (error_ptr)
+ error_ptr->SetError (kret, eErrorTypeMachKernel);
+ m_port = MACH_PORT_TYPE_NONE;
+ }
+
+ return eConnectionStatusSuccess;
+}
+
+size_t
+ConnectionMachPort::Read (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ ConnectionStatus &status,
+ Error *error_ptr)
+{
+ PayloadType payload;
+
+ kern_return_t kret = Receive (payload);
+ if (kret == KERN_SUCCESS)
+ {
+ memcpy (dst, payload.data, payload.data_length);
+ status = eConnectionStatusSuccess;
+ return payload.data_length;
+ }
+
+ if (error_ptr)
+ error_ptr->SetError (kret, eErrorTypeMachKernel);
+ status = eConnectionStatusError;
+ return 0;
+}
+
+size_t
+ConnectionMachPort::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
+{
+ PayloadType payload;
+ payload.command = 0;
+ payload.data_length = src_len;
+ const size_t max_payload_size = sizeof(payload.data);
+ if (src_len > max_payload_size)
+ payload.data_length = max_payload_size;
+ memcpy (payload.data, src, payload.data_length);
+
+ if (Send (payload) == KERN_SUCCESS)
+ {
+ status = eConnectionStatusSuccess;
+ return payload.data_length;
+ }
+ status = eConnectionStatusError;
+ return 0;
+}
+
+ConnectionStatus
+ConnectionMachPort::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ return eConnectionStatusLostConnection;
+}
+
+kern_return_t
+ConnectionMachPort::Send (const PayloadType &payload)
+{
+ struct MessageType message;
+
+ /* (i) Form the message : */
+
+ /* (i.a) Fill the header fields : */
+ message.head.msgh_bits = MACH_MSGH_BITS_REMOTE (MACH_MSG_TYPE_MAKE_SEND) |
+ MACH_MSGH_BITS_OTHER (MACH_MSGH_BITS_COMPLEX);
+ message.head.msgh_size = sizeof(MessageType);
+ message.head.msgh_local_port = MACH_PORT_NULL;
+ message.head.msgh_remote_port = m_port;
+
+ /* (i.b) Explain the message type ( an integer ) */
+ // message.type.msgt_name = MACH_MSG_TYPE_INTEGER_32;
+ // message.type.msgt_size = 32;
+ // message.type.msgt_number = 1;
+ // message.type.msgt_inline = TRUE;
+ // message.type.msgt_longform = FALSE;
+ // message.type.msgt_deallocate = FALSE;
+ /* message.type.msgt_unused = 0; */ /* not needed, I think */
+
+ /* (i.c) Fill the message with the given integer : */
+ message.payload = payload;
+
+ /* (ii) Send the message : */
+ kern_return_t kret = ::mach_msg (&message.head,
+ MACH_SEND_MSG,
+ message.head.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ return kret;
+}
+
+kern_return_t
+ConnectionMachPort::Receive (PayloadType &payload)
+{
+ MessageType message;
+ message.head.msgh_size = sizeof(MessageType);
+
+ kern_return_t kret = ::mach_msg (&message.head,
+ MACH_RCV_MSG,
+ 0,
+ sizeof(MessageType),
+ m_port,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ if (kret == KERN_SUCCESS)
+ payload = message.payload;
+
+ return kret;
+}
+
+
+#endif // #if defined(__APPLE__)
diff --git a/source/Core/ConnectionSharedMemory.cpp b/source/Core/ConnectionSharedMemory.cpp
new file mode 100644
index 0000000..625f17a
--- /dev/null
+++ b/source/Core/ConnectionSharedMemory.cpp
@@ -0,0 +1,131 @@
+//===-- ConnectionSharedMemory.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/ConnectionSharedMemory.h"
+
+// C Includes
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ConnectionSharedMemory::ConnectionSharedMemory () :
+ Connection(),
+ m_name(),
+ m_fd (-1),
+ m_mmap()
+{
+}
+
+ConnectionSharedMemory::~ConnectionSharedMemory ()
+{
+ Disconnect (NULL);
+}
+
+bool
+ConnectionSharedMemory::IsConnected () const
+{
+ return m_fd >= 0;
+}
+
+ConnectionStatus
+ConnectionSharedMemory::Connect (const char *s, Error *error_ptr)
+{
+// if (s && s[0])
+// {
+// if (strstr(s, "shm-create://"))
+// {
+// }
+// else if (strstr(s, "shm-connect://"))
+// {
+// }
+// if (error_ptr)
+// error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s);
+// return eConnectionStatusError;
+// }
+ if (error_ptr)
+ error_ptr->SetErrorString("invalid connect arguments");
+ return eConnectionStatusError;
+}
+
+ConnectionStatus
+ConnectionSharedMemory::Disconnect (Error *error_ptr)
+{
+ m_mmap.Clear();
+ if (!m_name.empty())
+ {
+ shm_unlink (m_name.c_str());
+ m_name.clear();
+ }
+ return eConnectionStatusSuccess;
+}
+
+size_t
+ConnectionSharedMemory::Read (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ ConnectionStatus &status,
+ Error *error_ptr)
+{
+ status = eConnectionStatusSuccess;
+ return 0;
+}
+
+size_t
+ConnectionSharedMemory::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
+{
+ status = eConnectionStatusSuccess;
+ return 0;
+}
+
+ConnectionStatus
+ConnectionSharedMemory::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ return eConnectionStatusLostConnection;
+}
+
+ConnectionStatus
+ConnectionSharedMemory::Open (bool create, const char *name, size_t size, Error *error_ptr)
+{
+ if (m_fd != -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("already open");
+ return eConnectionStatusError;
+ }
+
+ m_name.assign (name);
+ int oflag = O_RDWR;
+ if (create)
+ oflag |= O_CREAT;
+ m_fd = ::shm_open (m_name.c_str(), oflag, S_IRUSR|S_IWUSR);
+
+ if (create)
+ ::ftruncate (m_fd, size);
+
+ if (m_mmap.MemoryMapFromFileDescriptor(m_fd, 0, size, true, false) == size)
+ return eConnectionStatusSuccess;
+
+ Disconnect(NULL);
+ return eConnectionStatusError;
+}
+
diff --git a/source/Core/ConstString.cpp b/source/Core/ConstString.cpp
new file mode 100644
index 0000000..8751694
--- /dev/null
+++ b/source/Core/ConstString.cpp
@@ -0,0 +1,342 @@
+//===-- ConstString.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/ConstString.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/Mutex.h"
+#include "llvm/ADT/StringMap.h"
+
+using namespace lldb_private;
+
+
+class Pool
+{
+public:
+ typedef const char * StringPoolValueType;
+ typedef llvm::StringMap<StringPoolValueType, llvm::BumpPtrAllocator> StringPool;
+ typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType;
+
+ //------------------------------------------------------------------
+ // Default constructor
+ //
+ // Initialize the member variables and create the empty string.
+ //------------------------------------------------------------------
+ Pool () :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_string_map ()
+ {
+ }
+
+ //------------------------------------------------------------------
+ // Destructor
+ //------------------------------------------------------------------
+ ~Pool ()
+ {
+ }
+
+
+ static StringPoolEntryType &
+ GetStringMapEntryFromKeyData (const char *keyData)
+ {
+ char *ptr = const_cast<char*>(keyData) - sizeof (StringPoolEntryType);
+ return *reinterpret_cast<StringPoolEntryType*>(ptr);
+ }
+
+ size_t
+ GetConstCStringLength (const char *ccstr) const
+ {
+ if (ccstr)
+ {
+ const StringPoolEntryType&entry = GetStringMapEntryFromKeyData (ccstr);
+ return entry.getKey().size();
+ }
+ return 0;
+ }
+
+ StringPoolValueType
+ GetMangledCounterpart (const char *ccstr) const
+ {
+ if (ccstr)
+ return GetStringMapEntryFromKeyData (ccstr).getValue();
+ return 0;
+ }
+
+ bool
+ SetMangledCounterparts (const char *key_ccstr, const char *value_ccstr)
+ {
+ if (key_ccstr && value_ccstr)
+ {
+ GetStringMapEntryFromKeyData (key_ccstr).setValue(value_ccstr);
+ GetStringMapEntryFromKeyData (value_ccstr).setValue(key_ccstr);
+ return true;
+ }
+ return false;
+ }
+
+ const char *
+ GetConstCString (const char *cstr)
+ {
+ if (cstr)
+ return GetConstCStringWithLength (cstr, strlen (cstr));
+ return NULL;
+ }
+
+ const char *
+ GetConstCStringWithLength (const char *cstr, size_t cstr_len)
+ {
+ if (cstr)
+ {
+ Mutex::Locker locker (m_mutex);
+ llvm::StringRef string_ref (cstr, cstr_len);
+ StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL);
+ return entry.getKeyData();
+ }
+ return NULL;
+ }
+
+ const char *
+ GetConstCStringWithStringRef (const llvm::StringRef &string_ref)
+ {
+ if (string_ref.data())
+ {
+ Mutex::Locker locker (m_mutex);
+ StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL);
+ return entry.getKeyData();
+ }
+ return NULL;
+ }
+
+ const char *
+ GetConstCStringAndSetMangledCounterPart (const char *demangled_cstr, const char *mangled_ccstr)
+ {
+ if (demangled_cstr)
+ {
+ Mutex::Locker locker (m_mutex);
+ // Make string pool entry with the mangled counterpart already set
+ StringPoolEntryType& entry = m_string_map.GetOrCreateValue (llvm::StringRef (demangled_cstr), mangled_ccstr);
+
+ // Extract the const version of the demangled_cstr
+ const char *demangled_ccstr = entry.getKeyData();
+ // Now assign the demangled const string as the counterpart of the
+ // mangled const string...
+ GetStringMapEntryFromKeyData (mangled_ccstr).setValue(demangled_ccstr);
+ // Return the constant demangled C string
+ return demangled_ccstr;
+ }
+ return NULL;
+ }
+
+ const char *
+ GetConstTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
+ {
+ if (cstr)
+ {
+ const size_t trimmed_len = std::min<size_t> (strlen (cstr), cstr_len);
+ return GetConstCStringWithLength (cstr, trimmed_len);
+ }
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ // Return the size in bytes that this object and any items in its
+ // collection of uniqued strings + data count values takes in
+ // memory.
+ //------------------------------------------------------------------
+ size_t
+ MemorySize() const
+ {
+ Mutex::Locker locker (m_mutex);
+ size_t mem_size = sizeof(Pool);
+ const_iterator end = m_string_map.end();
+ for (const_iterator pos = m_string_map.begin(); pos != end; ++pos)
+ {
+ mem_size += sizeof(StringPoolEntryType) + pos->getKey().size();
+ }
+ return mem_size;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Typedefs
+ //------------------------------------------------------------------
+ typedef StringPool::iterator iterator;
+ typedef StringPool::const_iterator const_iterator;
+
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ mutable Mutex m_mutex;
+ StringPool m_string_map;
+};
+
+//----------------------------------------------------------------------
+// Frameworks and dylibs aren't supposed to have global C++
+// initializers so we hide the string pool in a static function so
+// that it will get initialized on the first call to this static
+// function.
+//
+// Note, for now we make the string pool a pointer to the pool, because
+// we can't guarantee that some objects won't get destroyed after the
+// global destructor chain is run, and trying to make sure no destructors
+// touch ConstStrings is difficult. So we leak the pool instead.
+//
+// FIXME: If we are going to keep it this way we should come up with some
+// abstraction to "pthread_once" so we don't have to check the pointer
+// every time.
+//----------------------------------------------------------------------
+static Pool &
+StringPool()
+{
+ static Mutex g_pool_initialization_mutex;
+ static Pool *g_string_pool = NULL;
+
+ if (g_string_pool == NULL)
+ {
+ Mutex::Locker initialization_locker(g_pool_initialization_mutex);
+ if (g_string_pool == NULL)
+ {
+ g_string_pool = new Pool();
+ }
+ }
+
+ return *g_string_pool;
+}
+
+ConstString::ConstString (const char *cstr) :
+ m_string (StringPool().GetConstCString (cstr))
+{
+}
+
+ConstString::ConstString (const char *cstr, size_t cstr_len) :
+ m_string (StringPool().GetConstCStringWithLength (cstr, cstr_len))
+{
+}
+
+ConstString::ConstString (const llvm::StringRef &s) :
+ m_string (StringPool().GetConstCStringWithLength (s.data(), s.size()))
+{
+}
+
+bool
+ConstString::operator < (const ConstString& rhs) const
+{
+ if (m_string == rhs.m_string)
+ return false;
+
+ llvm::StringRef lhs_string_ref (m_string, StringPool().GetConstCStringLength (m_string));
+ llvm::StringRef rhs_string_ref (rhs.m_string, StringPool().GetConstCStringLength (rhs.m_string));
+
+ // If both have valid C strings, then return the comparison
+ if (lhs_string_ref.data() && rhs_string_ref.data())
+ return lhs_string_ref < rhs_string_ref;
+
+ // Else one of them was NULL, so if LHS is NULL then it is less than
+ return lhs_string_ref.data() == NULL;
+}
+
+Stream&
+lldb_private::operator << (Stream& s, const ConstString& str)
+{
+ const char *cstr = str.GetCString();
+ if (cstr)
+ s << cstr;
+
+ return s;
+}
+
+size_t
+ConstString::GetLength () const
+{
+ return StringPool().GetConstCStringLength (m_string);
+}
+
+int
+ConstString::Compare (const ConstString& lhs, const ConstString& rhs)
+{
+ // If the iterators are the same, this is the same string
+ register const char *lhs_cstr = lhs.m_string;
+ register const char *rhs_cstr = rhs.m_string;
+ if (lhs_cstr == rhs_cstr)
+ return 0;
+ if (lhs_cstr && rhs_cstr)
+ {
+ llvm::StringRef lhs_string_ref (lhs_cstr, StringPool().GetConstCStringLength (lhs_cstr));
+ llvm::StringRef rhs_string_ref (rhs_cstr, StringPool().GetConstCStringLength (rhs_cstr));
+ return lhs_string_ref.compare(rhs_string_ref);
+ }
+
+ if (lhs_cstr)
+ return +1; // LHS isn't NULL but RHS is
+ else
+ return -1; // LHS is NULL but RHS isn't
+}
+
+void
+ConstString::Dump(Stream *s, const char *fail_value) const
+{
+ if (s)
+ {
+ const char *cstr = AsCString (fail_value);
+ if (cstr)
+ s->PutCString (cstr);
+ }
+}
+
+void
+ConstString::DumpDebug(Stream *s) const
+{
+ const char *cstr = GetCString ();
+ size_t cstr_len = GetLength();
+ // Only print the parens if we have a non-NULL string
+ const char *parens = cstr ? "\"" : "";
+ s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64, (int)sizeof(void*) * 2, this, parens, cstr, parens, (uint64_t)cstr_len);
+}
+
+void
+ConstString::SetCString (const char *cstr)
+{
+ m_string = StringPool().GetConstCString (cstr);
+}
+
+void
+ConstString::SetString (const llvm::StringRef &s)
+{
+ m_string = StringPool().GetConstCStringWithLength (s.data(), s.size());
+}
+
+void
+ConstString::SetCStringWithMangledCounterpart (const char *demangled, const ConstString &mangled)
+{
+ m_string = StringPool().GetConstCStringAndSetMangledCounterPart (demangled, mangled.m_string);
+}
+
+bool
+ConstString::GetMangledCounterpart (ConstString &counterpart) const
+{
+ counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
+ return counterpart;
+}
+
+void
+ConstString::SetCStringWithLength (const char *cstr, size_t cstr_len)
+{
+ m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
+}
+
+void
+ConstString::SetTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
+{
+ m_string = StringPool().GetConstTrimmedCStringWithLength (cstr, cstr_len);
+}
+
+size_t
+ConstString::StaticMemorySize()
+{
+ // Get the size of the static string pool
+ return StringPool().MemorySize();
+}
diff --git a/source/Core/DataBufferHeap.cpp b/source/Core/DataBufferHeap.cpp
new file mode 100644
index 0000000..2c8a865
--- /dev/null
+++ b/source/Core/DataBufferHeap.cpp
@@ -0,0 +1,111 @@
+//===-- DataBufferHeap.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/DataBufferHeap.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+DataBufferHeap::DataBufferHeap () :
+ m_data()
+{
+}
+
+//----------------------------------------------------------------------
+// Initialize this class with "n" characters and fill the buffer
+// with "ch".
+//----------------------------------------------------------------------
+DataBufferHeap::DataBufferHeap (lldb::offset_t n, uint8_t ch) :
+ m_data()
+{
+ if (n < m_data.max_size())
+ m_data.assign (n, ch);
+}
+
+//----------------------------------------------------------------------
+// Initialize this class with a copy of the "n" bytes from the "bytes"
+// buffer.
+//----------------------------------------------------------------------
+DataBufferHeap::DataBufferHeap (const void *src, lldb::offset_t src_len) :
+ m_data()
+{
+ CopyData (src, src_len);
+}
+
+//----------------------------------------------------------------------
+// Virtual destructor since this class inherits from a pure virtual
+// base class.
+//----------------------------------------------------------------------
+DataBufferHeap::~DataBufferHeap ()
+{
+}
+
+//----------------------------------------------------------------------
+// Return a pointer to the bytes owned by this object, or NULL if
+// the object contains no bytes.
+//----------------------------------------------------------------------
+uint8_t *
+DataBufferHeap::GetBytes ()
+{
+ if (m_data.empty())
+ return NULL;
+ return &m_data[0];
+}
+
+//----------------------------------------------------------------------
+// Return a const pointer to the bytes owned by this object, or NULL
+// if the object contains no bytes.
+//----------------------------------------------------------------------
+const uint8_t *
+DataBufferHeap::GetBytes () const
+{
+ if (m_data.empty())
+ return NULL;
+ return &m_data[0];
+}
+
+//----------------------------------------------------------------------
+// Return the number of bytes this object currently contains.
+//----------------------------------------------------------------------
+uint64_t
+DataBufferHeap::GetByteSize () const
+{
+ return m_data.size();
+}
+
+
+//----------------------------------------------------------------------
+// Sets the number of bytes that this object should be able to
+// contain. This can be used prior to copying data into the buffer.
+//----------------------------------------------------------------------
+uint64_t
+DataBufferHeap::SetByteSize (uint64_t new_size)
+{
+ m_data.resize(new_size);
+ return m_data.size();
+}
+
+void
+DataBufferHeap::CopyData (const void *src, uint64_t src_len)
+{
+ const uint8_t *src_u8 = (const uint8_t *)src;
+ if (src && src_len > 0)
+ m_data.assign (src_u8, src_u8 + src_len);
+ else
+ m_data.clear();
+}
+
+void
+DataBufferHeap::Clear()
+{
+ buffer_t empty;
+ m_data.swap(empty);
+}
diff --git a/source/Core/DataBufferMemoryMap.cpp b/source/Core/DataBufferMemoryMap.cpp
new file mode 100644
index 0000000..a4382a0
--- /dev/null
+++ b/source/Core/DataBufferMemoryMap.cpp
@@ -0,0 +1,258 @@
+//===-- DataBufferMemoryMap.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "lldb/Core/DataBufferMemoryMap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Core/Log.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default Constructor
+//----------------------------------------------------------------------
+DataBufferMemoryMap::DataBufferMemoryMap() :
+ m_mmap_addr(NULL),
+ m_mmap_size(0),
+ m_data(NULL),
+ m_size(0)
+{
+}
+
+//----------------------------------------------------------------------
+// Virtual destructor since this class inherits from a pure virtual
+// base class.
+//----------------------------------------------------------------------
+DataBufferMemoryMap::~DataBufferMemoryMap()
+{
+ Clear();
+}
+
+//----------------------------------------------------------------------
+// Return a pointer to the bytes owned by this object, or NULL if
+// the object contains no bytes.
+//----------------------------------------------------------------------
+uint8_t *
+DataBufferMemoryMap::GetBytes()
+{
+ return m_data;
+}
+
+//----------------------------------------------------------------------
+// Return a const pointer to the bytes owned by this object, or NULL
+// if the object contains no bytes.
+//----------------------------------------------------------------------
+const uint8_t *
+DataBufferMemoryMap::GetBytes() const
+{
+ return m_data;
+}
+
+//----------------------------------------------------------------------
+// Return the number of bytes this object currently contains.
+//----------------------------------------------------------------------
+uint64_t
+DataBufferMemoryMap::GetByteSize() const
+{
+ return m_size;
+}
+
+//----------------------------------------------------------------------
+// Reverts this object to an empty state by unmapping any memory
+// that is currently owned.
+//----------------------------------------------------------------------
+void
+DataBufferMemoryMap::Clear()
+{
+ if (m_mmap_addr != NULL)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
+ if (log)
+ log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %zu", m_mmap_addr, m_mmap_size);
+ ::munmap((void *)m_mmap_addr, m_mmap_size);
+ m_mmap_addr = NULL;
+ m_mmap_size = 0;
+ m_data = NULL;
+ m_size = 0;
+ }
+}
+
+//----------------------------------------------------------------------
+// Memory map "length" bytes from "file" starting "offset"
+// bytes into the file. If "length" is set to SIZE_MAX, then
+// map as many bytes as possible.
+//
+// Returns the number of bytes mapped starting from the requested
+// offset.
+//----------------------------------------------------------------------
+size_t
+DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec,
+ lldb::offset_t offset,
+ lldb::offset_t length,
+ bool writeable)
+{
+ if (filespec != NULL)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
+ if (log)
+ {
+ log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(file=\"%s\", offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i",
+ filespec->GetPath().c_str(),
+ offset,
+ length,
+ writeable);
+ }
+ char path[PATH_MAX];
+ if (filespec->GetPath(path, sizeof(path)))
+ {
+ uint32_t options = File::eOpenOptionRead;
+ if (writeable)
+ options |= File::eOpenOptionWrite;
+
+ File file;
+ Error error (file.Open(path, options));
+ if (error.Success())
+ {
+ const bool fd_is_file = true;
+ return MemoryMapFromFileDescriptor (file.GetDescriptor(), offset, length, writeable, fd_is_file);
+ }
+ }
+ }
+ // We should only get here if there was an error
+ Clear();
+ return 0;
+}
+
+
+//----------------------------------------------------------------------
+// The file descriptor FD is assumed to already be opened as read only
+// and the STAT structure is assumed to a valid pointer and already
+// containing valid data from a call to stat().
+//
+// Memory map FILE_LENGTH bytes in FILE starting FILE_OFFSET bytes into
+// the file. If FILE_LENGTH is set to SIZE_MAX, then map as many bytes
+// as possible.
+//
+// RETURNS
+// Number of bytes mapped starting from the requested offset.
+//----------------------------------------------------------------------
+size_t
+DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
+ lldb::offset_t offset,
+ lldb::offset_t length,
+ bool writeable,
+ bool fd_is_file)
+{
+ Clear();
+ if (fd >= 0)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP|LIBLLDB_LOG_VERBOSE));
+ if (log)
+ {
+ log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(fd=%i, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)",
+ fd,
+ offset,
+ length,
+ writeable,
+ fd_is_file);
+ }
+ struct stat stat;
+ if (::fstat(fd, &stat) == 0)
+ {
+ if (S_ISREG(stat.st_mode) && (stat.st_size > offset))
+ {
+ const size_t max_bytes_available = stat.st_size - offset;
+ if (length == SIZE_MAX)
+ {
+ length = max_bytes_available;
+ }
+ else if (length > max_bytes_available)
+ {
+ // Cap the length if too much data was requested
+ length = max_bytes_available;
+ }
+
+ if (length > 0)
+ {
+ int prot = PROT_READ;
+ if (writeable)
+ prot |= PROT_WRITE;
+
+ int flags = MAP_PRIVATE;
+ if (fd_is_file)
+ flags |= MAP_FILE;
+
+ m_mmap_addr = (uint8_t *)::mmap(NULL, length, prot, flags, fd, offset);
+ Error error;
+
+ if (m_mmap_addr == (void*)-1)
+ {
+ error.SetErrorToErrno ();
+ if (error.GetError() == EINVAL)
+ {
+ // We may still have a shot at memory mapping if we align things correctly
+ size_t page_offset = offset % Host::GetPageSize();
+ if (page_offset != 0)
+ {
+ m_mmap_addr = (uint8_t *)::mmap(NULL, length + page_offset, prot, flags, fd, offset - page_offset);
+ if (m_mmap_addr == (void*)-1)
+ {
+ // Failed to map file
+ m_mmap_addr = NULL;
+ }
+ else if (m_mmap_addr != NULL)
+ {
+ // We recovered and were able to memory map
+ // after we aligned things to page boundaries
+
+ // Save the actual mmap'ed size
+ m_mmap_size = length + page_offset;
+ // Our data is at an offset into the the mapped data
+ m_data = m_mmap_addr + page_offset;
+ // Our pretend size is the size that was requestd
+ m_size = length;
+ }
+ }
+ }
+ if (error.GetError() == ENOMEM)
+ {
+ error.SetErrorStringWithFormat("could not allocate %" PRId64 " bytes of memory to mmap in file", (uint64_t) length);
+ }
+ }
+ else
+ {
+ // We were able to map the requested data in one chunk
+ // where our mmap and actual data are the same.
+ m_mmap_size = length;
+ m_data = m_mmap_addr;
+ m_size = length;
+ }
+
+ if (log)
+ {
+ log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %zu, error = %s",
+ m_mmap_addr, m_mmap_size, error.AsCString());
+ }
+ }
+ }
+ }
+ }
+ return GetByteSize ();
+}
diff --git a/source/Core/DataEncoder.cpp b/source/Core/DataEncoder.cpp
new file mode 100644
index 0000000..92a9104
--- /dev/null
+++ b/source/Core/DataEncoder.cpp
@@ -0,0 +1,335 @@
+//===-- DataEncoder.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/DataEncoder.h"
+
+#include <assert.h>
+#include <stddef.h>
+
+#include "llvm/Support/MathExtras.h"
+
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Host/Endian.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static inline void
+WriteInt16(const unsigned char* ptr, unsigned offset, uint16_t value)
+{
+ *(uint16_t *)(ptr + offset) = value;
+}
+static inline void
+WriteInt32 (const unsigned char* ptr, unsigned offset, uint32_t value)
+{
+ *(uint32_t *)(ptr + offset) = value;
+}
+
+static inline void
+WriteInt64(const unsigned char* ptr, unsigned offset, uint64_t value)
+{
+ *(uint64_t *)(ptr + offset) = value;
+}
+
+static inline void
+WriteSwappedInt16(const unsigned char* ptr, unsigned offset, uint16_t value)
+{
+ *(uint16_t *)(ptr + offset) = llvm::ByteSwap_16(value);
+}
+
+static inline void
+WriteSwappedInt32 (const unsigned char* ptr, unsigned offset, uint32_t value)
+{
+ *(uint32_t *)(ptr + offset) = llvm::ByteSwap_32(value);
+}
+
+static inline void
+WriteSwappedInt64(const unsigned char* ptr, unsigned offset, uint64_t value)
+{
+ *(uint64_t *)(ptr + offset) = llvm::ByteSwap_64(value);
+}
+
+//----------------------------------------------------------------------
+// Default constructor.
+//----------------------------------------------------------------------
+DataEncoder::DataEncoder () :
+ m_start (NULL),
+ m_end (NULL),
+ m_byte_order(lldb::endian::InlHostByteOrder()),
+ m_addr_size (sizeof(void*)),
+ m_data_sp ()
+{
+}
+
+//----------------------------------------------------------------------
+// This constructor allows us to use data that is owned by someone else.
+// The data must stay around as long as this object is valid.
+//----------------------------------------------------------------------
+DataEncoder::DataEncoder (void* data, uint32_t length, ByteOrder endian, uint8_t addr_size) :
+ m_start ((uint8_t*)data),
+ m_end ((uint8_t*)data + length),
+ m_byte_order(endian),
+ m_addr_size (addr_size),
+ m_data_sp ()
+{
+}
+
+//----------------------------------------------------------------------
+// Make a shared pointer reference to the shared data in "data_sp" and
+// set the endian swapping setting to "swap", and the address size to
+// "addr_size". The shared data reference will ensure the data lives
+// as long as any DataEncoder objects exist that have a reference to
+// this data.
+//----------------------------------------------------------------------
+DataEncoder::DataEncoder (const DataBufferSP& data_sp, ByteOrder endian, uint8_t addr_size) :
+ m_start (NULL),
+ m_end (NULL),
+ m_byte_order(endian),
+ m_addr_size (addr_size),
+ m_data_sp ()
+{
+ SetData (data_sp);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DataEncoder::~DataEncoder ()
+{
+}
+
+//------------------------------------------------------------------
+// Clears the object contents back to a default invalid state, and
+// release any references to shared data that this object may
+// contain.
+//------------------------------------------------------------------
+void
+DataEncoder::Clear ()
+{
+ m_start = NULL;
+ m_end = NULL;
+ m_byte_order = lldb::endian::InlHostByteOrder();
+ m_addr_size = sizeof(void*);
+ m_data_sp.reset();
+}
+
+//------------------------------------------------------------------
+// If this object contains shared data, this function returns the
+// offset into that shared data. Else zero is returned.
+//------------------------------------------------------------------
+size_t
+DataEncoder::GetSharedDataOffset () const
+{
+ if (m_start != NULL)
+ {
+ const DataBuffer * data = m_data_sp.get();
+ if (data != NULL)
+ {
+ const uint8_t * data_bytes = data->GetBytes();
+ if (data_bytes != NULL)
+ {
+ assert(m_start >= data_bytes);
+ return m_start - data_bytes;
+ }
+ }
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Set the data with which this object will extract from to data
+// starting at BYTES and set the length of the data to LENGTH bytes
+// long. The data is externally owned must be around at least as
+// long as this object points to the data. No copy of the data is
+// made, this object just refers to this data and can extract from
+// it. If this object refers to any shared data upon entry, the
+// reference to that data will be released. Is SWAP is set to true,
+// any data extracted will be endian swapped.
+//----------------------------------------------------------------------
+uint32_t
+DataEncoder::SetData (const void *bytes, uint32_t length, ByteOrder endian)
+{
+ m_byte_order = endian;
+ m_data_sp.reset();
+ if (bytes == NULL || length == 0)
+ {
+ m_start = NULL;
+ m_end = NULL;
+ }
+ else
+ {
+ m_start = (uint8_t *)bytes;
+ m_end = m_start + length;
+ }
+ return GetByteSize();
+}
+
+//----------------------------------------------------------------------
+// Assign the data for this object to be a subrange of the shared
+// data in "data_sp" starting "data_offset" bytes into "data_sp"
+// and ending "data_length" bytes later. If "data_offset" is not
+// a valid offset into "data_sp", then this object will contain no
+// bytes. If "data_offset" is within "data_sp" yet "data_length" is
+// too large, the length will be capped at the number of bytes
+// remaining in "data_sp". A ref counted pointer to the data in
+// "data_sp" will be made in this object IF the number of bytes this
+// object refers to in greater than zero (if at least one byte was
+// available starting at "data_offset") to ensure the data stays
+// around as long as it is needed. The address size and endian swap
+// settings will remain unchanged from their current settings.
+//----------------------------------------------------------------------
+uint32_t
+DataEncoder::SetData (const DataBufferSP& data_sp, uint32_t data_offset, uint32_t data_length)
+{
+ m_start = m_end = NULL;
+
+ if (data_length > 0)
+ {
+ m_data_sp = data_sp;
+ if (data_sp.get())
+ {
+ const size_t data_size = data_sp->GetByteSize();
+ if (data_offset < data_size)
+ {
+ m_start = data_sp->GetBytes() + data_offset;
+ const size_t bytes_left = data_size - data_offset;
+ // Cap the length of we asked for too many
+ if (data_length <= bytes_left)
+ m_end = m_start + data_length; // We got all the bytes we wanted
+ else
+ m_end = m_start + bytes_left; // Not all the bytes requested were available in the shared data
+ }
+ }
+ }
+
+ uint32_t new_size = GetByteSize();
+
+ // Don't hold a shared pointer to the data buffer if we don't share
+ // any valid bytes in the shared buffer.
+ if (new_size == 0)
+ m_data_sp.reset();
+
+ return new_size;
+}
+
+//----------------------------------------------------------------------
+// Extract a single unsigned char from the binary data and update
+// the offset pointed to by "offset_ptr".
+//
+// RETURNS the byte that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint32_t
+DataEncoder::PutU8 (uint32_t offset, uint8_t value)
+{
+ if (ValidOffset(offset))
+ {
+ m_start[offset] = value;
+ return offset + 1;
+ }
+ return UINT32_MAX;
+}
+
+uint32_t
+DataEncoder::PutU16 (uint32_t offset, uint16_t value)
+{
+ if (ValidOffsetForDataOfSize(offset, sizeof(value)))
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ WriteSwappedInt16 (m_start, offset, value);
+ else
+ WriteInt16 (m_start, offset, value);
+
+ return offset + sizeof (value);
+ }
+ return UINT32_MAX;
+}
+
+uint32_t
+DataEncoder::PutU32 (uint32_t offset, uint32_t value)
+{
+ if (ValidOffsetForDataOfSize(offset, sizeof(value)))
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ WriteSwappedInt32 (m_start, offset, value);
+ else
+ WriteInt32 (m_start, offset, value);
+
+ return offset + sizeof (value);
+ }
+ return UINT32_MAX;
+}
+
+uint32_t
+DataEncoder::PutU64 (uint32_t offset, uint64_t value)
+{
+ if (ValidOffsetForDataOfSize(offset, sizeof(value)))
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ WriteSwappedInt64 (m_start, offset, value);
+ else
+ WriteInt64 (m_start, offset, value);
+
+ return offset + sizeof (value);
+ }
+ return UINT32_MAX;
+}
+
+//----------------------------------------------------------------------
+// Extract a single integer value from the data and update the offset
+// pointed to by "offset_ptr". The size of the extracted integer
+// is specified by the "byte_size" argument. "byte_size" should have
+// a value >= 1 and <= 8 since the return value is only 64 bits
+// wide. Any "byte_size" values less than 1 or greater than 8 will
+// result in nothing being extracted, and zero being returned.
+//
+// RETURNS the integer value that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint32_t
+DataEncoder::PutMaxU64 (uint32_t offset, uint32_t byte_size, uint64_t value)
+{
+ switch (byte_size)
+ {
+ case 1: return PutU8 (offset, value);
+ case 2: return PutU16(offset, value);
+ case 4: return PutU32(offset, value);
+ case 8: return PutU64(offset, value);
+ default:
+ assert(!"GetMax64 unhandled case!");
+ break;
+ }
+ return UINT32_MAX;
+}
+
+uint32_t
+DataEncoder::PutData (uint32_t offset, const void *src, uint32_t src_len)
+{
+ if (src == NULL || src_len == 0)
+ return offset;
+
+ if (ValidOffsetForDataOfSize(offset, src_len))
+ {
+ memcpy (m_start + offset, src, src_len);
+ return offset + src_len;
+ }
+ return UINT32_MAX;
+}
+
+uint32_t
+DataEncoder::PutAddress (uint32_t offset, lldb::addr_t addr)
+{
+ return PutMaxU64 (offset, GetAddressByteSize(), addr);
+}
+
+uint32_t
+DataEncoder::PutCString (uint32_t offset, const char *cstr)
+{
+ if (cstr)
+ return PutData (offset, cstr, strlen(cstr) + 1);
+ return UINT32_MAX;
+}
diff --git a/source/Core/DataExtractor.cpp b/source/Core/DataExtractor.cpp
new file mode 100644
index 0000000..518faeb
--- /dev/null
+++ b/source/Core/DataExtractor.cpp
@@ -0,0 +1,2179 @@
+//===-- DataExtractor.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <bitset>
+#include <limits>
+#include <sstream>
+#include <string>
+
+#include "clang/AST/ASTContext.h"
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/MathExtras.h"
+
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static inline uint16_t
+ReadInt16(const unsigned char* ptr, offset_t offset)
+{
+ return *(uint16_t *)(ptr + offset);
+}
+static inline uint32_t
+ReadInt32 (const unsigned char* ptr, offset_t offset)
+{
+ return *(uint32_t *)(ptr + offset);
+}
+
+static inline uint64_t
+ReadInt64(const unsigned char* ptr, offset_t offset)
+{
+ return *(uint64_t *)(ptr + offset);
+}
+
+static inline uint16_t
+ReadInt16(const void* ptr)
+{
+ return *(uint16_t *)(ptr);
+}
+static inline uint32_t
+ReadInt32 (const void* ptr)
+{
+ return *(uint32_t *)(ptr);
+}
+
+static inline uint64_t
+ReadInt64(const void* ptr)
+{
+ return *(uint64_t *)(ptr);
+}
+
+static inline uint16_t
+ReadSwapInt16(const unsigned char* ptr, offset_t offset)
+{
+ return llvm::ByteSwap_16(*(uint16_t *)(ptr + offset));
+}
+
+static inline uint32_t
+ReadSwapInt32 (const unsigned char* ptr, offset_t offset)
+{
+ return llvm::ByteSwap_32(*(uint32_t *)(ptr + offset));
+}
+static inline uint64_t
+ReadSwapInt64(const unsigned char* ptr, offset_t offset)
+{
+ return llvm::ByteSwap_64(*(uint64_t *)(ptr + offset));
+}
+
+static inline uint16_t
+ReadSwapInt16(const void* ptr)
+{
+ return llvm::ByteSwap_16(*(uint16_t *)(ptr));
+}
+
+static inline uint32_t
+ReadSwapInt32 (const void* ptr)
+{
+ return llvm::ByteSwap_32(*(uint32_t *)(ptr));
+}
+static inline uint64_t
+ReadSwapInt64(const void* ptr)
+{
+ return llvm::ByteSwap_64(*(uint64_t *)(ptr));
+}
+
+#define NON_PRINTABLE_CHAR '.'
+//----------------------------------------------------------------------
+// Default constructor.
+//----------------------------------------------------------------------
+DataExtractor::DataExtractor () :
+ m_start (NULL),
+ m_end (NULL),
+ m_byte_order(lldb::endian::InlHostByteOrder()),
+ m_addr_size (4),
+ m_data_sp ()
+{
+}
+
+//----------------------------------------------------------------------
+// This constructor allows us to use data that is owned by someone else.
+// The data must stay around as long as this object is valid.
+//----------------------------------------------------------------------
+DataExtractor::DataExtractor (const void* data, offset_t length, ByteOrder endian, uint32_t addr_size) :
+ m_start ((uint8_t*)data),
+ m_end ((uint8_t*)data + length),
+ m_byte_order(endian),
+ m_addr_size (addr_size),
+ m_data_sp ()
+{
+}
+
+//----------------------------------------------------------------------
+// Make a shared pointer reference to the shared data in "data_sp" and
+// set the endian swapping setting to "swap", and the address size to
+// "addr_size". The shared data reference will ensure the data lives
+// as long as any DataExtractor objects exist that have a reference to
+// this data.
+//----------------------------------------------------------------------
+DataExtractor::DataExtractor (const DataBufferSP& data_sp, ByteOrder endian, uint32_t addr_size) :
+ m_start (NULL),
+ m_end (NULL),
+ m_byte_order(endian),
+ m_addr_size (addr_size),
+ m_data_sp ()
+{
+ SetData (data_sp);
+}
+
+//----------------------------------------------------------------------
+// Initialize this object with a subset of the data bytes in "data".
+// If "data" contains shared data, then a reference to this shared
+// data will added and the shared data will stay around as long
+// as any object contains a reference to that data. The endian
+// swap and address size settings are copied from "data".
+//----------------------------------------------------------------------
+DataExtractor::DataExtractor (const DataExtractor& data, offset_t offset, offset_t length) :
+ m_start(NULL),
+ m_end(NULL),
+ m_byte_order(data.m_byte_order),
+ m_addr_size(data.m_addr_size),
+ m_data_sp()
+{
+ if (data.ValidOffset(offset))
+ {
+ offset_t bytes_available = data.GetByteSize() - offset;
+ if (length > bytes_available)
+ length = bytes_available;
+ SetData(data, offset, length);
+ }
+}
+
+DataExtractor::DataExtractor (const DataExtractor& rhs) :
+ m_start (rhs.m_start),
+ m_end (rhs.m_end),
+ m_byte_order (rhs.m_byte_order),
+ m_addr_size (rhs.m_addr_size),
+ m_data_sp (rhs.m_data_sp)
+{
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const DataExtractor&
+DataExtractor::operator= (const DataExtractor& rhs)
+{
+ if (this != &rhs)
+ {
+ m_start = rhs.m_start;
+ m_end = rhs.m_end;
+ m_byte_order = rhs.m_byte_order;
+ m_addr_size = rhs.m_addr_size;
+ m_data_sp = rhs.m_data_sp;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DataExtractor::~DataExtractor ()
+{
+}
+
+//------------------------------------------------------------------
+// Clears the object contents back to a default invalid state, and
+// release any references to shared data that this object may
+// contain.
+//------------------------------------------------------------------
+void
+DataExtractor::Clear ()
+{
+ m_start = NULL;
+ m_end = NULL;
+ m_byte_order = lldb::endian::InlHostByteOrder();
+ m_addr_size = 4;
+ m_data_sp.reset();
+}
+
+//------------------------------------------------------------------
+// If this object contains shared data, this function returns the
+// offset into that shared data. Else zero is returned.
+//------------------------------------------------------------------
+size_t
+DataExtractor::GetSharedDataOffset () const
+{
+ if (m_start != NULL)
+ {
+ const DataBuffer * data = m_data_sp.get();
+ if (data != NULL)
+ {
+ const uint8_t * data_bytes = data->GetBytes();
+ if (data_bytes != NULL)
+ {
+ assert(m_start >= data_bytes);
+ return m_start - data_bytes;
+ }
+ }
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Set the data with which this object will extract from to data
+// starting at BYTES and set the length of the data to LENGTH bytes
+// long. The data is externally owned must be around at least as
+// long as this object points to the data. No copy of the data is
+// made, this object just refers to this data and can extract from
+// it. If this object refers to any shared data upon entry, the
+// reference to that data will be released. Is SWAP is set to true,
+// any data extracted will be endian swapped.
+//----------------------------------------------------------------------
+lldb::offset_t
+DataExtractor::SetData (const void *bytes, offset_t length, ByteOrder endian)
+{
+ m_byte_order = endian;
+ m_data_sp.reset();
+ if (bytes == NULL || length == 0)
+ {
+ m_start = NULL;
+ m_end = NULL;
+ }
+ else
+ {
+ m_start = (uint8_t *)bytes;
+ m_end = m_start + length;
+ }
+ return GetByteSize();
+}
+
+//----------------------------------------------------------------------
+// Assign the data for this object to be a subrange in "data"
+// starting "data_offset" bytes into "data" and ending "data_length"
+// bytes later. If "data_offset" is not a valid offset into "data",
+// then this object will contain no bytes. If "data_offset" is
+// within "data" yet "data_length" is too large, the length will be
+// capped at the number of bytes remaining in "data". If "data"
+// contains a shared pointer to other data, then a ref counted
+// pointer to that data will be made in this object. If "data"
+// doesn't contain a shared pointer to data, then the bytes referred
+// to in "data" will need to exist at least as long as this object
+// refers to those bytes. The address size and endian swap settings
+// are copied from the current values in "data".
+//----------------------------------------------------------------------
+lldb::offset_t
+DataExtractor::SetData (const DataExtractor& data, offset_t data_offset, offset_t data_length)
+{
+ m_addr_size = data.m_addr_size;
+ // If "data" contains shared pointer to data, then we can use that
+ if (data.m_data_sp.get())
+ {
+ m_byte_order = data.m_byte_order;
+ return SetData(data.m_data_sp, data.GetSharedDataOffset() + data_offset, data_length);
+ }
+
+ // We have a DataExtractor object that just has a pointer to bytes
+ if (data.ValidOffset(data_offset))
+ {
+ if (data_length > data.GetByteSize() - data_offset)
+ data_length = data.GetByteSize() - data_offset;
+ return SetData (data.GetDataStart() + data_offset, data_length, data.GetByteOrder());
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Assign the data for this object to be a subrange of the shared
+// data in "data_sp" starting "data_offset" bytes into "data_sp"
+// and ending "data_length" bytes later. If "data_offset" is not
+// a valid offset into "data_sp", then this object will contain no
+// bytes. If "data_offset" is within "data_sp" yet "data_length" is
+// too large, the length will be capped at the number of bytes
+// remaining in "data_sp". A ref counted pointer to the data in
+// "data_sp" will be made in this object IF the number of bytes this
+// object refers to in greater than zero (if at least one byte was
+// available starting at "data_offset") to ensure the data stays
+// around as long as it is needed. The address size and endian swap
+// settings will remain unchanged from their current settings.
+//----------------------------------------------------------------------
+lldb::offset_t
+DataExtractor::SetData (const DataBufferSP& data_sp, offset_t data_offset, offset_t data_length)
+{
+ m_start = m_end = NULL;
+
+ if (data_length > 0)
+ {
+ m_data_sp = data_sp;
+ if (data_sp.get())
+ {
+ const size_t data_size = data_sp->GetByteSize();
+ if (data_offset < data_size)
+ {
+ m_start = data_sp->GetBytes() + data_offset;
+ const size_t bytes_left = data_size - data_offset;
+ // Cap the length of we asked for too many
+ if (data_length <= bytes_left)
+ m_end = m_start + data_length; // We got all the bytes we wanted
+ else
+ m_end = m_start + bytes_left; // Not all the bytes requested were available in the shared data
+ }
+ }
+ }
+
+ size_t new_size = GetByteSize();
+
+ // Don't hold a shared pointer to the data buffer if we don't share
+ // any valid bytes in the shared buffer.
+ if (new_size == 0)
+ m_data_sp.reset();
+
+ return new_size;
+}
+
+//----------------------------------------------------------------------
+// Extract a single unsigned char from the binary data and update
+// the offset pointed to by "offset_ptr".
+//
+// RETURNS the byte that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint8_t
+DataExtractor::GetU8 (offset_t *offset_ptr) const
+{
+ const uint8_t *data = (const uint8_t *)GetData (offset_ptr, 1);
+ if (data)
+ return *data;
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Extract "count" unsigned chars from the binary data and update the
+// offset pointed to by "offset_ptr". The extracted data is copied into
+// "dst".
+//
+// RETURNS the non-NULL buffer pointer upon successful extraction of
+// all the requested bytes, or NULL when the data is not available in
+// the buffer due to being out of bounds, or unsufficient data.
+//----------------------------------------------------------------------
+void *
+DataExtractor::GetU8 (offset_t *offset_ptr, void *dst, uint32_t count) const
+{
+ const uint8_t *data = (const uint8_t *)GetData (offset_ptr, count);
+ if (data)
+ {
+ // Copy the data into the buffer
+ memcpy (dst, data, count);
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return dst;
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Extract a single uint16_t from the data and update the offset
+// pointed to by "offset_ptr".
+//
+// RETURNS the uint16_t that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint16_t
+DataExtractor::GetU16 (offset_t *offset_ptr) const
+{
+ uint16_t val = 0;
+ const uint8_t *data = (const uint8_t *)GetData (offset_ptr, sizeof(val));
+ if (data)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ val = ReadSwapInt16(data);
+ else
+ val = ReadInt16 (data);
+ }
+ return val;
+}
+
+uint16_t
+DataExtractor::GetU16_unchecked (offset_t *offset_ptr) const
+{
+ uint16_t val;
+ if (m_byte_order == lldb::endian::InlHostByteOrder())
+ val = ReadInt16 (m_start, *offset_ptr);
+ else
+ val = ReadSwapInt16(m_start, *offset_ptr);
+ *offset_ptr += sizeof(val);
+ return val;
+}
+
+uint32_t
+DataExtractor::GetU32_unchecked (offset_t *offset_ptr) const
+{
+ uint32_t val;
+ if (m_byte_order == lldb::endian::InlHostByteOrder())
+ val = ReadInt32 (m_start, *offset_ptr);
+ else
+ val = ReadSwapInt32 (m_start, *offset_ptr);
+ *offset_ptr += sizeof(val);
+ return val;
+}
+
+uint64_t
+DataExtractor::GetU64_unchecked (offset_t *offset_ptr) const
+{
+ uint64_t val;
+ if (m_byte_order == lldb::endian::InlHostByteOrder())
+ val = ReadInt64 (m_start, *offset_ptr);
+ else
+ val = ReadSwapInt64 (m_start, *offset_ptr);
+ *offset_ptr += sizeof(val);
+ return val;
+}
+
+
+//----------------------------------------------------------------------
+// Extract "count" uint16_t values from the binary data and update
+// the offset pointed to by "offset_ptr". The extracted data is
+// copied into "dst".
+//
+// RETURNS the non-NULL buffer pointer upon successful extraction of
+// all the requested bytes, or NULL when the data is not available
+// in the buffer due to being out of bounds, or unsufficient data.
+//----------------------------------------------------------------------
+void *
+DataExtractor::GetU16 (offset_t *offset_ptr, void *void_dst, uint32_t count) const
+{
+ const size_t src_size = sizeof(uint16_t) * count;
+ const uint16_t *src = (const uint16_t *)GetData (offset_ptr, src_size);
+ if (src)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ {
+ uint16_t *dst_pos = (uint16_t *)void_dst;
+ uint16_t *dst_end = dst_pos + count;
+ const uint16_t *src_pos = src;
+ while (dst_pos < dst_end)
+ {
+ *dst_pos = ReadSwapInt16 (src_pos);
+ ++dst_pos;
+ ++src_pos;
+ }
+ }
+ else
+ {
+ memcpy (void_dst, src, src_size);
+ }
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return void_dst;
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Extract a single uint32_t from the data and update the offset
+// pointed to by "offset_ptr".
+//
+// RETURNS the uint32_t that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint32_t
+DataExtractor::GetU32 (offset_t *offset_ptr) const
+{
+ uint32_t val = 0;
+ const uint32_t *data = (const uint32_t *)GetData (offset_ptr, sizeof(val));
+ if (data)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ val = ReadSwapInt32 (data);
+ else
+ val = *data;
+ }
+ return val;
+}
+
+//----------------------------------------------------------------------
+// Extract "count" uint32_t values from the binary data and update
+// the offset pointed to by "offset_ptr". The extracted data is
+// copied into "dst".
+//
+// RETURNS the non-NULL buffer pointer upon successful extraction of
+// all the requested bytes, or NULL when the data is not available
+// in the buffer due to being out of bounds, or unsufficient data.
+//----------------------------------------------------------------------
+void *
+DataExtractor::GetU32 (offset_t *offset_ptr, void *void_dst, uint32_t count) const
+{
+ const size_t src_size = sizeof(uint32_t) * count;
+ const uint32_t *src = (const uint32_t *)GetData (offset_ptr, src_size);
+ if (src)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ {
+ uint32_t *dst_pos = (uint32_t *)void_dst;
+ uint32_t *dst_end = dst_pos + count;
+ const uint32_t *src_pos = src;
+ while (dst_pos < dst_end)
+ {
+ *dst_pos = ReadSwapInt32 (src_pos);
+ ++dst_pos;
+ ++src_pos;
+ }
+ }
+ else
+ {
+ memcpy (void_dst, src, src_size);
+ }
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return void_dst;
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Extract a single uint64_t from the data and update the offset
+// pointed to by "offset_ptr".
+//
+// RETURNS the uint64_t that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint64_t
+DataExtractor::GetU64 (offset_t *offset_ptr) const
+{
+ uint64_t val = 0;
+ const uint64_t *data = (const uint64_t *)GetData (offset_ptr, sizeof(val));
+ if (data)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ val = ReadSwapInt64 (data);
+ else
+ val = *data;
+ }
+ return val;
+}
+
+//----------------------------------------------------------------------
+// GetU64
+//
+// Get multiple consecutive 64 bit values. Return true if the entire
+// read succeeds and increment the offset pointed to by offset_ptr, else
+// return false and leave the offset pointed to by offset_ptr unchanged.
+//----------------------------------------------------------------------
+void *
+DataExtractor::GetU64 (offset_t *offset_ptr, void *void_dst, uint32_t count) const
+{
+ const size_t src_size = sizeof(uint64_t) * count;
+ const uint64_t *src = (const uint64_t *)GetData (offset_ptr, src_size);
+ if (src)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ {
+ uint64_t *dst_pos = (uint64_t *)void_dst;
+ uint64_t *dst_end = dst_pos + count;
+ const uint64_t *src_pos = src;
+ while (dst_pos < dst_end)
+ {
+ *dst_pos = ReadSwapInt64 (src_pos);
+ ++dst_pos;
+ ++src_pos;
+ }
+ }
+ else
+ {
+ memcpy (void_dst, src, src_size);
+ }
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return void_dst;
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Extract a single integer value from the data and update the offset
+// pointed to by "offset_ptr". The size of the extracted integer
+// is specified by the "byte_size" argument. "byte_size" should have
+// a value between 1 and 4 since the return value is only 32 bits
+// wide. Any "byte_size" values less than 1 or greater than 4 will
+// result in nothing being extracted, and zero being returned.
+//
+// RETURNS the integer value that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint32_t
+DataExtractor::GetMaxU32 (offset_t *offset_ptr, size_t byte_size) const
+{
+ switch (byte_size)
+ {
+ case 1: return GetU8 (offset_ptr); break;
+ case 2: return GetU16(offset_ptr); break;
+ case 4: return GetU32(offset_ptr); break;
+ default:
+ assert("GetMaxU32 unhandled case!" == NULL);
+ break;
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Extract a single integer value from the data and update the offset
+// pointed to by "offset_ptr". The size of the extracted integer
+// is specified by the "byte_size" argument. "byte_size" should have
+// a value >= 1 and <= 8 since the return value is only 64 bits
+// wide. Any "byte_size" values less than 1 or greater than 8 will
+// result in nothing being extracted, and zero being returned.
+//
+// RETURNS the integer value that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint64_t
+DataExtractor::GetMaxU64 (offset_t *offset_ptr, size_t size) const
+{
+ switch (size)
+ {
+ case 1: return GetU8 (offset_ptr); break;
+ case 2: return GetU16(offset_ptr); break;
+ case 4: return GetU32(offset_ptr); break;
+ case 8: return GetU64(offset_ptr); break;
+ default:
+ assert("GetMax64 unhandled case!" == NULL);
+ break;
+ }
+ return 0;
+}
+
+uint64_t
+DataExtractor::GetMaxU64_unchecked (offset_t *offset_ptr, size_t size) const
+{
+ switch (size)
+ {
+ case 1: return GetU8_unchecked (offset_ptr); break;
+ case 2: return GetU16_unchecked (offset_ptr); break;
+ case 4: return GetU32_unchecked (offset_ptr); break;
+ case 8: return GetU64_unchecked (offset_ptr); break;
+ default:
+ assert("GetMax64 unhandled case!" == NULL);
+ break;
+ }
+ return 0;
+}
+
+int64_t
+DataExtractor::GetMaxS64 (offset_t *offset_ptr, size_t size) const
+{
+ switch (size)
+ {
+ case 1: return (int8_t)GetU8 (offset_ptr); break;
+ case 2: return (int16_t)GetU16(offset_ptr); break;
+ case 4: return (int32_t)GetU32(offset_ptr); break;
+ case 8: return (int64_t)GetU64(offset_ptr); break;
+ default:
+ assert("GetMax64 unhandled case!" == NULL);
+ break;
+ }
+ return 0;
+}
+
+uint64_t
+DataExtractor::GetMaxU64Bitfield (offset_t *offset_ptr, size_t size, uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset) const
+{
+ uint64_t uval64 = GetMaxU64 (offset_ptr, size);
+ if (bitfield_bit_size > 0)
+ {
+ if (bitfield_bit_offset > 0)
+ uval64 >>= bitfield_bit_offset;
+ uint64_t bitfield_mask = ((1ul << bitfield_bit_size) - 1);
+ if (!bitfield_mask && bitfield_bit_offset == 0 && bitfield_bit_size == 64)
+ return uval64;
+ uval64 &= bitfield_mask;
+ }
+ return uval64;
+}
+
+int64_t
+DataExtractor::GetMaxS64Bitfield (offset_t *offset_ptr, size_t size, uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset) const
+{
+ int64_t sval64 = GetMaxS64 (offset_ptr, size);
+ if (bitfield_bit_size > 0)
+ {
+ if (bitfield_bit_offset > 0)
+ sval64 >>= bitfield_bit_offset;
+ uint64_t bitfield_mask = (((uint64_t)1) << bitfield_bit_size) - 1;
+ sval64 &= bitfield_mask;
+ // sign extend if needed
+ if (sval64 & (((uint64_t)1) << (bitfield_bit_size - 1)))
+ sval64 |= ~bitfield_mask;
+ }
+ return sval64;
+}
+
+
+float
+DataExtractor::GetFloat (offset_t *offset_ptr) const
+{
+ typedef float float_type;
+ float_type val = 0.0;
+ const size_t src_size = sizeof(float_type);
+ const float_type *src = (const float_type *)GetData (offset_ptr, src_size);
+ if (src)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ {
+ const uint8_t *src_data = (const uint8_t *)src;
+ uint8_t *dst_data = (uint8_t *)&val;
+ for (size_t i=0; i<sizeof(float_type); ++i)
+ dst_data[sizeof(float_type) - 1 - i] = src_data[i];
+ }
+ else
+ {
+ val = *src;
+ }
+ }
+ return val;
+}
+
+double
+DataExtractor::GetDouble (offset_t *offset_ptr) const
+{
+ typedef double float_type;
+ float_type val = 0.0;
+ const size_t src_size = sizeof(float_type);
+ const float_type *src = (const float_type *)GetData (offset_ptr, src_size);
+ if (src)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ {
+ const uint8_t *src_data = (const uint8_t *)src;
+ uint8_t *dst_data = (uint8_t *)&val;
+ for (size_t i=0; i<sizeof(float_type); ++i)
+ dst_data[sizeof(float_type) - 1 - i] = src_data[i];
+ }
+ else
+ {
+ val = *src;
+ }
+ }
+ return val;
+}
+
+
+long double
+DataExtractor::GetLongDouble (offset_t *offset_ptr) const
+{
+ long double val = 0.0;
+#if defined (__i386__) || defined (__amd64__) || defined (__x86_64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_X64)
+ *offset_ptr += CopyByteOrderedData (*offset_ptr, 10, &val, sizeof(val), lldb::endian::InlHostByteOrder());
+#else
+ *offset_ptr += CopyByteOrderedData (*offset_ptr, sizeof(val), &val, sizeof(val), lldb::endian::InlHostByteOrder());
+#endif
+ return val;
+}
+
+
+//------------------------------------------------------------------
+// Extract a single address from the data and update the offset
+// pointed to by "offset_ptr". The size of the extracted address
+// comes from the "this->m_addr_size" member variable and should be
+// set correctly prior to extracting any address values.
+//
+// RETURNS the address that was extracted, or zero on failure.
+//------------------------------------------------------------------
+uint64_t
+DataExtractor::GetAddress (offset_t *offset_ptr) const
+{
+ return GetMaxU64 (offset_ptr, m_addr_size);
+}
+
+uint64_t
+DataExtractor::GetAddress_unchecked (offset_t *offset_ptr) const
+{
+ return GetMaxU64_unchecked (offset_ptr, m_addr_size);
+}
+
+//------------------------------------------------------------------
+// Extract a single pointer from the data and update the offset
+// pointed to by "offset_ptr". The size of the extracted pointer
+// comes from the "this->m_addr_size" member variable and should be
+// set correctly prior to extracting any pointer values.
+//
+// RETURNS the pointer that was extracted, or zero on failure.
+//------------------------------------------------------------------
+uint64_t
+DataExtractor::GetPointer (offset_t *offset_ptr) const
+{
+ return GetMaxU64 (offset_ptr, m_addr_size);
+}
+
+//----------------------------------------------------------------------
+// GetDwarfEHPtr
+//
+// Used for calls when the value type is specified by a DWARF EH Frame
+// pointer encoding.
+//----------------------------------------------------------------------
+
+uint64_t
+DataExtractor::GetGNUEHPointer (offset_t *offset_ptr, uint32_t eh_ptr_enc, lldb::addr_t pc_rel_addr, lldb::addr_t text_addr, lldb::addr_t data_addr)//, BSDRelocs *data_relocs) const
+{
+ if (eh_ptr_enc == DW_EH_PE_omit)
+ return ULLONG_MAX; // Value isn't in the buffer...
+
+ uint64_t baseAddress = 0;
+ uint64_t addressValue = 0;
+ const uint32_t addr_size = GetAddressByteSize();
+
+ bool signExtendValue = false;
+ // Decode the base part or adjust our offset
+ switch (eh_ptr_enc & 0x70)
+ {
+ case DW_EH_PE_pcrel:
+ signExtendValue = true;
+ baseAddress = *offset_ptr;
+ if (pc_rel_addr != LLDB_INVALID_ADDRESS)
+ baseAddress += pc_rel_addr;
+// else
+// Log::GlobalWarning ("PC relative pointer encoding found with invalid pc relative address.");
+ break;
+
+ case DW_EH_PE_textrel:
+ signExtendValue = true;
+ if (text_addr != LLDB_INVALID_ADDRESS)
+ baseAddress = text_addr;
+// else
+// Log::GlobalWarning ("text relative pointer encoding being decoded with invalid text section address, setting base address to zero.");
+ break;
+
+ case DW_EH_PE_datarel:
+ signExtendValue = true;
+ if (data_addr != LLDB_INVALID_ADDRESS)
+ baseAddress = data_addr;
+// else
+// Log::GlobalWarning ("data relative pointer encoding being decoded with invalid data section address, setting base address to zero.");
+ break;
+
+ case DW_EH_PE_funcrel:
+ signExtendValue = true;
+ break;
+
+ case DW_EH_PE_aligned:
+ {
+ // SetPointerSize should be called prior to extracting these so the
+ // pointer size is cached
+ assert(addr_size != 0);
+ if (addr_size)
+ {
+ // Align to a address size boundary first
+ uint32_t alignOffset = *offset_ptr % addr_size;
+ if (alignOffset)
+ offset_ptr += addr_size - alignOffset;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Decode the value part
+ switch (eh_ptr_enc & DW_EH_PE_MASK_ENCODING)
+ {
+ case DW_EH_PE_absptr :
+ {
+ addressValue = GetAddress (offset_ptr);
+// if (data_relocs)
+// addressValue = data_relocs->Relocate(*offset_ptr - addr_size, *this, addressValue);
+ }
+ break;
+ case DW_EH_PE_uleb128 : addressValue = GetULEB128(offset_ptr); break;
+ case DW_EH_PE_udata2 : addressValue = GetU16(offset_ptr); break;
+ case DW_EH_PE_udata4 : addressValue = GetU32(offset_ptr); break;
+ case DW_EH_PE_udata8 : addressValue = GetU64(offset_ptr); break;
+ case DW_EH_PE_sleb128 : addressValue = GetSLEB128(offset_ptr); break;
+ case DW_EH_PE_sdata2 : addressValue = (int16_t)GetU16(offset_ptr); break;
+ case DW_EH_PE_sdata4 : addressValue = (int32_t)GetU32(offset_ptr); break;
+ case DW_EH_PE_sdata8 : addressValue = (int64_t)GetU64(offset_ptr); break;
+ default:
+ // Unhandled encoding type
+ assert(eh_ptr_enc);
+ break;
+ }
+
+ // Since we promote everything to 64 bit, we may need to sign extend
+ if (signExtendValue && addr_size < sizeof(baseAddress))
+ {
+ uint64_t sign_bit = 1ull << ((addr_size * 8ull) - 1ull);
+ if (sign_bit & addressValue)
+ {
+ uint64_t mask = ~sign_bit + 1;
+ addressValue |= mask;
+ }
+ }
+ return baseAddress + addressValue;
+}
+
+size_t
+DataExtractor::ExtractBytes (offset_t offset, offset_t length, ByteOrder dst_byte_order, void *dst) const
+{
+ const uint8_t *src = PeekData (offset, length);
+ if (src)
+ {
+ if (dst_byte_order != GetByteOrder())
+ {
+ for (uint32_t i=0; i<length; ++i)
+ ((uint8_t*)dst)[i] = src[length - i - 1];
+ }
+ else
+ ::memcpy (dst, src, length);
+ return length;
+ }
+ return 0;
+}
+
+// Extract data and swap if needed when doing the copy
+lldb::offset_t
+DataExtractor::CopyByteOrderedData (offset_t src_offset,
+ offset_t src_len,
+ void *dst_void_ptr,
+ offset_t dst_len,
+ ByteOrder dst_byte_order) const
+{
+ // Validate the source info
+ if (!ValidOffsetForDataOfSize(src_offset, src_len))
+ assert (ValidOffsetForDataOfSize(src_offset, src_len));
+ assert (src_len > 0);
+ assert (m_byte_order == eByteOrderBig || m_byte_order == eByteOrderLittle);
+
+ // Validate the destination info
+ assert (dst_void_ptr != NULL);
+ assert (dst_len > 0);
+ assert (dst_byte_order == eByteOrderBig || dst_byte_order == eByteOrderLittle);
+
+ // Must have valid byte orders set in this object and for destination
+ if (!(dst_byte_order == eByteOrderBig || dst_byte_order == eByteOrderLittle) ||
+ !(m_byte_order == eByteOrderBig || m_byte_order == eByteOrderLittle))
+ return 0;
+
+ uint32_t i;
+ uint8_t* dst = (uint8_t*)dst_void_ptr;
+ const uint8_t* src = (const uint8_t *)PeekData (src_offset, src_len);
+ if (src)
+ {
+ if (dst_len >= src_len)
+ {
+ // We are copying the entire value from src into dst.
+ // Calculate how many, if any, zeroes we need for the most
+ // significant bytes if "dst_len" is greater than "src_len"...
+ const size_t num_zeroes = dst_len - src_len;
+ if (dst_byte_order == eByteOrderBig)
+ {
+ // Big endian, so we lead with zeroes...
+ if (num_zeroes > 0)
+ ::memset (dst, 0, num_zeroes);
+ // Then either copy or swap the rest
+ if (m_byte_order == eByteOrderBig)
+ {
+ ::memcpy (dst + num_zeroes, src, src_len);
+ }
+ else
+ {
+ for (i=0; i<src_len; ++i)
+ dst[i+num_zeroes] = src[src_len - 1 - i];
+ }
+ }
+ else
+ {
+ // Little endian destination, so we lead the value bytes
+ if (m_byte_order == eByteOrderBig)
+ {
+ for (i=0; i<src_len; ++i)
+ dst[i] = src[src_len - 1 - i];
+ }
+ else
+ {
+ ::memcpy (dst, src, src_len);
+ }
+ // And zero the rest...
+ if (num_zeroes > 0)
+ ::memset (dst + src_len, 0, num_zeroes);
+ }
+ return src_len;
+ }
+ else
+ {
+ // We are only copying some of the value from src into dst..
+
+ if (dst_byte_order == eByteOrderBig)
+ {
+ // Big endian dst
+ if (m_byte_order == eByteOrderBig)
+ {
+ // Big endian dst, with big endian src
+ ::memcpy (dst, src + (src_len - dst_len), dst_len);
+ }
+ else
+ {
+ // Big endian dst, with little endian src
+ for (i=0; i<dst_len; ++i)
+ dst[i] = src[dst_len - 1 - i];
+ }
+ }
+ else
+ {
+ // Little endian dst
+ if (m_byte_order == eByteOrderBig)
+ {
+ // Little endian dst, with big endian src
+ for (i=0; i<dst_len; ++i)
+ dst[i] = src[src_len - 1 - i];
+ }
+ else
+ {
+ // Little endian dst, with big endian src
+ ::memcpy (dst, src, dst_len);
+ }
+ }
+ return dst_len;
+ }
+
+ }
+ return 0;
+}
+
+
+//----------------------------------------------------------------------
+// Extracts a variable length NULL terminated C string from
+// the data at the offset pointed to by "offset_ptr". The
+// "offset_ptr" will be updated with the offset of the byte that
+// follows the NULL terminator byte.
+//
+// If the offset pointed to by "offset_ptr" is out of bounds, or if
+// "length" is non-zero and there aren't enough avaialable
+// bytes, NULL will be returned and "offset_ptr" will not be
+// updated.
+//----------------------------------------------------------------------
+const char*
+DataExtractor::GetCStr (offset_t *offset_ptr) const
+{
+ const char *cstr = (const char *)PeekData (*offset_ptr, 1);
+ if (cstr)
+ {
+ const char *cstr_end = cstr;
+ const char *end = (const char *)m_end;
+ while (cstr_end < end && *cstr_end)
+ ++cstr_end;
+
+ // Now we are either at the end of the data or we point to the
+ // NULL C string terminator with cstr_end...
+ if (*cstr_end == '\0')
+ {
+ // Advance the offset with one extra byte for the NULL terminator
+ *offset_ptr += (cstr_end - cstr + 1);
+ return cstr;
+ }
+
+ // We reached the end of the data without finding a NULL C string
+ // terminator. Fall through and return NULL otherwise anyone that
+ // would have used the result as a C string can wonder into
+ // unknown memory...
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Extracts a NULL terminated C string from the fixed length field of
+// length "len" at the offset pointed to by "offset_ptr".
+// The "offset_ptr" will be updated with the offset of the byte that
+// follows the fixed length field.
+//
+// If the offset pointed to by "offset_ptr" is out of bounds, or if
+// the offset plus the length of the field is out of bounds, or if the
+// field does not contain a NULL terminator byte, NULL will be returned
+// and "offset_ptr" will not be updated.
+//----------------------------------------------------------------------
+const char*
+DataExtractor::GetCStr (offset_t *offset_ptr, offset_t len) const
+{
+ const char *cstr = (const char *)PeekData (*offset_ptr, len);
+ if (cstr)
+ {
+ if (memchr (cstr, '\0', len) == NULL)
+ {
+ return NULL;
+ }
+ *offset_ptr += len;
+ return cstr;
+ }
+ return NULL;
+}
+
+//------------------------------------------------------------------
+// Peeks at a string in the contained data. No verification is done
+// to make sure the entire string lies within the bounds of this
+// object's data, only "offset" is verified to be a valid offset.
+//
+// Returns a valid C string pointer if "offset" is a valid offset in
+// this object's data, else NULL is returned.
+//------------------------------------------------------------------
+const char *
+DataExtractor::PeekCStr (offset_t offset) const
+{
+ return (const char *)PeekData (offset, 1);
+}
+
+//----------------------------------------------------------------------
+// Extracts an unsigned LEB128 number from this object's data
+// starting at the offset pointed to by "offset_ptr". The offset
+// pointed to by "offset_ptr" will be updated with the offset of the
+// byte following the last extracted byte.
+//
+// Returned the extracted integer value.
+//----------------------------------------------------------------------
+uint64_t
+DataExtractor::GetULEB128 (offset_t *offset_ptr) const
+{
+ const uint8_t *src = (const uint8_t *)PeekData (*offset_ptr, 1);
+ if (src == NULL)
+ return 0;
+
+ const uint8_t *end = m_end;
+
+ if (src < end)
+ {
+ uint64_t result = *src++;
+ if (result >= 0x80)
+ {
+ result &= 0x7f;
+ int shift = 7;
+ while (src < end)
+ {
+ uint8_t byte = *src++;
+ result |= (byte & 0x7f) << shift;
+ if ((byte & 0x80) == 0)
+ break;
+ shift += 7;
+ }
+ }
+ *offset_ptr = src - m_start;
+ return result;
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Extracts an signed LEB128 number from this object's data
+// starting at the offset pointed to by "offset_ptr". The offset
+// pointed to by "offset_ptr" will be updated with the offset of the
+// byte following the last extracted byte.
+//
+// Returned the extracted integer value.
+//----------------------------------------------------------------------
+int64_t
+DataExtractor::GetSLEB128 (offset_t *offset_ptr) const
+{
+ const uint8_t *src = (const uint8_t *)PeekData (*offset_ptr, 1);
+ if (src == NULL)
+ return 0;
+
+ const uint8_t *end = m_end;
+
+ if (src < end)
+ {
+ int64_t result = 0;
+ int shift = 0;
+ int size = sizeof (int64_t) * 8;
+
+ uint8_t byte = 0;
+ int bytecount = 0;
+
+ while (src < end)
+ {
+ bytecount++;
+ byte = *src++;
+ result |= (byte & 0x7f) << shift;
+ shift += 7;
+ if ((byte & 0x80) == 0)
+ break;
+ }
+
+ // Sign bit of byte is 2nd high order bit (0x40)
+ if (shift < size && (byte & 0x40))
+ result |= - (1 << shift);
+
+ *offset_ptr += bytecount;
+ return result;
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Skips a ULEB128 number (signed or unsigned) from this object's
+// data starting at the offset pointed to by "offset_ptr". The
+// offset pointed to by "offset_ptr" will be updated with the offset
+// of the byte following the last extracted byte.
+//
+// Returns the number of bytes consumed during the extraction.
+//----------------------------------------------------------------------
+uint32_t
+DataExtractor::Skip_LEB128 (offset_t *offset_ptr) const
+{
+ uint32_t bytes_consumed = 0;
+ const uint8_t *src = (const uint8_t *)PeekData (*offset_ptr, 1);
+ if (src == NULL)
+ return 0;
+
+ const uint8_t *end = m_end;
+
+ if (src < end)
+ {
+ const uint8_t *src_pos = src;
+ while ((src_pos < end) && (*src_pos++ & 0x80))
+ ++bytes_consumed;
+ *offset_ptr += src_pos - src;
+ }
+ return bytes_consumed;
+}
+
+static bool
+GetAPInt (const DataExtractor &data, lldb::offset_t *offset_ptr, lldb::offset_t byte_size, llvm::APInt &result)
+{
+ llvm::SmallVector<uint64_t, 2> uint64_array;
+ lldb::offset_t bytes_left = byte_size;
+ uint64_t u64;
+ const lldb::ByteOrder byte_order = data.GetByteOrder();
+ if (byte_order == lldb::eByteOrderLittle)
+ {
+ while (bytes_left > 0)
+ {
+ if (bytes_left >= 8)
+ {
+ u64 = data.GetU64(offset_ptr);
+ bytes_left -= 8;
+ }
+ else
+ {
+ u64 = data.GetMaxU64(offset_ptr, (uint32_t)bytes_left);
+ bytes_left = 0;
+ }
+ uint64_array.push_back(u64);
+ }
+ result = llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
+ return true;
+ }
+ else if (byte_order == lldb::eByteOrderBig)
+ {
+ lldb::offset_t be_offset = *offset_ptr + byte_size;
+ lldb::offset_t temp_offset;
+ while (bytes_left > 0)
+ {
+ if (bytes_left >= 8)
+ {
+ be_offset -= 8;
+ temp_offset = be_offset;
+ u64 = data.GetU64(&temp_offset);
+ bytes_left -= 8;
+ }
+ else
+ {
+ be_offset -= bytes_left;
+ temp_offset = be_offset;
+ u64 = data.GetMaxU64(&temp_offset, (uint32_t)bytes_left);
+ bytes_left = 0;
+ }
+ uint64_array.push_back(u64);
+ }
+ *offset_ptr += byte_size;
+ result = llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
+ return true;
+ }
+ return false;
+}
+
+static lldb::offset_t
+DumpAPInt (Stream *s, const DataExtractor &data, lldb::offset_t offset, lldb::offset_t byte_size, bool is_signed, unsigned radix)
+{
+ llvm::APInt apint;
+ if (GetAPInt (data, &offset, byte_size, apint))
+ {
+ std::string apint_str(apint.toString(radix, is_signed));
+ switch (radix)
+ {
+ case 2:
+ s->Write ("0b", 2);
+ break;
+ case 8:
+ s->Write ("0", 1);
+ break;
+ case 10:
+ break;
+ }
+ s->Write(apint_str.c_str(), apint_str.size());
+ }
+ return offset;
+}
+
+static float half2float (uint16_t half)
+{
+ union{ float f; uint32_t u;}u;
+ int32_t v = (int16_t) half;
+
+ if( 0 == (v & 0x7c00))
+ {
+ u.u = v & 0x80007FFFU;
+ return u.f * 0x1.0p125f;
+ }
+
+ v <<= 13;
+ u.u = v | 0x70000000U;
+ return u.f * 0x1.0p-112f;
+}
+
+lldb::offset_t
+DataExtractor::Dump (Stream *s,
+ offset_t start_offset,
+ lldb::Format item_format,
+ size_t item_byte_size,
+ size_t item_count,
+ size_t num_per_line,
+ uint64_t base_addr,
+ uint32_t item_bit_size, // If zero, this is not a bitfield value, if non-zero, the value is a bitfield
+ uint32_t item_bit_offset, // If "item_bit_size" is non-zero, this is the shift amount to apply to a bitfield
+ ExecutionContextScope *exe_scope) const
+{
+ if (s == NULL)
+ return start_offset;
+
+ if (item_format == eFormatPointer)
+ {
+ if (item_byte_size != 4 && item_byte_size != 8)
+ item_byte_size = s->GetAddressByteSize();
+ }
+
+ offset_t offset = start_offset;
+
+ if (item_format == eFormatInstruction)
+ {
+ TargetSP target_sp;
+ if (exe_scope)
+ target_sp = exe_scope->CalculateTarget();
+ if (target_sp)
+ {
+ DisassemblerSP disassembler_sp (Disassembler::FindPlugin(target_sp->GetArchitecture(), NULL, NULL));
+ if (disassembler_sp)
+ {
+ lldb::addr_t addr = base_addr + start_offset;
+ lldb_private::Address so_addr;
+ bool data_from_file = true;
+ if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr, so_addr))
+ {
+ data_from_file = false;
+ }
+ else
+ {
+ if (target_sp->GetSectionLoadList().IsEmpty() || !target_sp->GetImages().ResolveFileAddress(addr, so_addr))
+ so_addr.SetRawAddress(addr);
+ }
+
+ size_t bytes_consumed = disassembler_sp->DecodeInstructions (so_addr, *this, start_offset, item_count, false, data_from_file);
+
+ if (bytes_consumed)
+ {
+ offset += bytes_consumed;
+ const bool show_address = base_addr != LLDB_INVALID_ADDRESS;
+ const bool show_bytes = true;
+ ExecutionContext exe_ctx;
+ exe_scope->CalculateExecutionContext(exe_ctx);
+ disassembler_sp->GetInstructionList().Dump (s, show_address, show_bytes, &exe_ctx);
+
+ // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
+ // I'll fix that but for now, just clear the list and it will go away nicely.
+ disassembler_sp->GetInstructionList().Clear();
+ }
+ }
+ }
+ else
+ s->Printf ("invalid target");
+
+ return offset;
+ }
+
+ if ((item_format == eFormatOSType || item_format == eFormatAddressInfo) && item_byte_size > 8)
+ item_format = eFormatHex;
+
+ lldb::offset_t line_start_offset = start_offset;
+ for (uint32_t count = 0; ValidOffset(offset) && count < item_count; ++count)
+ {
+ if ((count % num_per_line) == 0)
+ {
+ if (count > 0)
+ {
+ if (item_format == eFormatBytesWithASCII && offset > line_start_offset)
+ {
+ s->Printf("%*s", static_cast<int>((num_per_line - (offset - line_start_offset)) * 3 + 2), "");
+ Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, LLDB_INVALID_OFFSET, LLDB_INVALID_ADDRESS, 0, 0);
+ }
+ s->EOL();
+ }
+ if (base_addr != LLDB_INVALID_ADDRESS)
+ s->Printf ("0x%8.8" PRIx64 ": ", (uint64_t)(base_addr + (offset - start_offset)));
+ line_start_offset = offset;
+ }
+ else
+ if (item_format != eFormatChar &&
+ item_format != eFormatCharPrintable &&
+ item_format != eFormatCharArray &&
+ count > 0)
+ {
+ s->PutChar(' ');
+ }
+
+ uint32_t i;
+ switch (item_format)
+ {
+ case eFormatBoolean:
+ if (item_byte_size <= 8)
+ s->Printf ("%s", GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset) ? "true" : "false");
+ else
+ {
+ s->Printf("error: unsupported byte size (%zu) for boolean format", item_byte_size);
+ return offset;
+ }
+ break;
+
+ case eFormatBinary:
+ if (item_byte_size <= 8)
+ {
+ uint64_t uval64 = GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset);
+ // Avoid std::bitset<64>::to_string() since it is missing in
+ // earlier C++ libraries
+ std::string binary_value(64, '0');
+ std::bitset<64> bits(uval64);
+ for (i = 0; i < 64; ++i)
+ if (bits[i])
+ binary_value[64 - 1 - i] = '1';
+ if (item_bit_size > 0)
+ s->Printf("0b%s", binary_value.c_str() + 64 - item_bit_size);
+ else if (item_byte_size > 0 && item_byte_size <= 8)
+ s->Printf("0b%s", binary_value.c_str() + 64 - item_byte_size * 8);
+ }
+ else
+ {
+ const bool is_signed = false;
+ const unsigned radix = 2;
+ offset = DumpAPInt (s, *this, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatBytes:
+ case eFormatBytesWithASCII:
+ for (i=0; i<item_byte_size; ++i)
+ {
+ s->Printf ("%2.2x", GetU8(&offset));
+ }
+ // Put an extra space between the groups of bytes if more than one
+ // is being dumped in a group (item_byte_size is more than 1).
+ if (item_byte_size > 1)
+ s->PutChar(' ');
+ break;
+
+ case eFormatChar:
+ case eFormatCharPrintable:
+ case eFormatCharArray:
+ {
+ // If we are only printing one character surround it with single
+ // quotes
+ if (item_count == 1 && item_format == eFormatChar)
+ s->PutChar('\'');
+
+ const uint64_t ch = GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset);
+ if (isprint(ch))
+ s->Printf ("%c", (char)ch);
+ else if (item_format != eFormatCharPrintable)
+ {
+ switch (ch)
+ {
+ case '\033': s->Printf ("\\e"); break;
+ case '\a': s->Printf ("\\a"); break;
+ case '\b': s->Printf ("\\b"); break;
+ case '\f': s->Printf ("\\f"); break;
+ case '\n': s->Printf ("\\n"); break;
+ case '\r': s->Printf ("\\r"); break;
+ case '\t': s->Printf ("\\t"); break;
+ case '\v': s->Printf ("\\v"); break;
+ case '\0': s->Printf ("\\0"); break;
+ default:
+ if (item_byte_size == 1)
+ s->Printf ("\\x%2.2x", (uint8_t)ch);
+ else
+ s->Printf ("%" PRIu64, ch);
+ break;
+ }
+ }
+ else
+ {
+ s->PutChar(NON_PRINTABLE_CHAR);
+ }
+
+ // If we are only printing one character surround it with single quotes
+ if (item_count == 1 && item_format == eFormatChar)
+ s->PutChar('\'');
+ }
+ break;
+
+ case eFormatEnum: // Print enum value as a signed integer when we don't get the enum type
+ case eFormatDecimal:
+ if (item_byte_size <= 8)
+ s->Printf ("%" PRId64, GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ else
+ {
+ const bool is_signed = true;
+ const unsigned radix = 10;
+ offset = DumpAPInt (s, *this, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatUnsigned:
+ if (item_byte_size <= 8)
+ s->Printf ("%" PRIu64, GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ else
+ {
+ const bool is_signed = false;
+ const unsigned radix = 10;
+ offset = DumpAPInt (s, *this, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatOctal:
+ if (item_byte_size <= 8)
+ s->Printf ("0%" PRIo64, GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ else
+ {
+ const bool is_signed = false;
+ const unsigned radix = 8;
+ offset = DumpAPInt (s, *this, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatOSType:
+ {
+ uint64_t uval64 = GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset);
+ s->PutChar('\'');
+ for (i=0; i<item_byte_size; ++i)
+ {
+ uint8_t ch = (uint8_t)(uval64 >> ((item_byte_size - i - 1) * 8));
+ if (isprint(ch))
+ s->Printf ("%c", ch);
+ else
+ {
+ switch (ch)
+ {
+ case '\033': s->Printf ("\\e"); break;
+ case '\a': s->Printf ("\\a"); break;
+ case '\b': s->Printf ("\\b"); break;
+ case '\f': s->Printf ("\\f"); break;
+ case '\n': s->Printf ("\\n"); break;
+ case '\r': s->Printf ("\\r"); break;
+ case '\t': s->Printf ("\\t"); break;
+ case '\v': s->Printf ("\\v"); break;
+ case '\0': s->Printf ("\\0"); break;
+ default: s->Printf ("\\x%2.2x", ch); break;
+ }
+ }
+ }
+ s->PutChar('\'');
+ }
+ break;
+
+ case eFormatCString:
+ {
+ const char *cstr = GetCStr(&offset);
+
+ if (!cstr)
+ {
+ s->Printf("NULL");
+ offset = LLDB_INVALID_OFFSET;
+ }
+ else
+ {
+ s->PutChar('\"');
+
+ while (const char c = *cstr)
+ {
+ if (isprint(c))
+ {
+ s->PutChar(c);
+ }
+ else
+ {
+ switch (c)
+ {
+ case '\033': s->Printf ("\\e"); break;
+ case '\a': s->Printf ("\\a"); break;
+ case '\b': s->Printf ("\\b"); break;
+ case '\f': s->Printf ("\\f"); break;
+ case '\n': s->Printf ("\\n"); break;
+ case '\r': s->Printf ("\\r"); break;
+ case '\t': s->Printf ("\\t"); break;
+ case '\v': s->Printf ("\\v"); break;
+ default: s->Printf ("\\x%2.2x", c); break;
+ }
+ }
+
+ ++cstr;
+ }
+
+ s->PutChar('\"');
+ }
+ }
+ break;
+
+
+ case eFormatPointer:
+ s->Address(GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset), sizeof (addr_t));
+ break;
+
+
+ case eFormatComplexInteger:
+ {
+ size_t complex_int_byte_size = item_byte_size / 2;
+
+ if (complex_int_byte_size <= 8)
+ {
+ s->Printf("%" PRIu64, GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
+ s->Printf(" + %" PRIu64 "i", GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
+ }
+ else
+ {
+ s->Printf("error: unsupported byte size (%zu) for complex integer format", item_byte_size);
+ return offset;
+ }
+ }
+ break;
+
+ case eFormatComplex:
+ if (sizeof(float) * 2 == item_byte_size)
+ {
+ float f32_1 = GetFloat (&offset);
+ float f32_2 = GetFloat (&offset);
+
+ s->Printf ("%g + %gi", f32_1, f32_2);
+ break;
+ }
+ else if (sizeof(double) * 2 == item_byte_size)
+ {
+ double d64_1 = GetDouble (&offset);
+ double d64_2 = GetDouble (&offset);
+
+ s->Printf ("%lg + %lgi", d64_1, d64_2);
+ break;
+ }
+ else if (sizeof(long double) * 2 == item_byte_size)
+ {
+ long double ld64_1 = GetLongDouble (&offset);
+ long double ld64_2 = GetLongDouble (&offset);
+ s->Printf ("%Lg + %Lgi", ld64_1, ld64_2);
+ break;
+ }
+ else
+ {
+ s->Printf("error: unsupported byte size (%zu) for complex float format", item_byte_size);
+ return offset;
+ }
+ break;
+
+ default:
+ case eFormatDefault:
+ case eFormatHex:
+ case eFormatHexUppercase:
+ {
+ bool wantsuppercase = (item_format == eFormatHexUppercase);
+ if (item_byte_size <= 8)
+ {
+ s->Printf(wantsuppercase ? "0x%*.*" PRIX64 : "0x%*.*" PRIx64, (int)(2 * item_byte_size), (int)(2 * item_byte_size), GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ }
+ else
+ {
+ assert (item_bit_size == 0 && item_bit_offset == 0);
+ s->PutCString("0x");
+ const uint8_t *bytes = (const uint8_t* )GetData(&offset, item_byte_size);
+ if (bytes)
+ {
+ uint32_t idx;
+ if (m_byte_order == eByteOrderBig)
+ {
+ for (idx = 0; idx < item_byte_size; ++idx)
+ s->Printf(wantsuppercase ? "%2.2X" : "%2.2x", bytes[idx]);
+ }
+ else
+ {
+ for (idx = 0; idx < item_byte_size; ++idx)
+ s->Printf(wantsuppercase ? "%2.2X" : "%2.2x", bytes[item_byte_size - 1 - idx]);
+ }
+ }
+ }
+ }
+ break;
+
+ case eFormatFloat:
+ {
+ TargetSP target_sp;
+ bool used_apfloat = false;
+ if (exe_scope)
+ target_sp = exe_scope->CalculateTarget();
+ if (target_sp)
+ {
+ ClangASTContext *clang_ast = target_sp->GetScratchClangASTContext();
+ if (clang_ast)
+ {
+ clang::ASTContext *ast = clang_ast->getASTContext();
+ if (ast)
+ {
+ llvm::SmallVector<char, 256> sv;
+ // Show full precision when printing float values
+ const unsigned format_precision = 0;
+ const unsigned format_max_padding = 100;
+ size_t item_bit_size = item_byte_size * 8;
+
+ if (item_bit_size == ast->getTypeSize(ast->FloatTy))
+ {
+ llvm::APInt apint(item_bit_size, this->GetMaxU64(&offset, item_byte_size));
+ llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->FloatTy), apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ }
+ else if (item_bit_size == ast->getTypeSize(ast->DoubleTy))
+ {
+ llvm::APInt apint;
+ if (GetAPInt (*this, &offset, item_byte_size, apint))
+ {
+ llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->DoubleTy), apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ }
+ }
+ else if (item_bit_size == ast->getTypeSize(ast->LongDoubleTy))
+ {
+ llvm::APInt apint;
+ switch (target_sp->GetArchitecture().GetCore())
+ {
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ case ArchSpec::eCore_x86_64_x86_64:
+ // clang will assert when contructing the apfloat if we use a 16 byte integer value
+ if (GetAPInt (*this, &offset, 10, apint))
+ {
+ llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->LongDoubleTy), apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ }
+ break;
+
+ default:
+ if (GetAPInt (*this, &offset, item_byte_size, apint))
+ {
+ llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->LongDoubleTy), apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ }
+ break;
+ }
+ }
+ else if (item_bit_size == ast->getTypeSize(ast->HalfTy))
+ {
+ llvm::APInt apint(item_bit_size, this->GetU16(&offset));
+ llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->HalfTy), apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ }
+
+ if (!sv.empty())
+ {
+ s->Printf("%*.*s", (int)sv.size(), (int)sv.size(), sv.data());
+ used_apfloat = true;
+ }
+ }
+ }
+ }
+
+ if (!used_apfloat)
+ {
+ std::ostringstream ss;
+ if (item_byte_size == sizeof(float) || item_byte_size == 2)
+ {
+ float f;
+ if (item_byte_size == 2)
+ {
+ uint16_t half = this->GetU16(&offset);
+ f = half2float(half);
+ }
+ else
+ {
+ f = GetFloat (&offset);
+ }
+ ss.precision(std::numeric_limits<float>::digits10);
+ ss << f;
+ }
+ else if (item_byte_size == sizeof(double))
+ {
+ ss.precision(std::numeric_limits<double>::digits10);
+ ss << GetDouble(&offset);
+ }
+ else if (item_byte_size == sizeof(long double) || item_byte_size == 10)
+ {
+ ss.precision(std::numeric_limits<long double>::digits10);
+ ss << GetLongDouble(&offset);
+ }
+ else
+ {
+ s->Printf("error: unsupported byte size (%zu) for float format", item_byte_size);
+ return offset;
+ }
+ ss.flush();
+ s->Printf("%s", ss.str().c_str());
+ }
+ }
+ break;
+
+ case eFormatUnicode16:
+ s->Printf("U+%4.4x", GetU16 (&offset));
+ break;
+
+ case eFormatUnicode32:
+ s->Printf("U+0x%8.8x", GetU32 (&offset));
+ break;
+
+ case eFormatAddressInfo:
+ {
+ addr_t addr = GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset);
+ s->Printf("0x%*.*" PRIx64, (int)(2 * item_byte_size), (int)(2 * item_byte_size), addr);
+ if (exe_scope)
+ {
+ TargetSP target_sp (exe_scope->CalculateTarget());
+ lldb_private::Address so_addr;
+ if (target_sp)
+ {
+ if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr, so_addr))
+ {
+ s->PutChar(' ');
+ so_addr.Dump (s,
+ exe_scope,
+ Address::DumpStyleResolvedDescription,
+ Address::DumpStyleModuleWithFileAddress);
+ }
+ else
+ {
+ so_addr.SetOffset(addr);
+ so_addr.Dump (s, exe_scope, Address::DumpStyleResolvedPointerDescription);
+ }
+ }
+ }
+ }
+ break;
+
+ case eFormatHexFloat:
+ if (sizeof(float) == item_byte_size)
+ {
+ char float_cstr[256];
+ llvm::APFloat ap_float (GetFloat (&offset));
+ ap_float.convertToHexString (float_cstr, 0, false, llvm::APFloat::rmNearestTiesToEven);
+ s->Printf ("%s", float_cstr);
+ break;
+ }
+ else if (sizeof(double) == item_byte_size)
+ {
+ char float_cstr[256];
+ llvm::APFloat ap_float (GetDouble (&offset));
+ ap_float.convertToHexString (float_cstr, 0, false, llvm::APFloat::rmNearestTiesToEven);
+ s->Printf ("%s", float_cstr);
+ break;
+ }
+ else
+ {
+ s->Printf("error: unsupported byte size (%zu) for hex float format", item_byte_size);
+ return offset;
+ }
+ break;
+
+// please keep the single-item formats below in sync with FormatManager::GetSingleItemFormat
+// if you fail to do so, users will start getting different outputs depending on internal
+// implementation details they should not care about ||
+ case eFormatVectorOfChar: // ||
+ s->PutChar('{'); // \/
+ offset = Dump (s, offset, eFormatCharArray, 1, item_byte_size, item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt8:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatDecimal, 1, item_byte_size, item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt8:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatHex, 1, item_byte_size, item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt16:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatDecimal, sizeof(uint16_t), item_byte_size / sizeof(uint16_t), item_byte_size / sizeof(uint16_t), LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt16:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatHex, sizeof(uint16_t), item_byte_size / sizeof(uint16_t), item_byte_size / sizeof(uint16_t), LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt32:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatDecimal, sizeof(uint32_t), item_byte_size / sizeof(uint32_t), item_byte_size / sizeof(uint32_t), LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt32:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatHex, sizeof(uint32_t), item_byte_size / sizeof(uint32_t), item_byte_size / sizeof(uint32_t), LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt64:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatDecimal, sizeof(uint64_t), item_byte_size / sizeof(uint64_t), item_byte_size / sizeof(uint64_t), LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt64:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatHex, sizeof(uint64_t), item_byte_size / sizeof(uint64_t), item_byte_size / sizeof(uint64_t), LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfFloat32:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatFloat, 4, item_byte_size / 4, item_byte_size / 4, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfFloat64:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatFloat, 8, item_byte_size / 8, item_byte_size / 8, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt128:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatHex, 16, item_byte_size / 16, item_byte_size / 16, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+ }
+ }
+
+ if (item_format == eFormatBytesWithASCII && offset > line_start_offset)
+ {
+ s->Printf("%*s", static_cast<int>((num_per_line - (offset - line_start_offset)) * 3 + 2), "");
+ Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, LLDB_INVALID_OFFSET, LLDB_INVALID_ADDRESS, 0, 0);
+ }
+ return offset; // Return the offset at which we ended up
+}
+
+//----------------------------------------------------------------------
+// Dumps bytes from this object's data to the stream "s" starting
+// "start_offset" bytes into this data, and ending with the byte
+// before "end_offset". "base_addr" will be added to the offset
+// into the dumped data when showing the offset into the data in the
+// output information. "num_per_line" objects of type "type" will
+// be dumped with the option to override the format for each object
+// with "type_format". "type_format" is a printf style formatting
+// string. If "type_format" is NULL, then an appropriate format
+// string will be used for the supplied "type". If the stream "s"
+// is NULL, then the output will be send to Log().
+//----------------------------------------------------------------------
+lldb::offset_t
+DataExtractor::PutToLog
+(
+ Log *log,
+ offset_t start_offset,
+ offset_t length,
+ uint64_t base_addr,
+ uint32_t num_per_line,
+ DataExtractor::Type type,
+ const char *format
+) const
+{
+ if (log == NULL)
+ return start_offset;
+
+ offset_t offset;
+ offset_t end_offset;
+ uint32_t count;
+ StreamString sstr;
+ for (offset = start_offset, end_offset = offset + length, count = 0; ValidOffset(offset) && offset < end_offset; ++count)
+ {
+ if ((count % num_per_line) == 0)
+ {
+ // Print out any previous string
+ if (sstr.GetSize() > 0)
+ {
+ log->Printf("%s", sstr.GetData());
+ sstr.Clear();
+ }
+ // Reset string offset and fill the current line string with address:
+ if (base_addr != LLDB_INVALID_ADDRESS)
+ sstr.Printf("0x%8.8" PRIx64 ":", (uint64_t)(base_addr + (offset - start_offset)));
+ }
+
+ switch (type)
+ {
+ case TypeUInt8: sstr.Printf (format ? format : " %2.2x", GetU8(&offset)); break;
+ case TypeChar:
+ {
+ char ch = GetU8(&offset);
+ sstr.Printf (format ? format : " %c", isprint(ch) ? ch : ' ');
+ }
+ break;
+ case TypeUInt16: sstr.Printf (format ? format : " %4.4x", GetU16(&offset)); break;
+ case TypeUInt32: sstr.Printf (format ? format : " %8.8x", GetU32(&offset)); break;
+ case TypeUInt64: sstr.Printf (format ? format : " %16.16" PRIx64, GetU64(&offset)); break;
+ case TypePointer: sstr.Printf (format ? format : " 0x%" PRIx64, GetAddress(&offset)); break;
+ case TypeULEB128: sstr.Printf (format ? format : " 0x%" PRIx64, GetULEB128(&offset)); break;
+ case TypeSLEB128: sstr.Printf (format ? format : " %" PRId64, GetSLEB128(&offset)); break;
+ }
+ }
+
+ if (sstr.GetSize() > 0)
+ log->Printf("%s", sstr.GetData());
+
+ return offset; // Return the offset at which we ended up
+}
+
+//----------------------------------------------------------------------
+// DumpUUID
+//
+// Dump out a UUID starting at 'offset' bytes into the buffer
+//----------------------------------------------------------------------
+void
+DataExtractor::DumpUUID (Stream *s, offset_t offset) const
+{
+ if (s)
+ {
+ const uint8_t *uuid_data = PeekData(offset, 16);
+ if ( uuid_data )
+ {
+ lldb_private::UUID uuid(uuid_data, 16);
+ uuid.Dump(s);
+ }
+ else
+ {
+ s->Printf("<not enough data for UUID at offset 0x%8.8" PRIx64 ">", offset);
+ }
+ }
+}
+
+void
+DataExtractor::DumpHexBytes (Stream *s,
+ const void *src,
+ size_t src_len,
+ uint32_t bytes_per_line,
+ addr_t base_addr)
+{
+ DataExtractor data (src, src_len, eByteOrderLittle, 4);
+ data.Dump (s,
+ 0, // Offset into "src"
+ eFormatBytes, // Dump as hex bytes
+ 1, // Size of each item is 1 for single bytes
+ src_len, // Number of bytes
+ bytes_per_line, // Num bytes per line
+ base_addr, // Base address
+ 0, 0); // Bitfield info
+}
+
+size_t
+DataExtractor::Copy (DataExtractor &dest_data) const
+{
+ if (m_data_sp.get())
+ {
+ // we can pass along the SP to the data
+ dest_data.SetData(m_data_sp);
+ }
+ else
+ {
+ const uint8_t *base_ptr = m_start;
+ size_t data_size = GetByteSize();
+ dest_data.SetData(DataBufferSP(new DataBufferHeap(base_ptr, data_size)));
+ }
+ return GetByteSize();
+}
+
+bool
+DataExtractor::Append(DataExtractor& rhs)
+{
+ if (rhs.GetByteOrder() != GetByteOrder())
+ return false;
+
+ if (rhs.GetByteSize() == 0)
+ return true;
+
+ if (GetByteSize() == 0)
+ return (rhs.Copy(*this) > 0);
+
+ size_t bytes = GetByteSize() + rhs.GetByteSize();
+
+ DataBufferHeap *buffer_heap_ptr = NULL;
+ DataBufferSP buffer_sp(buffer_heap_ptr = new DataBufferHeap(bytes, 0));
+
+ if (buffer_sp.get() == NULL || buffer_heap_ptr == NULL)
+ return false;
+
+ uint8_t* bytes_ptr = buffer_heap_ptr->GetBytes();
+
+ memcpy(bytes_ptr, GetDataStart(), GetByteSize());
+ memcpy(bytes_ptr + GetByteSize(), rhs.GetDataStart(), rhs.GetByteSize());
+
+ SetData(buffer_sp);
+
+ return true;
+}
+
+bool
+DataExtractor::Append(void* buf, offset_t length)
+{
+ if (buf == NULL)
+ return false;
+
+ if (length == 0)
+ return true;
+
+ size_t bytes = GetByteSize() + length;
+
+ DataBufferHeap *buffer_heap_ptr = NULL;
+ DataBufferSP buffer_sp(buffer_heap_ptr = new DataBufferHeap(bytes, 0));
+
+ if (buffer_sp.get() == NULL || buffer_heap_ptr == NULL)
+ return false;
+
+ uint8_t* bytes_ptr = buffer_heap_ptr->GetBytes();
+
+ if (GetByteSize() > 0)
+ memcpy(bytes_ptr, GetDataStart(), GetByteSize());
+
+ memcpy(bytes_ptr + GetByteSize(), buf, length);
+
+ SetData(buffer_sp);
+
+ return true;
+}
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp
new file mode 100644
index 0000000..d1d2ebb
--- /dev/null
+++ b/source/Core/Debugger.cpp
@@ -0,0 +1,2695 @@
+//===-- Debugger.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/lldb-python.h"
+
+#include "lldb/API/SBDebugger.h"
+
+#include "lldb/Core/Debugger.h"
+
+#include <map>
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamAsynchronousIO.h"
+#include "lldb/Core/StreamCallback.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Host/DynamicLibrary.h"
+#include "lldb/Host/Terminal.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValueSInt64.h"
+#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/TargetList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/AnsiTerminal.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static uint32_t g_shared_debugger_refcount = 0;
+static lldb::user_id_t g_unique_id = 1;
+
+#pragma mark Static Functions
+
+static Mutex &
+GetDebuggerListMutex ()
+{
+ static Mutex g_mutex(Mutex::eMutexTypeRecursive);
+ return g_mutex;
+}
+
+typedef std::vector<DebuggerSP> DebuggerList;
+
+static DebuggerList &
+GetDebuggerList()
+{
+ // hide the static debugger list inside a singleton accessor to avoid
+ // global init contructors
+ static DebuggerList g_list;
+ return g_list;
+}
+
+OptionEnumValueElement
+g_show_disassembly_enum_values[] =
+{
+ { Debugger::eStopDisassemblyTypeNever, "never", "Never show disassembly when displaying a stop context."},
+ { Debugger::eStopDisassemblyTypeNoSource, "no-source", "Show disassembly when there is no source information, or the source file is missing when displaying a stop context."},
+ { Debugger::eStopDisassemblyTypeAlways, "always", "Always show disassembly when displaying a stop context."},
+ { 0, NULL, NULL }
+};
+
+OptionEnumValueElement
+g_language_enumerators[] =
+{
+ { eScriptLanguageNone, "none", "Disable scripting languages."},
+ { eScriptLanguagePython, "python", "Select python as the default scripting language."},
+ { eScriptLanguageDefault, "default", "Select the lldb default as the default scripting language."},
+ { 0, NULL, NULL }
+};
+
+#define MODULE_WITH_FUNC "{ ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}}"
+#define FILE_AND_LINE "{ at ${line.file.basename}:${line.number}}"
+
+#define DEFAULT_THREAD_FORMAT "thread #${thread.index}: tid = ${thread.id%tid}"\
+ "{, ${frame.pc}}"\
+ MODULE_WITH_FUNC\
+ FILE_AND_LINE\
+ "{, name = '${thread.name}'}"\
+ "{, queue = '${thread.queue}'}"\
+ "{, stop reason = ${thread.stop-reason}}"\
+ "{\\nReturn value: ${thread.return-value}}"\
+ "\\n"
+
+#define DEFAULT_FRAME_FORMAT "frame #${frame.index}: ${frame.pc}"\
+ MODULE_WITH_FUNC\
+ FILE_AND_LINE\
+ "\\n"
+
+
+
+static PropertyDefinition
+g_properties[] =
+{
+{ "auto-confirm", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true all confirmation prompts will receive their default reply." },
+{ "frame-format", OptionValue::eTypeString , true, 0 , DEFAULT_FRAME_FORMAT, NULL, "The default frame format string to use when displaying stack frame information for threads." },
+{ "notify-void", OptionValue::eTypeBoolean, true, false, NULL, NULL, "Notify the user explicitly if an expression returns void (default: false)." },
+{ "prompt", OptionValue::eTypeString , true, OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", NULL, "The debugger command line prompt displayed for the user." },
+{ "script-lang", OptionValue::eTypeEnum , true, eScriptLanguagePython, NULL, g_language_enumerators, "The script language to be used for evaluating user-written scripts." },
+{ "stop-disassembly-count", OptionValue::eTypeSInt64 , true, 4 , NULL, NULL, "The number of disassembly lines to show when displaying a stopped context." },
+{ "stop-disassembly-display", OptionValue::eTypeEnum , true, Debugger::eStopDisassemblyTypeNoSource, NULL, g_show_disassembly_enum_values, "Control when to display disassembly when displaying a stopped context." },
+{ "stop-line-count-after", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come after the current source line when displaying a stopped context." },
+{ "stop-line-count-before", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come before the current source line when displaying a stopped context." },
+{ "term-width", OptionValue::eTypeSInt64 , true, 80 , NULL, NULL, "The maximum number of columns to use for displaying text." },
+{ "thread-format", OptionValue::eTypeString , true, 0 , DEFAULT_THREAD_FORMAT, NULL, "The default thread format string to use when displaying thread information." },
+{ "use-external-editor", OptionValue::eTypeBoolean, true, false, NULL, NULL, "Whether to use an external editor or not." },
+{ "use-color", OptionValue::eTypeBoolean, true, true , NULL, NULL, "Whether to use Ansi color codes or not." },
+
+ { NULL, OptionValue::eTypeInvalid, true, 0 , NULL, NULL, NULL }
+};
+
+enum
+{
+ ePropertyAutoConfirm = 0,
+ ePropertyFrameFormat,
+ ePropertyNotiftVoid,
+ ePropertyPrompt,
+ ePropertyScriptLanguage,
+ ePropertyStopDisassemblyCount,
+ ePropertyStopDisassemblyDisplay,
+ ePropertyStopLineCountAfter,
+ ePropertyStopLineCountBefore,
+ ePropertyTerminalWidth,
+ ePropertyThreadFormat,
+ ePropertyUseExternalEditor,
+ ePropertyUseColor,
+};
+
+//
+//const char *
+//Debugger::GetFrameFormat() const
+//{
+// return m_properties_sp->GetFrameFormat();
+//}
+//const char *
+//Debugger::GetThreadFormat() const
+//{
+// return m_properties_sp->GetThreadFormat();
+//}
+//
+
+
+Error
+Debugger::SetPropertyValue (const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ const char *property_path,
+ const char *value)
+{
+ bool is_load_script = strcmp(property_path,"target.load-script-from-symbol-file") == 0;
+ TargetSP target_sp;
+ LoadScriptFromSymFile load_script_old_value;
+ if (is_load_script && exe_ctx->GetTargetSP())
+ {
+ target_sp = exe_ctx->GetTargetSP();
+ load_script_old_value = target_sp->TargetProperties::GetLoadScriptFromSymbolFile();
+ }
+ Error error (Properties::SetPropertyValue (exe_ctx, op, property_path, value));
+ if (error.Success())
+ {
+ // FIXME it would be nice to have "on-change" callbacks for properties
+ if (strcmp(property_path, g_properties[ePropertyPrompt].name) == 0)
+ {
+ const char *new_prompt = GetPrompt();
+ std::string str = lldb_utility::ansi::FormatAnsiTerminalCodes (new_prompt, GetUseColor());
+ if (str.length())
+ new_prompt = str.c_str();
+ EventSP prompt_change_event_sp (new Event(CommandInterpreter::eBroadcastBitResetPrompt, new EventDataBytes (new_prompt)));
+ GetCommandInterpreter().BroadcastEvent (prompt_change_event_sp);
+ }
+ else if (strcmp(property_path, g_properties[ePropertyUseColor].name) == 0)
+ {
+ // use-color changed. Ping the prompt so it can reset the ansi terminal codes.
+ SetPrompt (GetPrompt());
+ }
+ else if (is_load_script && target_sp && load_script_old_value == eLoadScriptFromSymFileWarn)
+ {
+ if (target_sp->TargetProperties::GetLoadScriptFromSymbolFile() == eLoadScriptFromSymFileTrue)
+ {
+ std::list<Error> errors;
+ StreamString feedback_stream;
+ if (!target_sp->LoadScriptingResources(errors,&feedback_stream))
+ {
+ for (auto error : errors)
+ {
+ GetErrorStream().Printf("%s\n",error.AsCString());
+ }
+ if (feedback_stream.GetSize())
+ GetErrorStream().Printf("%s",feedback_stream.GetData());
+ }
+ }
+ }
+ }
+ return error;
+}
+
+bool
+Debugger::GetAutoConfirm () const
+{
+ const uint32_t idx = ePropertyAutoConfirm;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+const char *
+Debugger::GetFrameFormat() const
+{
+ const uint32_t idx = ePropertyFrameFormat;
+ return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value);
+}
+
+bool
+Debugger::GetNotifyVoid () const
+{
+ const uint32_t idx = ePropertyNotiftVoid;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+const char *
+Debugger::GetPrompt() const
+{
+ const uint32_t idx = ePropertyPrompt;
+ return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value);
+}
+
+void
+Debugger::SetPrompt(const char *p)
+{
+ const uint32_t idx = ePropertyPrompt;
+ m_collection_sp->SetPropertyAtIndexAsString (NULL, idx, p);
+ const char *new_prompt = GetPrompt();
+ std::string str = lldb_utility::ansi::FormatAnsiTerminalCodes (new_prompt, GetUseColor());
+ if (str.length())
+ new_prompt = str.c_str();
+ EventSP prompt_change_event_sp (new Event(CommandInterpreter::eBroadcastBitResetPrompt, new EventDataBytes (new_prompt)));;
+ GetCommandInterpreter().BroadcastEvent (prompt_change_event_sp);
+}
+
+const char *
+Debugger::GetThreadFormat() const
+{
+ const uint32_t idx = ePropertyThreadFormat;
+ return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value);
+}
+
+lldb::ScriptLanguage
+Debugger::GetScriptLanguage() const
+{
+ const uint32_t idx = ePropertyScriptLanguage;
+ return (lldb::ScriptLanguage)m_collection_sp->GetPropertyAtIndexAsEnumeration (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+bool
+Debugger::SetScriptLanguage (lldb::ScriptLanguage script_lang)
+{
+ const uint32_t idx = ePropertyScriptLanguage;
+ return m_collection_sp->SetPropertyAtIndexAsEnumeration (NULL, idx, script_lang);
+}
+
+uint32_t
+Debugger::GetTerminalWidth () const
+{
+ const uint32_t idx = ePropertyTerminalWidth;
+ return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+bool
+Debugger::SetTerminalWidth (uint32_t term_width)
+{
+ const uint32_t idx = ePropertyTerminalWidth;
+ return m_collection_sp->SetPropertyAtIndexAsSInt64 (NULL, idx, term_width);
+}
+
+bool
+Debugger::GetUseExternalEditor () const
+{
+ const uint32_t idx = ePropertyUseExternalEditor;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+bool
+Debugger::SetUseExternalEditor (bool b)
+{
+ const uint32_t idx = ePropertyUseExternalEditor;
+ return m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
+}
+
+bool
+Debugger::GetUseColor () const
+{
+ const uint32_t idx = ePropertyUseColor;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+bool
+Debugger::SetUseColor (bool b)
+{
+ const uint32_t idx = ePropertyUseColor;
+ bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
+ SetPrompt (GetPrompt());
+ return ret;
+}
+
+uint32_t
+Debugger::GetStopSourceLineCount (bool before) const
+{
+ const uint32_t idx = before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter;
+ return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+Debugger::StopDisassemblyType
+Debugger::GetStopDisassemblyDisplay () const
+{
+ const uint32_t idx = ePropertyStopDisassemblyDisplay;
+ return (Debugger::StopDisassemblyType)m_collection_sp->GetPropertyAtIndexAsEnumeration (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+uint32_t
+Debugger::GetDisassemblyLineCount () const
+{
+ const uint32_t idx = ePropertyStopDisassemblyCount;
+ return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+#pragma mark Debugger
+
+//const DebuggerPropertiesSP &
+//Debugger::GetSettings() const
+//{
+// return m_properties_sp;
+//}
+//
+
+int
+Debugger::TestDebuggerRefCount ()
+{
+ return g_shared_debugger_refcount;
+}
+
+void
+Debugger::Initialize ()
+{
+ if (g_shared_debugger_refcount++ == 0)
+ lldb_private::Initialize();
+}
+
+void
+Debugger::Terminate ()
+{
+ if (g_shared_debugger_refcount > 0)
+ {
+ g_shared_debugger_refcount--;
+ if (g_shared_debugger_refcount == 0)
+ {
+ lldb_private::WillTerminate();
+ lldb_private::Terminate();
+
+ // Clear our master list of debugger objects
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ GetDebuggerList().clear();
+ }
+ }
+}
+
+void
+Debugger::SettingsInitialize ()
+{
+ Target::SettingsInitialize ();
+}
+
+void
+Debugger::SettingsTerminate ()
+{
+ Target::SettingsTerminate ();
+}
+
+bool
+Debugger::LoadPlugin (const FileSpec& spec, Error& error)
+{
+ lldb::DynamicLibrarySP dynlib_sp(new lldb_private::DynamicLibrary(spec));
+ if (!dynlib_sp || dynlib_sp->IsValid() == false)
+ {
+ if (spec.Exists())
+ error.SetErrorString("this file does not represent a loadable dylib");
+ else
+ error.SetErrorString("no such file");
+ return false;
+ }
+ lldb::DebuggerSP debugger_sp(shared_from_this());
+ lldb::SBDebugger debugger_sb(debugger_sp);
+ // This calls the bool lldb::PluginInitialize(lldb::SBDebugger debugger) function.
+ // TODO: mangle this differently for your system - on OSX, the first underscore needs to be removed and the second one stays
+ LLDBCommandPluginInit init_func = dynlib_sp->GetSymbol<LLDBCommandPluginInit>("_ZN4lldb16PluginInitializeENS_10SBDebuggerE");
+ if (!init_func)
+ {
+ error.SetErrorString("cannot find the initialization function lldb::PluginInitialize(lldb::SBDebugger)");
+ return false;
+ }
+ if (init_func(debugger_sb))
+ {
+ m_loaded_plugins.push_back(dynlib_sp);
+ return true;
+ }
+ error.SetErrorString("dylib refused to be loaded");
+ return false;
+}
+
+static FileSpec::EnumerateDirectoryResult
+LoadPluginCallback
+(
+ void *baton,
+ FileSpec::FileType file_type,
+ const FileSpec &file_spec
+ )
+{
+ Error error;
+
+ static ConstString g_dylibext("dylib");
+ static ConstString g_solibext("so");
+
+ if (!baton)
+ return FileSpec::eEnumerateDirectoryResultQuit;
+
+ Debugger *debugger = (Debugger*)baton;
+
+ // If we have a regular file, a symbolic link or unknown file type, try
+ // and process the file. We must handle unknown as sometimes the directory
+ // enumeration might be enumerating a file system that doesn't have correct
+ // file type information.
+ if (file_type == FileSpec::eFileTypeRegular ||
+ file_type == FileSpec::eFileTypeSymbolicLink ||
+ file_type == FileSpec::eFileTypeUnknown )
+ {
+ FileSpec plugin_file_spec (file_spec);
+ plugin_file_spec.ResolvePath ();
+
+ if (plugin_file_spec.GetFileNameExtension() != g_dylibext &&
+ plugin_file_spec.GetFileNameExtension() != g_solibext)
+ {
+ return FileSpec::eEnumerateDirectoryResultNext;
+ }
+
+ Error plugin_load_error;
+ debugger->LoadPlugin (plugin_file_spec, plugin_load_error);
+
+ return FileSpec::eEnumerateDirectoryResultNext;
+ }
+
+ else if (file_type == FileSpec::eFileTypeUnknown ||
+ file_type == FileSpec::eFileTypeDirectory ||
+ file_type == FileSpec::eFileTypeSymbolicLink )
+ {
+ // Try and recurse into anything that a directory or symbolic link.
+ // We must also do this for unknown as sometimes the directory enumeration
+ // might be enurating a file system that doesn't have correct file type
+ // information.
+ return FileSpec::eEnumerateDirectoryResultEnter;
+ }
+
+ return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+void
+Debugger::InstanceInitialize ()
+{
+ FileSpec dir_spec;
+ const bool find_directories = true;
+ const bool find_files = true;
+ const bool find_other = true;
+ char dir_path[PATH_MAX];
+ if (Host::GetLLDBPath (ePathTypeLLDBSystemPlugins, dir_spec))
+ {
+ if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path)))
+ {
+ FileSpec::EnumerateDirectory (dir_path,
+ find_directories,
+ find_files,
+ find_other,
+ LoadPluginCallback,
+ this);
+ }
+ }
+
+ if (Host::GetLLDBPath (ePathTypeLLDBUserPlugins, dir_spec))
+ {
+ if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path)))
+ {
+ FileSpec::EnumerateDirectory (dir_path,
+ find_directories,
+ find_files,
+ find_other,
+ LoadPluginCallback,
+ this);
+ }
+ }
+
+ PluginManager::DebuggerInitialize (*this);
+}
+
+DebuggerSP
+Debugger::CreateInstance (lldb::LogOutputCallback log_callback, void *baton)
+{
+ DebuggerSP debugger_sp (new Debugger(log_callback, baton));
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ GetDebuggerList().push_back(debugger_sp);
+ }
+ debugger_sp->InstanceInitialize ();
+ return debugger_sp;
+}
+
+void
+Debugger::Destroy (DebuggerSP &debugger_sp)
+{
+ if (debugger_sp.get() == NULL)
+ return;
+
+ debugger_sp->Clear();
+
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ DebuggerList &debugger_list = GetDebuggerList ();
+ DebuggerList::iterator pos, end = debugger_list.end();
+ for (pos = debugger_list.begin (); pos != end; ++pos)
+ {
+ if ((*pos).get() == debugger_sp.get())
+ {
+ debugger_list.erase (pos);
+ return;
+ }
+ }
+ }
+}
+
+DebuggerSP
+Debugger::FindDebuggerWithInstanceName (const ConstString &instance_name)
+{
+ DebuggerSP debugger_sp;
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ DebuggerList &debugger_list = GetDebuggerList();
+ DebuggerList::iterator pos, end = debugger_list.end();
+
+ for (pos = debugger_list.begin(); pos != end; ++pos)
+ {
+ if ((*pos).get()->m_instance_name == instance_name)
+ {
+ debugger_sp = *pos;
+ break;
+ }
+ }
+ }
+ return debugger_sp;
+}
+
+TargetSP
+Debugger::FindTargetWithProcessID (lldb::pid_t pid)
+{
+ TargetSP target_sp;
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ DebuggerList &debugger_list = GetDebuggerList();
+ DebuggerList::iterator pos, end = debugger_list.end();
+ for (pos = debugger_list.begin(); pos != end; ++pos)
+ {
+ target_sp = (*pos)->GetTargetList().FindTargetWithProcessID (pid);
+ if (target_sp)
+ break;
+ }
+ }
+ return target_sp;
+}
+
+TargetSP
+Debugger::FindTargetWithProcess (Process *process)
+{
+ TargetSP target_sp;
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ DebuggerList &debugger_list = GetDebuggerList();
+ DebuggerList::iterator pos, end = debugger_list.end();
+ for (pos = debugger_list.begin(); pos != end; ++pos)
+ {
+ target_sp = (*pos)->GetTargetList().FindTargetWithProcess (process);
+ if (target_sp)
+ break;
+ }
+ }
+ return target_sp;
+}
+
+Debugger::Debugger (lldb::LogOutputCallback log_callback, void *baton) :
+ UserID (g_unique_id++),
+ Properties(OptionValuePropertiesSP(new OptionValueProperties())),
+ m_input_comm("debugger.input"),
+ m_input_file (),
+ m_output_file (),
+ m_error_file (),
+ m_terminal_state (),
+ m_target_list (*this),
+ m_platform_list (),
+ m_listener ("lldb.Debugger"),
+ m_source_manager_ap(),
+ m_source_file_cache(),
+ m_command_interpreter_ap (new CommandInterpreter (*this, eScriptLanguageDefault, false)),
+ m_input_reader_stack (),
+ m_input_reader_data (),
+ m_instance_name()
+{
+ char instance_cstr[256];
+ snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID());
+ m_instance_name.SetCString(instance_cstr);
+ if (log_callback)
+ m_log_callback_stream_sp.reset (new StreamCallback (log_callback, baton));
+ m_command_interpreter_ap->Initialize ();
+ // Always add our default platform to the platform list
+ PlatformSP default_platform_sp (Platform::GetDefaultPlatform());
+ assert (default_platform_sp.get());
+ m_platform_list.Append (default_platform_sp, true);
+
+ m_collection_sp->Initialize (g_properties);
+ m_collection_sp->AppendProperty (ConstString("target"),
+ ConstString("Settings specify to debugging targets."),
+ true,
+ Target::GetGlobalProperties()->GetValueProperties());
+ if (m_command_interpreter_ap.get())
+ {
+ m_collection_sp->AppendProperty (ConstString("interpreter"),
+ ConstString("Settings specify to the debugger's command interpreter."),
+ true,
+ m_command_interpreter_ap->GetValueProperties());
+ }
+ OptionValueSInt64 *term_width = m_collection_sp->GetPropertyAtIndexAsOptionValueSInt64 (NULL, ePropertyTerminalWidth);
+ term_width->SetMinimumValue(10);
+ term_width->SetMaximumValue(1024);
+
+ // Turn off use-color if this is a dumb terminal.
+ const char *term = getenv ("TERM");
+ if (term && !strcmp (term, "dumb"))
+ SetUseColor (false);
+}
+
+Debugger::~Debugger ()
+{
+ Clear();
+}
+
+void
+Debugger::Clear()
+{
+ CleanUpInputReaders();
+ m_listener.Clear();
+ int num_targets = m_target_list.GetNumTargets();
+ for (int i = 0; i < num_targets; i++)
+ {
+ TargetSP target_sp (m_target_list.GetTargetAtIndex (i));
+ if (target_sp)
+ {
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ process_sp->Finalize();
+ target_sp->Destroy();
+ }
+ }
+ BroadcasterManager::Clear ();
+
+ // Close the input file _before_ we close the input read communications class
+ // as it does NOT own the input file, our m_input_file does.
+ m_terminal_state.Clear();
+ GetInputFile().Close ();
+ // Now that we have closed m_input_file, we can now tell our input communication
+ // class to close down. Its read thread should quickly exit after we close
+ // the input file handle above.
+ m_input_comm.Clear ();
+}
+
+bool
+Debugger::GetCloseInputOnEOF () const
+{
+ return m_input_comm.GetCloseOnEOF();
+}
+
+void
+Debugger::SetCloseInputOnEOF (bool b)
+{
+ m_input_comm.SetCloseOnEOF(b);
+}
+
+bool
+Debugger::GetAsyncExecution ()
+{
+ return !m_command_interpreter_ap->GetSynchronous();
+}
+
+void
+Debugger::SetAsyncExecution (bool async_execution)
+{
+ m_command_interpreter_ap->SetSynchronous (!async_execution);
+}
+
+
+void
+Debugger::SetInputFileHandle (FILE *fh, bool tranfer_ownership)
+{
+ File &in_file = GetInputFile();
+ in_file.SetStream (fh, tranfer_ownership);
+ if (in_file.IsValid() == false)
+ in_file.SetStream (stdin, true);
+
+ // Disconnect from any old connection if we had one
+ m_input_comm.Disconnect ();
+ // Pass false as the second argument to ConnectionFileDescriptor below because
+ // our "in_file" above will already take ownership if requested and we don't
+ // want to objects trying to own and close a file descriptor.
+ m_input_comm.SetConnection (new ConnectionFileDescriptor (in_file.GetDescriptor(), false));
+ m_input_comm.SetReadThreadBytesReceivedCallback (Debugger::DispatchInputCallback, this);
+
+ // Save away the terminal state if that is relevant, so that we can restore it in RestoreInputState.
+ SaveInputTerminalState ();
+
+ Error error;
+ if (m_input_comm.StartReadThread (&error) == false)
+ {
+ File &err_file = GetErrorFile();
+
+ err_file.Printf ("error: failed to main input read thread: %s", error.AsCString() ? error.AsCString() : "unkown error");
+ exit(1);
+ }
+}
+
+void
+Debugger::SetOutputFileHandle (FILE *fh, bool tranfer_ownership)
+{
+ File &out_file = GetOutputFile();
+ out_file.SetStream (fh, tranfer_ownership);
+ if (out_file.IsValid() == false)
+ out_file.SetStream (stdout, false);
+
+ // do not create the ScriptInterpreter just for setting the output file handle
+ // as the constructor will know how to do the right thing on its own
+ const bool can_create = false;
+ ScriptInterpreter* script_interpreter = GetCommandInterpreter().GetScriptInterpreter(can_create);
+ if (script_interpreter)
+ script_interpreter->ResetOutputFileHandle (fh);
+}
+
+void
+Debugger::SetErrorFileHandle (FILE *fh, bool tranfer_ownership)
+{
+ File &err_file = GetErrorFile();
+ err_file.SetStream (fh, tranfer_ownership);
+ if (err_file.IsValid() == false)
+ err_file.SetStream (stderr, false);
+}
+
+void
+Debugger::SaveInputTerminalState ()
+{
+ File &in_file = GetInputFile();
+ if (in_file.GetDescriptor() != File::kInvalidDescriptor)
+ m_terminal_state.Save(in_file.GetDescriptor(), true);
+}
+
+void
+Debugger::RestoreInputTerminalState ()
+{
+ m_terminal_state.Restore();
+}
+
+ExecutionContext
+Debugger::GetSelectedExecutionContext ()
+{
+ ExecutionContext exe_ctx;
+ TargetSP target_sp(GetSelectedTarget());
+ exe_ctx.SetTargetSP (target_sp);
+
+ if (target_sp)
+ {
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ exe_ctx.SetProcessSP (process_sp);
+ if (process_sp && process_sp->IsRunning() == false)
+ {
+ ThreadSP thread_sp (process_sp->GetThreadList().GetSelectedThread());
+ if (thread_sp)
+ {
+ exe_ctx.SetThreadSP (thread_sp);
+ exe_ctx.SetFrameSP (thread_sp->GetSelectedFrame());
+ if (exe_ctx.GetFramePtr() == NULL)
+ exe_ctx.SetFrameSP (thread_sp->GetStackFrameAtIndex (0));
+ }
+ }
+ }
+ return exe_ctx;
+
+}
+
+InputReaderSP
+Debugger::GetCurrentInputReader ()
+{
+ InputReaderSP reader_sp;
+
+ if (!m_input_reader_stack.IsEmpty())
+ {
+ // Clear any finished readers from the stack
+ while (CheckIfTopInputReaderIsDone()) ;
+
+ if (!m_input_reader_stack.IsEmpty())
+ reader_sp = m_input_reader_stack.Top();
+ }
+
+ return reader_sp;
+}
+
+void
+Debugger::DispatchInputCallback (void *baton, const void *bytes, size_t bytes_len)
+{
+ if (bytes_len > 0)
+ ((Debugger *)baton)->DispatchInput ((char *)bytes, bytes_len);
+ else
+ ((Debugger *)baton)->DispatchInputEndOfFile ();
+}
+
+
+void
+Debugger::DispatchInput (const char *bytes, size_t bytes_len)
+{
+ if (bytes == NULL || bytes_len == 0)
+ return;
+
+ WriteToDefaultReader (bytes, bytes_len);
+}
+
+void
+Debugger::DispatchInputInterrupt ()
+{
+ m_input_reader_data.clear();
+
+ InputReaderSP reader_sp (GetCurrentInputReader ());
+ if (reader_sp)
+ {
+ reader_sp->Notify (eInputReaderInterrupt);
+
+ // If notifying the reader of the interrupt finished the reader, we should pop it off the stack.
+ while (CheckIfTopInputReaderIsDone ()) ;
+ }
+}
+
+void
+Debugger::DispatchInputEndOfFile ()
+{
+ m_input_reader_data.clear();
+
+ InputReaderSP reader_sp (GetCurrentInputReader ());
+ if (reader_sp)
+ {
+ reader_sp->Notify (eInputReaderEndOfFile);
+
+ // If notifying the reader of the end-of-file finished the reader, we should pop it off the stack.
+ while (CheckIfTopInputReaderIsDone ()) ;
+ }
+}
+
+void
+Debugger::CleanUpInputReaders ()
+{
+ m_input_reader_data.clear();
+
+ // The bottom input reader should be the main debugger input reader. We do not want to close that one here.
+ while (m_input_reader_stack.GetSize() > 1)
+ {
+ InputReaderSP reader_sp (GetCurrentInputReader ());
+ if (reader_sp)
+ {
+ reader_sp->Notify (eInputReaderEndOfFile);
+ reader_sp->SetIsDone (true);
+ }
+ }
+}
+
+void
+Debugger::NotifyTopInputReader (InputReaderAction notification)
+{
+ InputReaderSP reader_sp (GetCurrentInputReader());
+ if (reader_sp)
+ {
+ reader_sp->Notify (notification);
+
+ // Flush out any input readers that are done.
+ while (CheckIfTopInputReaderIsDone ())
+ /* Do nothing. */;
+ }
+}
+
+bool
+Debugger::InputReaderIsTopReader (const InputReaderSP& reader_sp)
+{
+ InputReaderSP top_reader_sp (GetCurrentInputReader());
+
+ return (reader_sp.get() == top_reader_sp.get());
+}
+
+
+void
+Debugger::WriteToDefaultReader (const char *bytes, size_t bytes_len)
+{
+ if (bytes && bytes_len)
+ m_input_reader_data.append (bytes, bytes_len);
+
+ if (m_input_reader_data.empty())
+ return;
+
+ while (!m_input_reader_stack.IsEmpty() && !m_input_reader_data.empty())
+ {
+ // Get the input reader from the top of the stack
+ InputReaderSP reader_sp (GetCurrentInputReader ());
+ if (!reader_sp)
+ break;
+
+ size_t bytes_handled = reader_sp->HandleRawBytes (m_input_reader_data.c_str(),
+ m_input_reader_data.size());
+ if (bytes_handled)
+ {
+ m_input_reader_data.erase (0, bytes_handled);
+ }
+ else
+ {
+ // No bytes were handled, we might not have reached our
+ // granularity, just return and wait for more data
+ break;
+ }
+ }
+
+ // Flush out any input readers that are done.
+ while (CheckIfTopInputReaderIsDone ())
+ /* Do nothing. */;
+
+}
+
+void
+Debugger::PushInputReader (const InputReaderSP& reader_sp)
+{
+ if (!reader_sp)
+ return;
+
+ // Deactivate the old top reader
+ InputReaderSP top_reader_sp (GetCurrentInputReader ());
+
+ if (top_reader_sp)
+ top_reader_sp->Notify (eInputReaderDeactivate);
+
+ m_input_reader_stack.Push (reader_sp);
+ reader_sp->Notify (eInputReaderActivate);
+ ActivateInputReader (reader_sp);
+}
+
+bool
+Debugger::PopInputReader (const InputReaderSP& pop_reader_sp)
+{
+ bool result = false;
+
+ // The reader on the stop of the stack is done, so let the next
+ // read on the stack referesh its prompt and if there is one...
+ if (!m_input_reader_stack.IsEmpty())
+ {
+ // Cannot call GetCurrentInputReader here, as that would cause an infinite loop.
+ InputReaderSP reader_sp(m_input_reader_stack.Top());
+
+ if (!pop_reader_sp || pop_reader_sp.get() == reader_sp.get())
+ {
+ m_input_reader_stack.Pop ();
+ reader_sp->Notify (eInputReaderDeactivate);
+ reader_sp->Notify (eInputReaderDone);
+ result = true;
+
+ if (!m_input_reader_stack.IsEmpty())
+ {
+ reader_sp = m_input_reader_stack.Top();
+ if (reader_sp)
+ {
+ ActivateInputReader (reader_sp);
+ reader_sp->Notify (eInputReaderReactivate);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+bool
+Debugger::CheckIfTopInputReaderIsDone ()
+{
+ bool result = false;
+ if (!m_input_reader_stack.IsEmpty())
+ {
+ // Cannot call GetCurrentInputReader here, as that would cause an infinite loop.
+ InputReaderSP reader_sp(m_input_reader_stack.Top());
+
+ if (reader_sp && reader_sp->IsDone())
+ {
+ result = true;
+ PopInputReader (reader_sp);
+ }
+ }
+ return result;
+}
+
+void
+Debugger::ActivateInputReader (const InputReaderSP &reader_sp)
+{
+ int input_fd = m_input_file.GetFile().GetDescriptor();
+
+ if (input_fd >= 0)
+ {
+ Terminal tty(input_fd);
+
+ tty.SetEcho(reader_sp->GetEcho());
+
+ switch (reader_sp->GetGranularity())
+ {
+ case eInputReaderGranularityByte:
+ case eInputReaderGranularityWord:
+ tty.SetCanonical (false);
+ break;
+
+ case eInputReaderGranularityLine:
+ case eInputReaderGranularityAll:
+ tty.SetCanonical (true);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+StreamSP
+Debugger::GetAsyncOutputStream ()
+{
+ return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(),
+ CommandInterpreter::eBroadcastBitAsynchronousOutputData));
+}
+
+StreamSP
+Debugger::GetAsyncErrorStream ()
+{
+ return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(),
+ CommandInterpreter::eBroadcastBitAsynchronousErrorData));
+}
+
+size_t
+Debugger::GetNumDebuggers()
+{
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ return GetDebuggerList().size();
+ }
+ return 0;
+}
+
+lldb::DebuggerSP
+Debugger::GetDebuggerAtIndex (size_t index)
+{
+ DebuggerSP debugger_sp;
+
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ DebuggerList &debugger_list = GetDebuggerList();
+
+ if (index < debugger_list.size())
+ debugger_sp = debugger_list[index];
+ }
+
+ return debugger_sp;
+}
+
+DebuggerSP
+Debugger::FindDebuggerWithID (lldb::user_id_t id)
+{
+ DebuggerSP debugger_sp;
+
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ DebuggerList &debugger_list = GetDebuggerList();
+ DebuggerList::iterator pos, end = debugger_list.end();
+ for (pos = debugger_list.begin(); pos != end; ++pos)
+ {
+ if ((*pos).get()->GetID() == id)
+ {
+ debugger_sp = *pos;
+ break;
+ }
+ }
+ }
+ return debugger_sp;
+}
+
+static void
+TestPromptFormats (StackFrame *frame)
+{
+ if (frame == NULL)
+ return;
+
+ StreamString s;
+ const char *prompt_format =
+ "{addr = '${addr}'\n}"
+ "{process.id = '${process.id}'\n}"
+ "{process.name = '${process.name}'\n}"
+ "{process.file.basename = '${process.file.basename}'\n}"
+ "{process.file.fullpath = '${process.file.fullpath}'\n}"
+ "{thread.id = '${thread.id}'\n}"
+ "{thread.index = '${thread.index}'\n}"
+ "{thread.name = '${thread.name}'\n}"
+ "{thread.queue = '${thread.queue}'\n}"
+ "{thread.stop-reason = '${thread.stop-reason}'\n}"
+ "{target.arch = '${target.arch}'\n}"
+ "{module.file.basename = '${module.file.basename}'\n}"
+ "{module.file.fullpath = '${module.file.fullpath}'\n}"
+ "{file.basename = '${file.basename}'\n}"
+ "{file.fullpath = '${file.fullpath}'\n}"
+ "{frame.index = '${frame.index}'\n}"
+ "{frame.pc = '${frame.pc}'\n}"
+ "{frame.sp = '${frame.sp}'\n}"
+ "{frame.fp = '${frame.fp}'\n}"
+ "{frame.flags = '${frame.flags}'\n}"
+ "{frame.reg.rdi = '${frame.reg.rdi}'\n}"
+ "{frame.reg.rip = '${frame.reg.rip}'\n}"
+ "{frame.reg.rsp = '${frame.reg.rsp}'\n}"
+ "{frame.reg.rbp = '${frame.reg.rbp}'\n}"
+ "{frame.reg.rflags = '${frame.reg.rflags}'\n}"
+ "{frame.reg.xmm0 = '${frame.reg.xmm0}'\n}"
+ "{frame.reg.carp = '${frame.reg.carp}'\n}"
+ "{function.id = '${function.id}'\n}"
+ "{function.name = '${function.name}'\n}"
+ "{function.name-with-args = '${function.name-with-args}'\n}"
+ "{function.addr-offset = '${function.addr-offset}'\n}"
+ "{function.line-offset = '${function.line-offset}'\n}"
+ "{function.pc-offset = '${function.pc-offset}'\n}"
+ "{line.file.basename = '${line.file.basename}'\n}"
+ "{line.file.fullpath = '${line.file.fullpath}'\n}"
+ "{line.number = '${line.number}'\n}"
+ "{line.start-addr = '${line.start-addr}'\n}"
+ "{line.end-addr = '${line.end-addr}'\n}"
+;
+
+ SymbolContext sc (frame->GetSymbolContext(eSymbolContextEverything));
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext(exe_ctx);
+ if (Debugger::FormatPrompt (prompt_format, &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s))
+ {
+ printf("%s\n", s.GetData());
+ }
+ else
+ {
+ printf ("what we got: %s\n", s.GetData());
+ }
+}
+
+static bool
+ScanFormatDescriptor (const char* var_name_begin,
+ const char* var_name_end,
+ const char** var_name_final,
+ const char** percent_position,
+ Format* custom_format,
+ ValueObject::ValueObjectRepresentationStyle* val_obj_display)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+ *percent_position = ::strchr(var_name_begin,'%');
+ if (!*percent_position || *percent_position > var_name_end)
+ {
+ if (log)
+ log->Printf("[ScanFormatDescriptor] no format descriptor in string, skipping");
+ *var_name_final = var_name_end;
+ }
+ else
+ {
+ *var_name_final = *percent_position;
+ std::string format_name(*var_name_final+1, var_name_end-*var_name_final-1);
+ if (log)
+ log->Printf("[ScanFormatDescriptor] parsing %s as a format descriptor", format_name.c_str());
+ if ( !FormatManager::GetFormatFromCString(format_name.c_str(),
+ true,
+ *custom_format) )
+ {
+ if (log)
+ log->Printf("[ScanFormatDescriptor] %s is an unknown format", format_name.c_str());
+
+ switch (format_name.front())
+ {
+ case '@': // if this is an @ sign, print ObjC description
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleLanguageSpecific;
+ break;
+ case 'V': // if this is a V, print the value using the default format
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleValue;
+ break;
+ case 'L': // if this is an L, print the location of the value
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleLocation;
+ break;
+ case 'S': // if this is an S, print the summary after all
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleSummary;
+ break;
+ case '#': // if this is a '#', print the number of children
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleChildrenCount;
+ break;
+ case 'T': // if this is a 'T', print the type
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleType;
+ break;
+ case 'N': // if this is a 'N', print the name
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleName;
+ break;
+ case '>': // if this is a '>', print the name
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleExpressionPath;
+ break;
+ default:
+ if (log)
+ log->Printf("ScanFormatDescriptor] %s is an error, leaving the previous value alone", format_name.c_str());
+ break;
+ }
+ }
+ // a good custom format tells us to print the value using it
+ else
+ {
+ if (log)
+ log->Printf("[ScanFormatDescriptor] will display value for this VO");
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleValue;
+ }
+ }
+ if (log)
+ log->Printf("[ScanFormatDescriptor] final format description outcome: custom_format = %d, val_obj_display = %d",
+ *custom_format,
+ *val_obj_display);
+ return true;
+}
+
+static bool
+ScanBracketedRange (const char* var_name_begin,
+ const char* var_name_end,
+ const char* var_name_final,
+ const char** open_bracket_position,
+ const char** separator_position,
+ const char** close_bracket_position,
+ const char** var_name_final_if_array_range,
+ int64_t* index_lower,
+ int64_t* index_higher)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+ *open_bracket_position = ::strchr(var_name_begin,'[');
+ if (*open_bracket_position && *open_bracket_position < var_name_final)
+ {
+ *separator_position = ::strchr(*open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield
+ *close_bracket_position = ::strchr(*open_bracket_position,']');
+ // as usual, we assume that [] will come before %
+ //printf("trying to expand a []\n");
+ *var_name_final_if_array_range = *open_bracket_position;
+ if (*close_bracket_position - *open_bracket_position == 1)
+ {
+ if (log)
+ log->Printf("[ScanBracketedRange] '[]' detected.. going from 0 to end of data");
+ *index_lower = 0;
+ }
+ else if (*separator_position == NULL || *separator_position > var_name_end)
+ {
+ char *end = NULL;
+ *index_lower = ::strtoul (*open_bracket_position+1, &end, 0);
+ *index_higher = *index_lower;
+ if (log)
+ log->Printf("[ScanBracketedRange] [%" PRId64 "] detected, high index is same", *index_lower);
+ }
+ else if (*close_bracket_position && *close_bracket_position < var_name_end)
+ {
+ char *end = NULL;
+ *index_lower = ::strtoul (*open_bracket_position+1, &end, 0);
+ *index_higher = ::strtoul (*separator_position+1, &end, 0);
+ if (log)
+ log->Printf("[ScanBracketedRange] [%" PRId64 "-%" PRId64 "] detected", *index_lower, *index_higher);
+ }
+ else
+ {
+ if (log)
+ log->Printf("[ScanBracketedRange] expression is erroneous, cannot extract indices out of it");
+ return false;
+ }
+ if (*index_lower > *index_higher && *index_higher > 0)
+ {
+ if (log)
+ log->Printf("[ScanBracketedRange] swapping indices");
+ int64_t temp = *index_lower;
+ *index_lower = *index_higher;
+ *index_higher = temp;
+ }
+ }
+ else if (log)
+ log->Printf("[ScanBracketedRange] no bracketed range, skipping entirely");
+ return true;
+}
+
+template <typename T>
+static bool RunScriptFormatKeyword(Stream &s, ScriptInterpreter *script_interpreter, T t, const std::string& script_name)
+{
+ if (script_interpreter)
+ {
+ Error script_error;
+ std::string script_output;
+
+ if (script_interpreter->RunScriptFormatKeyword(script_name.c_str(), t, script_output, script_error) && script_error.Success())
+ {
+ s.Printf("%s", script_output.c_str());
+ return true;
+ }
+ else
+ {
+ s.Printf("<error: %s>",script_error.AsCString());
+ }
+ }
+ return false;
+}
+
+static ValueObjectSP
+ExpandIndexedExpression (ValueObject* valobj,
+ size_t index,
+ StackFrame* frame,
+ bool deref_pointer)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+ const char* ptr_deref_format = "[%d]";
+ std::string ptr_deref_buffer(10,0);
+ ::sprintf(&ptr_deref_buffer[0], ptr_deref_format, index);
+ if (log)
+ log->Printf("[ExpandIndexedExpression] name to deref: %s",ptr_deref_buffer.c_str());
+ const char* first_unparsed;
+ ValueObject::GetValueForExpressionPathOptions options;
+ ValueObject::ExpressionPathEndResultType final_value_type;
+ ValueObject::ExpressionPathScanEndReason reason_to_stop;
+ ValueObject::ExpressionPathAftermath what_next = (deref_pointer ? ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing);
+ ValueObjectSP item = valobj->GetValueForExpressionPath (ptr_deref_buffer.c_str(),
+ &first_unparsed,
+ &reason_to_stop,
+ &final_value_type,
+ options,
+ &what_next);
+ if (!item)
+ {
+ if (log)
+ log->Printf("[ExpandIndexedExpression] ERROR: unparsed portion = %s, why stopping = %d,"
+ " final_value_type %d",
+ first_unparsed, reason_to_stop, final_value_type);
+ }
+ else
+ {
+ if (log)
+ log->Printf("[ExpandIndexedExpression] ALL RIGHT: unparsed portion = %s, why stopping = %d,"
+ " final_value_type %d",
+ first_unparsed, reason_to_stop, final_value_type);
+ }
+ return item;
+}
+
+static inline bool
+IsToken(const char *var_name_begin, const char *var)
+{
+ return (::strncmp (var_name_begin, var, strlen(var)) == 0);
+}
+
+static bool
+IsTokenWithFormat(const char *var_name_begin, const char *var, std::string &format, const char *default_format,
+ const ExecutionContext *exe_ctx_ptr, const SymbolContext *sc_ptr)
+{
+ int var_len = strlen(var);
+ if (::strncmp (var_name_begin, var, var_len) == 0)
+ {
+ var_name_begin += var_len;
+ if (*var_name_begin == '}')
+ {
+ format = default_format;
+ return true;
+ }
+ else if (*var_name_begin == '%')
+ {
+ // Allow format specifiers: x|X|u with optional width specifiers.
+ // ${thread.id%x} ; hex
+ // ${thread.id%X} ; uppercase hex
+ // ${thread.id%u} ; unsigned decimal
+ // ${thread.id%8.8X} ; width.precision + specifier
+ // ${thread.id%tid} ; unsigned on FreeBSD/Linux, otherwise default_format (0x%4.4x for thread.id)
+ int dot_count = 0;
+ const char *specifier = NULL;
+ int width_precision_length = 0;
+ const char *width_precision = ++var_name_begin;
+ while (isdigit(*var_name_begin) || *var_name_begin == '.')
+ {
+ dot_count += (*var_name_begin == '.');
+ if (dot_count > 1)
+ break;
+ var_name_begin++;
+ width_precision_length++;
+ }
+
+ if (IsToken (var_name_begin, "tid}"))
+ {
+ Target *target = Target::GetTargetFromContexts (exe_ctx_ptr, sc_ptr);
+ if (target)
+ {
+ ArchSpec arch (target->GetArchitecture ());
+ llvm::Triple::OSType ostype = arch.IsValid() ? arch.GetTriple().getOS() : llvm::Triple::UnknownOS;
+ if ((ostype == llvm::Triple::FreeBSD) || (ostype == llvm::Triple::Linux))
+ specifier = PRIu64;
+ }
+ if (!specifier)
+ {
+ format = default_format;
+ return true;
+ }
+ }
+ else if (IsToken (var_name_begin, "x}"))
+ specifier = PRIx64;
+ else if (IsToken (var_name_begin, "X}"))
+ specifier = PRIX64;
+ else if (IsToken (var_name_begin, "u}"))
+ specifier = PRIu64;
+
+ if (specifier)
+ {
+ format = "%";
+ if (width_precision_length)
+ format += std::string(width_precision, width_precision_length);
+ format += specifier;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool
+FormatPromptRecurse
+(
+ const char *format,
+ const SymbolContext *sc,
+ const ExecutionContext *exe_ctx,
+ const Address *addr,
+ Stream &s,
+ const char **end,
+ ValueObject* valobj
+)
+{
+ ValueObject* realvalobj = NULL; // makes it super-easy to parse pointers
+ bool success = true;
+ const char *p;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+
+ for (p = format; *p != '\0'; ++p)
+ {
+ if (realvalobj)
+ {
+ valobj = realvalobj;
+ realvalobj = NULL;
+ }
+ size_t non_special_chars = ::strcspn (p, "${}\\");
+ if (non_special_chars > 0)
+ {
+ if (success)
+ s.Write (p, non_special_chars);
+ p += non_special_chars;
+ }
+
+ if (*p == '\0')
+ {
+ break;
+ }
+ else if (*p == '{')
+ {
+ // Start a new scope that must have everything it needs if it is to
+ // to make it into the final output stream "s". If you want to make
+ // a format that only prints out the function or symbol name if there
+ // is one in the symbol context you can use:
+ // "{function =${function.name}}"
+ // The first '{' starts a new scope that end with the matching '}' at
+ // the end of the string. The contents "function =${function.name}"
+ // will then be evaluated and only be output if there is a function
+ // or symbol with a valid name.
+ StreamString sub_strm;
+
+ ++p; // Skip the '{'
+
+ if (FormatPromptRecurse (p, sc, exe_ctx, addr, sub_strm, &p, valobj))
+ {
+ // The stream had all it needed
+ s.Write(sub_strm.GetData(), sub_strm.GetSize());
+ }
+ if (*p != '}')
+ {
+ success = false;
+ break;
+ }
+ }
+ else if (*p == '}')
+ {
+ // End of a enclosing scope
+ break;
+ }
+ else if (*p == '$')
+ {
+ // We have a prompt variable to print
+ ++p;
+ if (*p == '{')
+ {
+ ++p;
+ const char *var_name_begin = p;
+ const char *var_name_end = ::strchr (p, '}');
+
+ if (var_name_end && var_name_begin < var_name_end)
+ {
+ // if we have already failed to parse, skip this variable
+ if (success)
+ {
+ const char *cstr = NULL;
+ std::string token_format;
+ Address format_addr;
+ bool calculate_format_addr_function_offset = false;
+ // Set reg_kind and reg_num to invalid values
+ RegisterKind reg_kind = kNumRegisterKinds;
+ uint32_t reg_num = LLDB_INVALID_REGNUM;
+ FileSpec format_file_spec;
+ const RegisterInfo *reg_info = NULL;
+ RegisterContext *reg_ctx = NULL;
+ bool do_deref_pointer = false;
+ ValueObject::ExpressionPathScanEndReason reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString;
+ ValueObject::ExpressionPathEndResultType final_value_type = ValueObject::eExpressionPathEndResultTypePlain;
+
+ // Each variable must set success to true below...
+ bool var_success = false;
+ switch (var_name_begin[0])
+ {
+ case '*':
+ case 'v':
+ case 's':
+ {
+ if (!valobj)
+ break;
+
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] initial string: %s",var_name_begin);
+
+ // check for *var and *svar
+ if (*var_name_begin == '*')
+ {
+ do_deref_pointer = true;
+ var_name_begin++;
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] found a deref, new string is: %s",var_name_begin);
+ }
+
+ if (*var_name_begin == 's')
+ {
+ if (!valobj->IsSynthetic())
+ valobj = valobj->GetSyntheticValue().get();
+ if (!valobj)
+ break;
+ var_name_begin++;
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] found a synthetic, new string is: %s",var_name_begin);
+ }
+
+ // should be a 'v' by now
+ if (*var_name_begin != 'v')
+ break;
+
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] string I am working with: %s",var_name_begin);
+
+ ValueObject::ExpressionPathAftermath what_next = (do_deref_pointer ?
+ ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing);
+ ValueObject::GetValueForExpressionPathOptions options;
+ options.DontCheckDotVsArrowSyntax().DoAllowBitfieldSyntax().DoAllowFragileIVar().DoAllowSyntheticChildren();
+ ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eValueObjectRepresentationStyleSummary;
+ ValueObject* target = NULL;
+ Format custom_format = eFormatInvalid;
+ const char* var_name_final = NULL;
+ const char* var_name_final_if_array_range = NULL;
+ const char* close_bracket_position = NULL;
+ int64_t index_lower = -1;
+ int64_t index_higher = -1;
+ bool is_array_range = false;
+ const char* first_unparsed;
+ bool was_plain_var = false;
+ bool was_var_format = false;
+ bool was_var_indexed = false;
+
+ if (!valobj) break;
+ // simplest case ${var}, just print valobj's value
+ if (IsToken (var_name_begin, "var}"))
+ {
+ was_plain_var = true;
+ target = valobj;
+ val_obj_display = ValueObject::eValueObjectRepresentationStyleValue;
+ }
+ else if (IsToken (var_name_begin,"var%"))
+ {
+ was_var_format = true;
+ // this is a variable with some custom format applied to it
+ const char* percent_position;
+ target = valobj;
+ val_obj_display = ValueObject::eValueObjectRepresentationStyleValue;
+ ScanFormatDescriptor (var_name_begin,
+ var_name_end,
+ &var_name_final,
+ &percent_position,
+ &custom_format,
+ &val_obj_display);
+ }
+ // this is ${var.something} or multiple .something nested
+ else if (IsToken (var_name_begin, "var"))
+ {
+ if (IsToken (var_name_begin, "var["))
+ was_var_indexed = true;
+ const char* percent_position;
+ ScanFormatDescriptor (var_name_begin,
+ var_name_end,
+ &var_name_final,
+ &percent_position,
+ &custom_format,
+ &val_obj_display);
+
+ const char* open_bracket_position;
+ const char* separator_position;
+ ScanBracketedRange (var_name_begin,
+ var_name_end,
+ var_name_final,
+ &open_bracket_position,
+ &separator_position,
+ &close_bracket_position,
+ &var_name_final_if_array_range,
+ &index_lower,
+ &index_higher);
+
+ Error error;
+
+ std::string expr_path(var_name_final-var_name_begin-1,0);
+ memcpy(&expr_path[0], var_name_begin+3,var_name_final-var_name_begin-3);
+
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] symbol to expand: %s",expr_path.c_str());
+
+ target = valobj->GetValueForExpressionPath(expr_path.c_str(),
+ &first_unparsed,
+ &reason_to_stop,
+ &final_value_type,
+ options,
+ &what_next).get();
+
+ if (!target)
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] ERROR: unparsed portion = %s, why stopping = %d,"
+ " final_value_type %d",
+ first_unparsed, reason_to_stop, final_value_type);
+ break;
+ }
+ else
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] ALL RIGHT: unparsed portion = %s, why stopping = %d,"
+ " final_value_type %d",
+ first_unparsed, reason_to_stop, final_value_type);
+ }
+ }
+ else
+ break;
+
+ is_array_range = (final_value_type == ValueObject::eExpressionPathEndResultTypeBoundedRange ||
+ final_value_type == ValueObject::eExpressionPathEndResultTypeUnboundedRange);
+
+ do_deref_pointer = (what_next == ValueObject::eExpressionPathAftermathDereference);
+
+ if (do_deref_pointer && !is_array_range)
+ {
+ // I have not deref-ed yet, let's do it
+ // this happens when we are not going through GetValueForVariableExpressionPath
+ // to get to the target ValueObject
+ Error error;
+ target = target->Dereference(error).get();
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] ERROR: %s\n", error.AsCString("unknown")); \
+ break;
+ }
+ do_deref_pointer = false;
+ }
+
+ // <rdar://problem/11338654>
+ // we do not want to use the summary for a bitfield of type T:n
+ // if we were originally dealing with just a T - that would get
+ // us into an endless recursion
+ if (target->IsBitfield() && was_var_indexed)
+ {
+ // TODO: check for a (T:n)-specific summary - we should still obey that
+ StreamString bitfield_name;
+ bitfield_name.Printf("%s:%d", target->GetTypeName().AsCString(), target->GetBitfieldBitSize());
+ lldb::TypeNameSpecifierImplSP type_sp(new TypeNameSpecifierImpl(bitfield_name.GetData(),false));
+ if (!DataVisualization::GetSummaryForType(type_sp))
+ val_obj_display = ValueObject::eValueObjectRepresentationStyleValue;
+ }
+
+ // TODO use flags for these
+ const uint32_t type_info_flags = target->GetClangType().GetTypeInfo(NULL);
+ bool is_array = (type_info_flags & ClangASTType::eTypeIsArray) != 0;
+ bool is_pointer = (type_info_flags & ClangASTType::eTypeIsPointer) != 0;
+ bool is_aggregate = target->GetClangType().IsAggregateType();
+
+ if ((is_array || is_pointer) && (!is_array_range) && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) // this should be wrong, but there are some exceptions
+ {
+ StreamString str_temp;
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] I am into array || pointer && !range");
+
+ if (target->HasSpecialPrintableRepresentation(val_obj_display, custom_format))
+ {
+ // try to use the special cases
+ var_success = target->DumpPrintableRepresentation(str_temp,
+ val_obj_display,
+ custom_format);
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] special cases did%s match", var_success ? "" : "n't");
+
+ // should not happen
+ if (var_success)
+ s << str_temp.GetData();
+ var_success = true;
+ break;
+ }
+ else
+ {
+ if (was_plain_var) // if ${var}
+ {
+ s << target->GetTypeName() << " @ " << target->GetLocationAsCString();
+ }
+ else if (is_pointer) // if pointer, value is the address stored
+ {
+ target->DumpPrintableRepresentation (s,
+ val_obj_display,
+ custom_format,
+ ValueObject::ePrintableRepresentationSpecialCasesDisable);
+ }
+ var_success = true;
+ break;
+ }
+ }
+
+ // if directly trying to print ${var}, and this is an aggregate, display a nice
+ // type @ location message
+ if (is_aggregate && was_plain_var)
+ {
+ s << target->GetTypeName() << " @ " << target->GetLocationAsCString();
+ var_success = true;
+ break;
+ }
+
+ // if directly trying to print ${var%V}, and this is an aggregate, do not let the user do it
+ if (is_aggregate && ((was_var_format && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue)))
+ {
+ s << "<invalid use of aggregate type>";
+ var_success = true;
+ break;
+ }
+
+ if (!is_array_range)
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] dumping ordinary printable output");
+ var_success = target->DumpPrintableRepresentation(s,val_obj_display, custom_format);
+ }
+ else
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] checking if I can handle as array");
+ if (!is_array && !is_pointer)
+ break;
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] handle as array");
+ const char* special_directions = NULL;
+ StreamString special_directions_writer;
+ if (close_bracket_position && (var_name_end-close_bracket_position > 1))
+ {
+ ConstString additional_data;
+ additional_data.SetCStringWithLength(close_bracket_position+1, var_name_end-close_bracket_position-1);
+ special_directions_writer.Printf("${%svar%s}",
+ do_deref_pointer ? "*" : "",
+ additional_data.GetCString());
+ special_directions = special_directions_writer.GetData();
+ }
+
+ // let us display items index_lower thru index_higher of this array
+ s.PutChar('[');
+ var_success = true;
+
+ if (index_higher < 0)
+ index_higher = valobj->GetNumChildren() - 1;
+
+ uint32_t max_num_children = target->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
+
+ for (;index_lower<=index_higher;index_lower++)
+ {
+ ValueObject* item = ExpandIndexedExpression (target,
+ index_lower,
+ exe_ctx->GetFramePtr(),
+ false).get();
+
+ if (!item)
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] ERROR in getting child item at index %" PRId64, index_lower);
+ }
+ else
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] special_directions for child item: %s",special_directions);
+ }
+
+ if (!special_directions)
+ var_success &= item->DumpPrintableRepresentation(s,val_obj_display, custom_format);
+ else
+ var_success &= FormatPromptRecurse(special_directions, sc, exe_ctx, addr, s, NULL, item);
+
+ if (--max_num_children == 0)
+ {
+ s.PutCString(", ...");
+ break;
+ }
+
+ if (index_lower < index_higher)
+ s.PutChar(',');
+ }
+ s.PutChar(']');
+ }
+ }
+ break;
+ case 'a':
+ if (IsToken (var_name_begin, "addr}"))
+ {
+ if (addr && addr->IsValid())
+ {
+ var_success = true;
+ format_addr = *addr;
+ }
+ }
+ break;
+
+ case 'p':
+ if (IsToken (var_name_begin, "process."))
+ {
+ if (exe_ctx)
+ {
+ Process *process = exe_ctx->GetProcessPtr();
+ if (process)
+ {
+ var_name_begin += ::strlen ("process.");
+ if (IsTokenWithFormat (var_name_begin, "id", token_format, "%" PRIu64, exe_ctx, sc))
+ {
+ s.Printf(token_format.c_str(), process->GetID());
+ var_success = true;
+ }
+ else if ((IsToken (var_name_begin, "name}")) ||
+ (IsToken (var_name_begin, "file.basename}")) ||
+ (IsToken (var_name_begin, "file.fullpath}")))
+ {
+ Module *exe_module = process->GetTarget().GetExecutableModulePointer();
+ if (exe_module)
+ {
+ if (var_name_begin[0] == 'n' || var_name_begin[5] == 'f')
+ {
+ format_file_spec.GetFilename() = exe_module->GetFileSpec().GetFilename();
+ var_success = format_file_spec;
+ }
+ else
+ {
+ format_file_spec = exe_module->GetFileSpec();
+ var_success = format_file_spec;
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "script:"))
+ {
+ var_name_begin += ::strlen("script:");
+ std::string script_name(var_name_begin,var_name_end);
+ ScriptInterpreter* script_interpreter = process->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (RunScriptFormatKeyword (s, script_interpreter, process, script_name))
+ var_success = true;
+ }
+ }
+ }
+ }
+ break;
+
+ case 't':
+ if (IsToken (var_name_begin, "thread."))
+ {
+ if (exe_ctx)
+ {
+ Thread *thread = exe_ctx->GetThreadPtr();
+ if (thread)
+ {
+ var_name_begin += ::strlen ("thread.");
+ if (IsTokenWithFormat (var_name_begin, "id", token_format, "0x%4.4" PRIx64, exe_ctx, sc))
+ {
+ s.Printf(token_format.c_str(), thread->GetID());
+ var_success = true;
+ }
+ else if (IsTokenWithFormat (var_name_begin, "protocol_id", token_format, "0x%4.4" PRIx64, exe_ctx, sc))
+ {
+ s.Printf(token_format.c_str(), thread->GetProtocolID());
+ var_success = true;
+ }
+ else if (IsTokenWithFormat (var_name_begin, "index", token_format, "%" PRIu64, exe_ctx, sc))
+ {
+ s.Printf(token_format.c_str(), (uint64_t)thread->GetIndexID());
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "name}"))
+ {
+ cstr = thread->GetName();
+ var_success = cstr && cstr[0];
+ if (var_success)
+ s.PutCString(cstr);
+ }
+ else if (IsToken (var_name_begin, "queue}"))
+ {
+ cstr = thread->GetQueueName();
+ var_success = cstr && cstr[0];
+ if (var_success)
+ s.PutCString(cstr);
+ }
+ else if (IsToken (var_name_begin, "stop-reason}"))
+ {
+ StopInfoSP stop_info_sp = thread->GetStopInfo ();
+ if (stop_info_sp && stop_info_sp->IsValid())
+ {
+ cstr = stop_info_sp->GetDescription();
+ if (cstr && cstr[0])
+ {
+ s.PutCString(cstr);
+ var_success = true;
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "return-value}"))
+ {
+ StopInfoSP stop_info_sp = thread->GetStopInfo ();
+ if (stop_info_sp && stop_info_sp->IsValid())
+ {
+ ValueObjectSP return_valobj_sp = StopInfo::GetReturnValueObject (stop_info_sp);
+ if (return_valobj_sp)
+ {
+ ValueObject::DumpValueObject (s, return_valobj_sp.get());
+ var_success = true;
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "script:"))
+ {
+ var_name_begin += ::strlen("script:");
+ std::string script_name(var_name_begin,var_name_end);
+ ScriptInterpreter* script_interpreter = thread->GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (RunScriptFormatKeyword (s, script_interpreter, thread, script_name))
+ var_success = true;
+ }
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "target."))
+ {
+ // TODO: hookup properties
+// if (!target_properties_sp)
+// {
+// Target *target = Target::GetTargetFromContexts (exe_ctx, sc);
+// if (target)
+// target_properties_sp = target->GetProperties();
+// }
+//
+// if (target_properties_sp)
+// {
+// var_name_begin += ::strlen ("target.");
+// const char *end_property = strchr(var_name_begin, '}');
+// if (end_property)
+// {
+// ConstString property_name(var_name_begin, end_property - var_name_begin);
+// std::string property_value (target_properties_sp->GetPropertyValue(property_name));
+// if (!property_value.empty())
+// {
+// s.PutCString (property_value.c_str());
+// var_success = true;
+// }
+// }
+// }
+ Target *target = Target::GetTargetFromContexts (exe_ctx, sc);
+ if (target)
+ {
+ var_name_begin += ::strlen ("target.");
+ if (IsToken (var_name_begin, "arch}"))
+ {
+ ArchSpec arch (target->GetArchitecture ());
+ if (arch.IsValid())
+ {
+ s.PutCString (arch.GetArchitectureName());
+ var_success = true;
+ }
+ }
+ else if (IsToken (var_name_begin, "script:"))
+ {
+ var_name_begin += ::strlen("script:");
+ std::string script_name(var_name_begin,var_name_end);
+ ScriptInterpreter* script_interpreter = target->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (RunScriptFormatKeyword (s, script_interpreter, target, script_name))
+ var_success = true;
+ }
+ }
+ }
+ break;
+
+
+ case 'm':
+ if (IsToken (var_name_begin, "module."))
+ {
+ if (sc && sc->module_sp.get())
+ {
+ Module *module = sc->module_sp.get();
+ var_name_begin += ::strlen ("module.");
+
+ if (IsToken (var_name_begin, "file."))
+ {
+ if (module->GetFileSpec())
+ {
+ var_name_begin += ::strlen ("file.");
+
+ if (IsToken (var_name_begin, "basename}"))
+ {
+ format_file_spec.GetFilename() = module->GetFileSpec().GetFilename();
+ var_success = format_file_spec;
+ }
+ else if (IsToken (var_name_begin, "fullpath}"))
+ {
+ format_file_spec = module->GetFileSpec();
+ var_success = format_file_spec;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+
+ case 'f':
+ if (IsToken (var_name_begin, "file."))
+ {
+ if (sc && sc->comp_unit != NULL)
+ {
+ var_name_begin += ::strlen ("file.");
+
+ if (IsToken (var_name_begin, "basename}"))
+ {
+ format_file_spec.GetFilename() = sc->comp_unit->GetFilename();
+ var_success = format_file_spec;
+ }
+ else if (IsToken (var_name_begin, "fullpath}"))
+ {
+ format_file_spec = *sc->comp_unit;
+ var_success = format_file_spec;
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "frame."))
+ {
+ if (exe_ctx)
+ {
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ if (frame)
+ {
+ var_name_begin += ::strlen ("frame.");
+ if (IsToken (var_name_begin, "index}"))
+ {
+ s.Printf("%u", frame->GetFrameIndex());
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "pc}"))
+ {
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_PC;
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "sp}"))
+ {
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_SP;
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "fp}"))
+ {
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_FP;
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "flags}"))
+ {
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_FLAGS;
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "reg."))
+ {
+ reg_ctx = frame->GetRegisterContext().get();
+ if (reg_ctx)
+ {
+ var_name_begin += ::strlen ("reg.");
+ if (var_name_begin < var_name_end)
+ {
+ std::string reg_name (var_name_begin, var_name_end);
+ reg_info = reg_ctx->GetRegisterInfoByName (reg_name.c_str());
+ if (reg_info)
+ var_success = true;
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "script:"))
+ {
+ var_name_begin += ::strlen("script:");
+ std::string script_name(var_name_begin,var_name_end);
+ ScriptInterpreter* script_interpreter = frame->GetThread()->GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (RunScriptFormatKeyword (s, script_interpreter, frame, script_name))
+ var_success = true;
+ }
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "function."))
+ {
+ if (sc && (sc->function != NULL || sc->symbol != NULL))
+ {
+ var_name_begin += ::strlen ("function.");
+ if (IsToken (var_name_begin, "id}"))
+ {
+ if (sc->function)
+ s.Printf("function{0x%8.8" PRIx64 "}", sc->function->GetID());
+ else
+ s.Printf("symbol[%u]", sc->symbol->GetID());
+
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "name}"))
+ {
+ if (sc->function)
+ cstr = sc->function->GetName().AsCString (NULL);
+ else if (sc->symbol)
+ cstr = sc->symbol->GetName().AsCString (NULL);
+ if (cstr)
+ {
+ s.PutCString(cstr);
+
+ if (sc->block)
+ {
+ Block *inline_block = sc->block->GetContainingInlinedBlock ();
+ if (inline_block)
+ {
+ const InlineFunctionInfo *inline_info = sc->block->GetInlinedFunctionInfo();
+ if (inline_info)
+ {
+ s.PutCString(" [inlined] ");
+ inline_info->GetName().Dump(&s);
+ }
+ }
+ }
+ var_success = true;
+ }
+ }
+ else if (IsToken (var_name_begin, "name-with-args}"))
+ {
+ // Print the function name with arguments in it
+
+ if (sc->function)
+ {
+ var_success = true;
+ ExecutionContextScope *exe_scope = exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL;
+ cstr = sc->function->GetName().AsCString (NULL);
+ if (cstr)
+ {
+ const InlineFunctionInfo *inline_info = NULL;
+ VariableListSP variable_list_sp;
+ bool get_function_vars = true;
+ if (sc->block)
+ {
+ Block *inline_block = sc->block->GetContainingInlinedBlock ();
+
+ if (inline_block)
+ {
+ get_function_vars = false;
+ inline_info = sc->block->GetInlinedFunctionInfo();
+ if (inline_info)
+ variable_list_sp = inline_block->GetBlockVariableList (true);
+ }
+ }
+
+ if (get_function_vars)
+ {
+ variable_list_sp = sc->function->GetBlock(true).GetBlockVariableList (true);
+ }
+
+ if (inline_info)
+ {
+ s.PutCString (cstr);
+ s.PutCString (" [inlined] ");
+ cstr = inline_info->GetName().GetCString();
+ }
+
+ VariableList args;
+ if (variable_list_sp)
+ variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument, args);
+ if (args.GetSize() > 0)
+ {
+ const char *open_paren = strchr (cstr, '(');
+ const char *close_paren = NULL;
+ if (open_paren)
+ {
+ if (IsToken (open_paren, "(anonymous namespace)"))
+ {
+ open_paren = strchr (open_paren + strlen("(anonymous namespace)"), '(');
+ if (open_paren)
+ close_paren = strchr (open_paren, ')');
+ }
+ else
+ close_paren = strchr (open_paren, ')');
+ }
+
+ if (open_paren)
+ s.Write(cstr, open_paren - cstr + 1);
+ else
+ {
+ s.PutCString (cstr);
+ s.PutChar ('(');
+ }
+ const size_t num_args = args.GetSize();
+ for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx)
+ {
+ VariableSP var_sp (args.GetVariableAtIndex (arg_idx));
+ ValueObjectSP var_value_sp (ValueObjectVariable::Create (exe_scope, var_sp));
+ const char *var_name = var_value_sp->GetName().GetCString();
+ const char *var_value = var_value_sp->GetValueAsCString();
+ if (arg_idx > 0)
+ s.PutCString (", ");
+ if (var_value_sp->GetError().Success())
+ {
+ if (var_value)
+ s.Printf ("%s=%s", var_name, var_value);
+ else
+ s.Printf ("%s=%s at %s", var_name, var_value_sp->GetTypeName().GetCString(), var_value_sp->GetLocationAsCString());
+ }
+ else
+ s.Printf ("%s=<unavailable>", var_name);
+ }
+
+ if (close_paren)
+ s.PutCString (close_paren);
+ else
+ s.PutChar(')');
+
+ }
+ else
+ {
+ s.PutCString(cstr);
+ }
+ }
+ }
+ else if (sc->symbol)
+ {
+ cstr = sc->symbol->GetName().AsCString (NULL);
+ if (cstr)
+ {
+ s.PutCString(cstr);
+ var_success = true;
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "addr-offset}"))
+ {
+ var_success = addr != NULL;
+ if (var_success)
+ {
+ format_addr = *addr;
+ calculate_format_addr_function_offset = true;
+ }
+ }
+ else if (IsToken (var_name_begin, "line-offset}"))
+ {
+ var_success = sc->line_entry.range.GetBaseAddress().IsValid();
+ if (var_success)
+ {
+ format_addr = sc->line_entry.range.GetBaseAddress();
+ calculate_format_addr_function_offset = true;
+ }
+ }
+ else if (IsToken (var_name_begin, "pc-offset}"))
+ {
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ var_success = frame != NULL;
+ if (var_success)
+ {
+ format_addr = frame->GetFrameCodeAddress();
+ calculate_format_addr_function_offset = true;
+ }
+ }
+ }
+ }
+ break;
+
+ case 'l':
+ if (IsToken (var_name_begin, "line."))
+ {
+ if (sc && sc->line_entry.IsValid())
+ {
+ var_name_begin += ::strlen ("line.");
+ if (IsToken (var_name_begin, "file."))
+ {
+ var_name_begin += ::strlen ("file.");
+
+ if (IsToken (var_name_begin, "basename}"))
+ {
+ format_file_spec.GetFilename() = sc->line_entry.file.GetFilename();
+ var_success = format_file_spec;
+ }
+ else if (IsToken (var_name_begin, "fullpath}"))
+ {
+ format_file_spec = sc->line_entry.file;
+ var_success = format_file_spec;
+ }
+ }
+ else if (IsTokenWithFormat (var_name_begin, "number", token_format, "%" PRIu64, exe_ctx, sc))
+ {
+ var_success = true;
+ s.Printf(token_format.c_str(), (uint64_t)sc->line_entry.line);
+ }
+ else if ((IsToken (var_name_begin, "start-addr}")) ||
+ (IsToken (var_name_begin, "end-addr}")))
+ {
+ var_success = sc && sc->line_entry.range.GetBaseAddress().IsValid();
+ if (var_success)
+ {
+ format_addr = sc->line_entry.range.GetBaseAddress();
+ if (var_name_begin[0] == 'e')
+ format_addr.Slide (sc->line_entry.range.GetByteSize());
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ if (var_success)
+ {
+ // If format addr is valid, then we need to print an address
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ // We have a register value to display...
+ if (reg_num == LLDB_REGNUM_GENERIC_PC && reg_kind == eRegisterKindGeneric)
+ {
+ format_addr = frame->GetFrameCodeAddress();
+ }
+ else
+ {
+ if (reg_ctx == NULL)
+ reg_ctx = frame->GetRegisterContext().get();
+
+ if (reg_ctx)
+ {
+ if (reg_kind != kNumRegisterKinds)
+ reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num);
+ reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_num);
+ var_success = reg_info != NULL;
+ }
+ }
+ }
+
+ if (reg_info != NULL)
+ {
+ RegisterValue reg_value;
+ var_success = reg_ctx->ReadRegister (reg_info, reg_value);
+ if (var_success)
+ {
+ reg_value.Dump(&s, reg_info, false, false, eFormatDefault);
+ }
+ }
+
+ if (format_file_spec)
+ {
+ s << format_file_spec;
+ }
+
+ // If format addr is valid, then we need to print an address
+ if (format_addr.IsValid())
+ {
+ var_success = false;
+
+ if (calculate_format_addr_function_offset)
+ {
+ Address func_addr;
+
+ if (sc)
+ {
+ if (sc->function)
+ {
+ func_addr = sc->function->GetAddressRange().GetBaseAddress();
+ if (sc->block)
+ {
+ // Check to make sure we aren't in an inline
+ // function. If we are, use the inline block
+ // range that contains "format_addr" since
+ // blocks can be discontiguous.
+ Block *inline_block = sc->block->GetContainingInlinedBlock ();
+ AddressRange inline_range;
+ if (inline_block && inline_block->GetRangeContainingAddress (format_addr, inline_range))
+ func_addr = inline_range.GetBaseAddress();
+ }
+ }
+ else if (sc->symbol && sc->symbol->ValueIsAddress())
+ func_addr = sc->symbol->GetAddress();
+ }
+
+ if (func_addr.IsValid())
+ {
+ if (func_addr.GetSection() == format_addr.GetSection())
+ {
+ addr_t func_file_addr = func_addr.GetFileAddress();
+ addr_t addr_file_addr = format_addr.GetFileAddress();
+ if (addr_file_addr > func_file_addr)
+ s.Printf(" + %" PRIu64, addr_file_addr - func_file_addr);
+ else if (addr_file_addr < func_file_addr)
+ s.Printf(" - %" PRIu64, func_file_addr - addr_file_addr);
+ var_success = true;
+ }
+ else
+ {
+ Target *target = Target::GetTargetFromContexts (exe_ctx, sc);
+ if (target)
+ {
+ addr_t func_load_addr = func_addr.GetLoadAddress (target);
+ addr_t addr_load_addr = format_addr.GetLoadAddress (target);
+ if (addr_load_addr > func_load_addr)
+ s.Printf(" + %" PRIu64, addr_load_addr - func_load_addr);
+ else if (addr_load_addr < func_load_addr)
+ s.Printf(" - %" PRIu64, func_load_addr - addr_load_addr);
+ var_success = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ Target *target = Target::GetTargetFromContexts (exe_ctx, sc);
+ addr_t vaddr = LLDB_INVALID_ADDRESS;
+ if (exe_ctx && !target->GetSectionLoadList().IsEmpty())
+ vaddr = format_addr.GetLoadAddress (target);
+ if (vaddr == LLDB_INVALID_ADDRESS)
+ vaddr = format_addr.GetFileAddress ();
+
+ if (vaddr != LLDB_INVALID_ADDRESS)
+ {
+ int addr_width = target->GetArchitecture().GetAddressByteSize() * 2;
+ if (addr_width == 0)
+ addr_width = 16;
+ s.Printf("0x%*.*" PRIx64, addr_width, addr_width, vaddr);
+ var_success = true;
+ }
+ }
+ }
+ }
+
+ if (var_success == false)
+ success = false;
+ }
+ p = var_name_end;
+ }
+ else
+ break;
+ }
+ else
+ {
+ // We got a dollar sign with no '{' after it, it must just be a dollar sign
+ s.PutChar(*p);
+ }
+ }
+ else if (*p == '\\')
+ {
+ ++p; // skip the slash
+ switch (*p)
+ {
+ case 'a': s.PutChar ('\a'); break;
+ case 'b': s.PutChar ('\b'); break;
+ case 'f': s.PutChar ('\f'); break;
+ case 'n': s.PutChar ('\n'); break;
+ case 'r': s.PutChar ('\r'); break;
+ case 't': s.PutChar ('\t'); break;
+ case 'v': s.PutChar ('\v'); break;
+ case '\'': s.PutChar ('\''); break;
+ case '\\': s.PutChar ('\\'); break;
+ case '0':
+ // 1 to 3 octal chars
+ {
+ // Make a string that can hold onto the initial zero char,
+ // up to 3 octal digits, and a terminating NULL.
+ char oct_str[5] = { 0, 0, 0, 0, 0 };
+
+ int i;
+ for (i=0; (p[i] >= '0' && p[i] <= '7') && i<4; ++i)
+ oct_str[i] = p[i];
+
+ // We don't want to consume the last octal character since
+ // the main for loop will do this for us, so we advance p by
+ // one less than i (even if i is zero)
+ p += i - 1;
+ unsigned long octal_value = ::strtoul (oct_str, NULL, 8);
+ if (octal_value <= UINT8_MAX)
+ {
+ s.PutChar((char)octal_value);
+ }
+ }
+ break;
+
+ case 'x':
+ // hex number in the format
+ if (isxdigit(p[1]))
+ {
+ ++p; // Skip the 'x'
+
+ // Make a string that can hold onto two hex chars plus a
+ // NULL terminator
+ char hex_str[3] = { 0,0,0 };
+ hex_str[0] = *p;
+ if (isxdigit(p[1]))
+ {
+ ++p; // Skip the first of the two hex chars
+ hex_str[1] = *p;
+ }
+
+ unsigned long hex_value = strtoul (hex_str, NULL, 16);
+ if (hex_value <= UINT8_MAX)
+ s.PutChar ((char)hex_value);
+ }
+ else
+ {
+ s.PutChar('x');
+ }
+ break;
+
+ default:
+ // Just desensitize any other character by just printing what
+ // came after the '\'
+ s << *p;
+ break;
+
+ }
+
+ }
+ }
+ if (end)
+ *end = p;
+ return success;
+}
+
+bool
+Debugger::FormatPrompt
+(
+ const char *format,
+ const SymbolContext *sc,
+ const ExecutionContext *exe_ctx,
+ const Address *addr,
+ Stream &s,
+ ValueObject* valobj
+)
+{
+ bool use_color = exe_ctx ? exe_ctx->GetTargetRef().GetDebugger().GetUseColor() : true;
+ std::string format_str = lldb_utility::ansi::FormatAnsiTerminalCodes (format, use_color);
+ if (format_str.length())
+ format = format_str.c_str();
+ return FormatPromptRecurse (format, sc, exe_ctx, addr, s, NULL, valobj);
+}
+
+void
+Debugger::SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton)
+{
+ // For simplicity's sake, I am not going to deal with how to close down any
+ // open logging streams, I just redirect everything from here on out to the
+ // callback.
+ m_log_callback_stream_sp.reset (new StreamCallback (log_callback, baton));
+}
+
+bool
+Debugger::EnableLog (const char *channel, const char **categories, const char *log_file, uint32_t log_options, Stream &error_stream)
+{
+ Log::Callbacks log_callbacks;
+
+ StreamSP log_stream_sp;
+ if (m_log_callback_stream_sp)
+ {
+ log_stream_sp = m_log_callback_stream_sp;
+ // For now when using the callback mode you always get thread & timestamp.
+ log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
+ }
+ else if (log_file == NULL || *log_file == '\0')
+ {
+ log_stream_sp.reset(new StreamFile(GetOutputFile().GetDescriptor(), false));
+ }
+ else
+ {
+ LogStreamMap::iterator pos = m_log_streams.find(log_file);
+ if (pos != m_log_streams.end())
+ log_stream_sp = pos->second.lock();
+ if (!log_stream_sp)
+ {
+ log_stream_sp.reset (new StreamFile (log_file));
+ m_log_streams[log_file] = log_stream_sp;
+ }
+ }
+ assert (log_stream_sp.get());
+
+ if (log_options == 0)
+ log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE;
+
+ if (Log::GetLogChannelCallbacks (ConstString(channel), log_callbacks))
+ {
+ log_callbacks.enable (log_stream_sp, log_options, categories, &error_stream);
+ return true;
+ }
+ else
+ {
+ LogChannelSP log_channel_sp (LogChannel::FindPlugin (channel));
+ if (log_channel_sp)
+ {
+ if (log_channel_sp->Enable (log_stream_sp, log_options, &error_stream, categories))
+ {
+ return true;
+ }
+ else
+ {
+ error_stream.Printf ("Invalid log channel '%s'.\n", channel);
+ return false;
+ }
+ }
+ else
+ {
+ error_stream.Printf ("Invalid log channel '%s'.\n", channel);
+ return false;
+ }
+ }
+ return false;
+}
+
+SourceManager &
+Debugger::GetSourceManager ()
+{
+ if (m_source_manager_ap.get() == NULL)
+ m_source_manager_ap.reset (new SourceManager (shared_from_this()));
+ return *m_source_manager_ap;
+}
+
+
diff --git a/source/Core/Disassembler.cpp b/source/Core/Disassembler.cpp
new file mode 100644
index 0000000..e80e92c
--- /dev/null
+++ b/source/Core/Disassembler.cpp
@@ -0,0 +1,1269 @@
+//===-- Disassembler.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/lldb-python.h"
+
+#include "lldb/Core/Disassembler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Interpreter/OptionValue.h"
+#include "lldb/Interpreter/OptionValueArray.h"
+#include "lldb/Interpreter/OptionValueDictionary.h"
+#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Interpreter/OptionValueUInt64.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+
+#define DEFAULT_DISASM_BYTE_SIZE 32
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+DisassemblerSP
+Disassembler::FindPlugin (const ArchSpec &arch, const char *flavor, const char *plugin_name)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "Disassembler::FindPlugin (arch = %s, plugin_name = %s)",
+ arch.GetArchitectureName(),
+ plugin_name);
+
+ DisassemblerCreateInstance create_callback = NULL;
+
+ if (plugin_name)
+ {
+ ConstString const_plugin_name (plugin_name);
+ create_callback = PluginManager::GetDisassemblerCreateCallbackForPluginName (const_plugin_name);
+ if (create_callback)
+ {
+ DisassemblerSP disassembler_sp(create_callback(arch, flavor));
+
+ if (disassembler_sp.get())
+ return disassembler_sp;
+ }
+ }
+ else
+ {
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ DisassemblerSP disassembler_sp(create_callback(arch, flavor));
+
+ if (disassembler_sp.get())
+ return disassembler_sp;
+ }
+ }
+ return DisassemblerSP();
+}
+
+DisassemblerSP
+Disassembler::FindPluginForTarget(const TargetSP target_sp, const ArchSpec &arch, const char *flavor, const char *plugin_name)
+{
+ if (target_sp && flavor == NULL)
+ {
+ // FIXME - we don't have the mechanism in place to do per-architecture settings. But since we know that for now
+ // we only support flavors on x86 & x86_64,
+ if (arch.GetTriple().getArch() == llvm::Triple::x86
+ || arch.GetTriple().getArch() == llvm::Triple::x86_64)
+ flavor = target_sp->GetDisassemblyFlavor();
+ }
+ return FindPlugin(arch, flavor, plugin_name);
+}
+
+
+static void
+ResolveAddress (const ExecutionContext &exe_ctx,
+ const Address &addr,
+ Address &resolved_addr)
+{
+ if (!addr.IsSectionOffset())
+ {
+ // If we weren't passed in a section offset address range,
+ // try and resolve it to something
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ if (target->GetSectionLoadList().IsEmpty())
+ {
+ target->GetImages().ResolveFileAddress (addr.GetOffset(), resolved_addr);
+ }
+ else
+ {
+ target->GetSectionLoadList().ResolveLoadAddress (addr.GetOffset(), resolved_addr);
+ }
+ // We weren't able to resolve the address, just treat it as a
+ // raw address
+ if (resolved_addr.IsValid())
+ return;
+ }
+ }
+ resolved_addr = addr;
+}
+
+size_t
+Disassembler::Disassemble
+(
+ Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ SymbolContextList &sc_list,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm
+)
+{
+ size_t success_count = 0;
+ const size_t count = sc_list.GetSize();
+ SymbolContext sc;
+ AddressRange range;
+ const uint32_t scope = eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = true;
+ for (size_t i=0; i<count; ++i)
+ {
+ if (sc_list.GetContextAtIndex(i, sc) == false)
+ break;
+ for (uint32_t range_idx = 0; sc.GetAddressRange(scope, range_idx, use_inline_block_range, range); ++range_idx)
+ {
+ if (Disassemble (debugger,
+ arch,
+ plugin_name,
+ flavor,
+ exe_ctx,
+ range,
+ num_instructions,
+ num_mixed_context_lines,
+ options,
+ strm))
+ {
+ ++success_count;
+ strm.EOL();
+ }
+ }
+ }
+ return success_count;
+}
+
+bool
+Disassembler::Disassemble
+(
+ Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const ConstString &name,
+ Module *module,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm
+)
+{
+ SymbolContextList sc_list;
+ if (name)
+ {
+ const bool include_symbols = true;
+ const bool include_inlines = true;
+ if (module)
+ {
+ module->FindFunctions (name,
+ NULL,
+ eFunctionNameTypeAuto,
+ include_symbols,
+ include_inlines,
+ true,
+ sc_list);
+ }
+ else if (exe_ctx.GetTargetPtr())
+ {
+ exe_ctx.GetTargetPtr()->GetImages().FindFunctions (name,
+ eFunctionNameTypeAuto,
+ include_symbols,
+ include_inlines,
+ false,
+ sc_list);
+ }
+ }
+
+ if (sc_list.GetSize ())
+ {
+ return Disassemble (debugger,
+ arch,
+ plugin_name,
+ flavor,
+ exe_ctx,
+ sc_list,
+ num_instructions,
+ num_mixed_context_lines,
+ options,
+ strm);
+ }
+ return false;
+}
+
+
+lldb::DisassemblerSP
+Disassembler::DisassembleRange
+(
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const AddressRange &range
+)
+{
+ lldb::DisassemblerSP disasm_sp;
+ if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid())
+ {
+ disasm_sp = Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(), arch, flavor, plugin_name);
+
+ if (disasm_sp)
+ {
+ const bool prefer_file_cache = false;
+ size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx, range, NULL, prefer_file_cache);
+ if (bytes_disassembled == 0)
+ disasm_sp.reset();
+ }
+ }
+ return disasm_sp;
+}
+
+lldb::DisassemblerSP
+Disassembler::DisassembleBytes (const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const Address &start,
+ const void *src,
+ size_t src_len,
+ uint32_t num_instructions,
+ bool data_from_file)
+{
+ lldb::DisassemblerSP disasm_sp;
+
+ if (src)
+ {
+ disasm_sp = Disassembler::FindPlugin(arch, flavor, plugin_name);
+
+ if (disasm_sp)
+ {
+ DataExtractor data(src, src_len, arch.GetByteOrder(), arch.GetAddressByteSize());
+
+ (void)disasm_sp->DecodeInstructions (start,
+ data,
+ 0,
+ num_instructions,
+ false,
+ data_from_file);
+ }
+ }
+
+ return disasm_sp;
+}
+
+
+bool
+Disassembler::Disassemble
+(
+ Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const AddressRange &disasm_range,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm
+)
+{
+ if (disasm_range.GetByteSize())
+ {
+ lldb::DisassemblerSP disasm_sp (Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(), arch, flavor, plugin_name));
+
+ if (disasm_sp.get())
+ {
+ AddressRange range;
+ ResolveAddress (exe_ctx, disasm_range.GetBaseAddress(), range.GetBaseAddress());
+ range.SetByteSize (disasm_range.GetByteSize());
+ const bool prefer_file_cache = false;
+ size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx, range, &strm, prefer_file_cache);
+ if (bytes_disassembled == 0)
+ return false;
+
+ bool result = PrintInstructions (disasm_sp.get(),
+ debugger,
+ arch,
+ exe_ctx,
+ num_instructions,
+ num_mixed_context_lines,
+ options,
+ strm);
+
+ // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
+ // I'll fix that but for now, just clear the list and it will go away nicely.
+ disasm_sp->GetInstructionList().Clear();
+ return result;
+ }
+ }
+ return false;
+}
+
+bool
+Disassembler::Disassemble
+(
+ Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const Address &start_address,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm
+)
+{
+ if (num_instructions > 0)
+ {
+ lldb::DisassemblerSP disasm_sp (Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(),
+ arch,
+ flavor,
+ plugin_name));
+ if (disasm_sp.get())
+ {
+ Address addr;
+ ResolveAddress (exe_ctx, start_address, addr);
+ const bool prefer_file_cache = false;
+ size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx,
+ addr,
+ num_instructions,
+ prefer_file_cache);
+ if (bytes_disassembled == 0)
+ return false;
+ bool result = PrintInstructions (disasm_sp.get(),
+ debugger,
+ arch,
+ exe_ctx,
+ num_instructions,
+ num_mixed_context_lines,
+ options,
+ strm);
+
+ // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
+ // I'll fix that but for now, just clear the list and it will go away nicely.
+ disasm_sp->GetInstructionList().Clear();
+ return result;
+ }
+ }
+ return false;
+}
+
+bool
+Disassembler::PrintInstructions
+(
+ Disassembler *disasm_ptr,
+ Debugger &debugger,
+ const ArchSpec &arch,
+ const ExecutionContext &exe_ctx,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm
+)
+{
+ // We got some things disassembled...
+ size_t num_instructions_found = disasm_ptr->GetInstructionList().GetSize();
+
+ if (num_instructions > 0 && num_instructions < num_instructions_found)
+ num_instructions_found = num_instructions;
+
+ const uint32_t max_opcode_byte_size = disasm_ptr->GetInstructionList().GetMaxOpcocdeByteSize ();
+ uint32_t offset = 0;
+ SymbolContext sc;
+ SymbolContext prev_sc;
+ AddressRange sc_range;
+ const Address *pc_addr_ptr = NULL;
+ ExecutionContextScope *exe_scope = exe_ctx.GetBestExecutionContextScope();
+ StackFrame *frame = exe_ctx.GetFramePtr();
+
+ TargetSP target_sp (exe_ctx.GetTargetSP());
+ SourceManager &source_manager = target_sp ? target_sp->GetSourceManager() : debugger.GetSourceManager();
+
+ if (frame)
+ pc_addr_ptr = &frame->GetFrameCodeAddress();
+ const uint32_t scope = eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+ for (size_t i=0; i<num_instructions_found; ++i)
+ {
+ Instruction *inst = disasm_ptr->GetInstructionList().GetInstructionAtIndex (i).get();
+ if (inst)
+ {
+ const Address &addr = inst->GetAddress();
+ const bool inst_is_at_pc = pc_addr_ptr && addr == *pc_addr_ptr;
+
+ prev_sc = sc;
+
+ ModuleSP module_sp (addr.GetModule());
+ if (module_sp)
+ {
+ uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc);
+ if (resolved_mask)
+ {
+ if (num_mixed_context_lines)
+ {
+ if (!sc_range.ContainsFileAddress (addr))
+ {
+ sc.GetAddressRange (scope, 0, use_inline_block_range, sc_range);
+
+ if (sc != prev_sc)
+ {
+ if (offset != 0)
+ strm.EOL();
+
+ sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, true, false);
+ strm.EOL();
+
+ if (sc.comp_unit && sc.line_entry.IsValid())
+ {
+ source_manager.DisplaySourceLinesWithLineNumbers (sc.line_entry.file,
+ sc.line_entry.line,
+ num_mixed_context_lines,
+ num_mixed_context_lines,
+ ((inst_is_at_pc && (options & eOptionMarkPCSourceLine)) ? "->" : ""),
+ &strm);
+ }
+ }
+ }
+ }
+ else if ((sc.function || sc.symbol) && (sc.function != prev_sc.function || sc.symbol != prev_sc.symbol))
+ {
+ if (prev_sc.function || prev_sc.symbol)
+ strm.EOL();
+
+ bool show_fullpaths = false;
+ bool show_module = true;
+ bool show_inlined_frames = true;
+ sc.DumpStopContext (&strm,
+ exe_scope,
+ addr,
+ show_fullpaths,
+ show_module,
+ show_inlined_frames);
+
+ strm << ":\n";
+ }
+ }
+ else
+ {
+ sc.Clear(true);
+ }
+ }
+
+ if ((options & eOptionMarkPCAddress) && pc_addr_ptr)
+ {
+ strm.PutCString(inst_is_at_pc ? "-> " : " ");
+ }
+ const bool show_bytes = (options & eOptionShowBytes) != 0;
+ inst->Dump(&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx);
+ strm.EOL();
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+bool
+Disassembler::Disassemble
+(
+ Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm
+)
+{
+ AddressRange range;
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
+ if (sc.function)
+ {
+ range = sc.function->GetAddressRange();
+ }
+ else if (sc.symbol && sc.symbol->ValueIsAddress())
+ {
+ range.GetBaseAddress() = sc.symbol->GetAddress();
+ range.SetByteSize (sc.symbol->GetByteSize());
+ }
+ else
+ {
+ range.GetBaseAddress() = frame->GetFrameCodeAddress();
+ }
+
+ if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)
+ range.SetByteSize (DEFAULT_DISASM_BYTE_SIZE);
+ }
+
+ return Disassemble (debugger,
+ arch,
+ plugin_name,
+ flavor,
+ exe_ctx,
+ range,
+ num_instructions,
+ num_mixed_context_lines,
+ options,
+ strm);
+}
+
+Instruction::Instruction(const Address &address, AddressClass addr_class) :
+ m_address (address),
+ m_address_class (addr_class),
+ m_opcode(),
+ m_calculated_strings(false)
+{
+}
+
+Instruction::~Instruction()
+{
+}
+
+AddressClass
+Instruction::GetAddressClass ()
+{
+ if (m_address_class == eAddressClassInvalid)
+ m_address_class = m_address.GetAddressClass();
+ return m_address_class;
+}
+
+void
+Instruction::Dump (lldb_private::Stream *s,
+ uint32_t max_opcode_byte_size,
+ bool show_address,
+ bool show_bytes,
+ const ExecutionContext* exe_ctx)
+{
+ size_t opcode_column_width = 7;
+ const size_t operand_column_width = 25;
+
+ CalculateMnemonicOperandsAndCommentIfNeeded (exe_ctx);
+
+ StreamString ss;
+
+ if (show_address)
+ {
+ m_address.Dump(&ss,
+ exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL,
+ Address::DumpStyleLoadAddress,
+ Address::DumpStyleModuleWithFileAddress,
+ 0);
+
+ ss.PutCString(": ");
+ }
+
+ if (show_bytes)
+ {
+ if (m_opcode.GetType() == Opcode::eTypeBytes)
+ {
+ // x86_64 and i386 are the only ones that use bytes right now so
+ // pad out the byte dump to be able to always show 15 bytes (3 chars each)
+ // plus a space
+ if (max_opcode_byte_size > 0)
+ m_opcode.Dump (&ss, max_opcode_byte_size * 3 + 1);
+ else
+ m_opcode.Dump (&ss, 15 * 3 + 1);
+ }
+ else
+ {
+ // Else, we have ARM which can show up to a uint32_t 0x00000000 (10 spaces)
+ // plus two for padding...
+ if (max_opcode_byte_size > 0)
+ m_opcode.Dump (&ss, max_opcode_byte_size * 3 + 1);
+ else
+ m_opcode.Dump (&ss, 12);
+ }
+ }
+
+ const size_t opcode_pos = ss.GetSize();
+
+ // The default opcode size of 7 characters is plenty for most architectures
+ // but some like arm can pull out the occasional vqrshrun.s16. We won't get
+ // consistent column spacing in these cases, unfortunately.
+ if (m_opcode_name.length() >= opcode_column_width)
+ {
+ opcode_column_width = m_opcode_name.length() + 1;
+ }
+
+ ss.PutCString (m_opcode_name.c_str());
+ ss.FillLastLineToColumn (opcode_pos + opcode_column_width, ' ');
+ ss.PutCString (m_mnemonics.c_str());
+
+ if (!m_comment.empty())
+ {
+ ss.FillLastLineToColumn (opcode_pos + opcode_column_width + operand_column_width, ' ');
+ ss.PutCString (" ; ");
+ ss.PutCString (m_comment.c_str());
+ }
+ s->Write (ss.GetData(), ss.GetSize());
+}
+
+bool
+Instruction::DumpEmulation (const ArchSpec &arch)
+{
+ std::unique_ptr<EmulateInstruction> insn_emulator_ap (EmulateInstruction::FindPlugin (arch, eInstructionTypeAny, NULL));
+ if (insn_emulator_ap.get())
+ {
+ insn_emulator_ap->SetInstruction (GetOpcode(), GetAddress(), NULL);
+ return insn_emulator_ap->EvaluateInstruction (0);
+ }
+
+ return false;
+}
+
+OptionValueSP
+Instruction::ReadArray (FILE *in_file, Stream *out_stream, OptionValue::Type data_type)
+{
+ bool done = false;
+ char buffer[1024];
+
+ OptionValueSP option_value_sp (new OptionValueArray (1u << data_type));
+
+ int idx = 0;
+ while (!done)
+ {
+ if (!fgets (buffer, 1023, in_file))
+ {
+ out_stream->Printf ("Instruction::ReadArray: Error reading file (fgets).\n");
+ option_value_sp.reset ();
+ return option_value_sp;
+ }
+
+ std::string line (buffer);
+
+ size_t len = line.size();
+ if (line[len-1] == '\n')
+ {
+ line[len-1] = '\0';
+ line.resize (len-1);
+ }
+
+ if ((line.size() == 1) && line[0] == ']')
+ {
+ done = true;
+ line.clear();
+ }
+
+ if (line.size() > 0)
+ {
+ std::string value;
+ static RegularExpression g_reg_exp ("^[ \t]*([^ \t]+)[ \t]*$");
+ RegularExpression::Match regex_match(1);
+ bool reg_exp_success = g_reg_exp.Execute (line.c_str(), &regex_match);
+ if (reg_exp_success)
+ regex_match.GetMatchAtIndex (line.c_str(), 1, value);
+ else
+ value = line;
+
+ OptionValueSP data_value_sp;
+ switch (data_type)
+ {
+ case OptionValue::eTypeUInt64:
+ data_value_sp.reset (new OptionValueUInt64 (0, 0));
+ data_value_sp->SetValueFromCString (value.c_str());
+ break;
+ // Other types can be added later as needed.
+ default:
+ data_value_sp.reset (new OptionValueString (value.c_str(), ""));
+ break;
+ }
+
+ option_value_sp->GetAsArray()->InsertValue (idx, data_value_sp);
+ ++idx;
+ }
+ }
+
+ return option_value_sp;
+}
+
+OptionValueSP
+Instruction::ReadDictionary (FILE *in_file, Stream *out_stream)
+{
+ bool done = false;
+ char buffer[1024];
+
+ OptionValueSP option_value_sp (new OptionValueDictionary());
+ static ConstString encoding_key ("data_encoding");
+ OptionValue::Type data_type = OptionValue::eTypeInvalid;
+
+
+ while (!done)
+ {
+ // Read the next line in the file
+ if (!fgets (buffer, 1023, in_file))
+ {
+ out_stream->Printf ("Instruction::ReadDictionary: Error reading file (fgets).\n");
+ option_value_sp.reset ();
+ return option_value_sp;
+ }
+
+ // Check to see if the line contains the end-of-dictionary marker ("}")
+ std::string line (buffer);
+
+ size_t len = line.size();
+ if (line[len-1] == '\n')
+ {
+ line[len-1] = '\0';
+ line.resize (len-1);
+ }
+
+ if ((line.size() == 1) && (line[0] == '}'))
+ {
+ done = true;
+ line.clear();
+ }
+
+ // Try to find a key-value pair in the current line and add it to the dictionary.
+ if (line.size() > 0)
+ {
+ static RegularExpression g_reg_exp ("^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*=[ \t]*(.*)[ \t]*$");
+ RegularExpression::Match regex_match(2);
+
+ bool reg_exp_success = g_reg_exp.Execute (line.c_str(), &regex_match);
+ std::string key;
+ std::string value;
+ if (reg_exp_success)
+ {
+ regex_match.GetMatchAtIndex (line.c_str(), 1, key);
+ regex_match.GetMatchAtIndex (line.c_str(), 2, value);
+ }
+ else
+ {
+ out_stream->Printf ("Instruction::ReadDictionary: Failure executing regular expression.\n");
+ option_value_sp.reset();
+ return option_value_sp;
+ }
+
+ ConstString const_key (key.c_str());
+ // Check value to see if it's the start of an array or dictionary.
+
+ lldb::OptionValueSP value_sp;
+ assert (value.empty() == false);
+ assert (key.empty() == false);
+
+ if (value[0] == '{')
+ {
+ assert (value.size() == 1);
+ // value is a dictionary
+ value_sp = ReadDictionary (in_file, out_stream);
+ if (value_sp.get() == NULL)
+ {
+ option_value_sp.reset ();
+ return option_value_sp;
+ }
+ }
+ else if (value[0] == '[')
+ {
+ assert (value.size() == 1);
+ // value is an array
+ value_sp = ReadArray (in_file, out_stream, data_type);
+ if (value_sp.get() == NULL)
+ {
+ option_value_sp.reset ();
+ return option_value_sp;
+ }
+ // We've used the data_type to read an array; re-set the type to Invalid
+ data_type = OptionValue::eTypeInvalid;
+ }
+ else if ((value[0] == '0') && (value[1] == 'x'))
+ {
+ value_sp.reset (new OptionValueUInt64 (0, 0));
+ value_sp->SetValueFromCString (value.c_str());
+ }
+ else
+ {
+ size_t len = value.size();
+ if ((value[0] == '"') && (value[len-1] == '"'))
+ value = value.substr (1, len-2);
+ value_sp.reset (new OptionValueString (value.c_str(), ""));
+ }
+
+
+
+ if (const_key == encoding_key)
+ {
+ // A 'data_encoding=..." is NOT a normal key-value pair; it is meta-data indicating the
+ // data type of an upcoming array (usually the next bit of data to be read in).
+ if (strcmp (value.c_str(), "uint32_t") == 0)
+ data_type = OptionValue::eTypeUInt64;
+ }
+ else
+ option_value_sp->GetAsDictionary()->SetValueForKey (const_key, value_sp, false);
+ }
+ }
+
+ return option_value_sp;
+}
+
+bool
+Instruction::TestEmulation (Stream *out_stream, const char *file_name)
+{
+ if (!out_stream)
+ return false;
+
+ if (!file_name)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Missing file_name.");
+ return false;
+ }
+
+ FILE *test_file = fopen (file_name, "r");
+ if (!test_file)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Attempt to open test file failed.");
+ return false;
+ }
+
+ char buffer[256];
+ if (!fgets (buffer, 255, test_file))
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Error reading first line of test file.\n");
+ fclose (test_file);
+ return false;
+ }
+
+ if (strncmp (buffer, "InstructionEmulationState={", 27) != 0)
+ {
+ out_stream->Printf ("Instructin::TestEmulation: Test file does not contain emulation state dictionary\n");
+ fclose (test_file);
+ return false;
+ }
+
+ // Read all the test information from the test file into an OptionValueDictionary.
+
+ OptionValueSP data_dictionary_sp (ReadDictionary (test_file, out_stream));
+ if (data_dictionary_sp.get() == NULL)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Error reading Dictionary Object.\n");
+ fclose (test_file);
+ return false;
+ }
+
+ fclose (test_file);
+
+ OptionValueDictionary *data_dictionary = data_dictionary_sp->GetAsDictionary();
+ static ConstString description_key ("assembly_string");
+ static ConstString triple_key ("triple");
+
+ OptionValueSP value_sp = data_dictionary->GetValueForKey (description_key);
+
+ if (value_sp.get() == NULL)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Test file does not contain description string.\n");
+ return false;
+ }
+
+ SetDescription (value_sp->GetStringValue());
+
+
+ value_sp = data_dictionary->GetValueForKey (triple_key);
+ if (value_sp.get() == NULL)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Test file does not contain triple.\n");
+ return false;
+ }
+
+ ArchSpec arch;
+ arch.SetTriple (llvm::Triple (value_sp->GetStringValue()));
+
+ bool success = false;
+ std::unique_ptr<EmulateInstruction> insn_emulator_ap (EmulateInstruction::FindPlugin (arch, eInstructionTypeAny, NULL));
+ if (insn_emulator_ap.get())
+ success = insn_emulator_ap->TestEmulation (out_stream, arch, data_dictionary);
+
+ if (success)
+ out_stream->Printf ("Emulation test succeeded.");
+ else
+ out_stream->Printf ("Emulation test failed.");
+
+ return success;
+}
+
+bool
+Instruction::Emulate (const ArchSpec &arch,
+ uint32_t evaluate_options,
+ void *baton,
+ EmulateInstruction::ReadMemoryCallback read_mem_callback,
+ EmulateInstruction::WriteMemoryCallback write_mem_callback,
+ EmulateInstruction::ReadRegisterCallback read_reg_callback,
+ EmulateInstruction::WriteRegisterCallback write_reg_callback)
+{
+ std::unique_ptr<EmulateInstruction> insn_emulator_ap (EmulateInstruction::FindPlugin (arch, eInstructionTypeAny, NULL));
+ if (insn_emulator_ap.get())
+ {
+ insn_emulator_ap->SetBaton (baton);
+ insn_emulator_ap->SetCallbacks (read_mem_callback, write_mem_callback, read_reg_callback, write_reg_callback);
+ insn_emulator_ap->SetInstruction (GetOpcode(), GetAddress(), NULL);
+ return insn_emulator_ap->EvaluateInstruction (evaluate_options);
+ }
+
+ return false;
+}
+
+
+uint32_t
+Instruction::GetData (DataExtractor &data)
+{
+ return m_opcode.GetData(data);
+}
+
+InstructionList::InstructionList() :
+ m_instructions()
+{
+}
+
+InstructionList::~InstructionList()
+{
+}
+
+size_t
+InstructionList::GetSize() const
+{
+ return m_instructions.size();
+}
+
+uint32_t
+InstructionList::GetMaxOpcocdeByteSize () const
+{
+ uint32_t max_inst_size = 0;
+ collection::const_iterator pos, end;
+ for (pos = m_instructions.begin(), end = m_instructions.end();
+ pos != end;
+ ++pos)
+ {
+ uint32_t inst_size = (*pos)->GetOpcode().GetByteSize();
+ if (max_inst_size < inst_size)
+ max_inst_size = inst_size;
+ }
+ return max_inst_size;
+}
+
+
+
+InstructionSP
+InstructionList::GetInstructionAtIndex (size_t idx) const
+{
+ InstructionSP inst_sp;
+ if (idx < m_instructions.size())
+ inst_sp = m_instructions[idx];
+ return inst_sp;
+}
+
+void
+InstructionList::Dump (Stream *s,
+ bool show_address,
+ bool show_bytes,
+ const ExecutionContext* exe_ctx)
+{
+ const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize();
+ collection::const_iterator pos, begin, end;
+ for (begin = m_instructions.begin(), end = m_instructions.end(), pos = begin;
+ pos != end;
+ ++pos)
+ {
+ if (pos != begin)
+ s->EOL();
+ (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx);
+ }
+}
+
+
+void
+InstructionList::Clear()
+{
+ m_instructions.clear();
+}
+
+void
+InstructionList::Append (lldb::InstructionSP &inst_sp)
+{
+ if (inst_sp)
+ m_instructions.push_back(inst_sp);
+}
+
+uint32_t
+InstructionList::GetIndexOfNextBranchInstruction(uint32_t start) const
+{
+ size_t num_instructions = m_instructions.size();
+
+ uint32_t next_branch = UINT32_MAX;
+ for (size_t i = start; i < num_instructions; i++)
+ {
+ if (m_instructions[i]->DoesBranch())
+ {
+ next_branch = i;
+ break;
+ }
+ }
+ return next_branch;
+}
+
+uint32_t
+InstructionList::GetIndexOfInstructionAtLoadAddress (lldb::addr_t load_addr, Target &target)
+{
+ Address address;
+ address.SetLoadAddress(load_addr, &target);
+ size_t num_instructions = m_instructions.size();
+ uint32_t index = UINT32_MAX;
+ for (size_t i = 0; i < num_instructions; i++)
+ {
+ if (m_instructions[i]->GetAddress() == address)
+ {
+ index = i;
+ break;
+ }
+ }
+ return index;
+}
+
+size_t
+Disassembler::ParseInstructions (const ExecutionContext *exe_ctx,
+ const AddressRange &range,
+ Stream *error_strm_ptr,
+ bool prefer_file_cache)
+{
+ if (exe_ctx)
+ {
+ Target *target = exe_ctx->GetTargetPtr();
+ const addr_t byte_size = range.GetByteSize();
+ if (target == NULL || byte_size == 0 || !range.GetBaseAddress().IsValid())
+ return 0;
+
+ DataBufferHeap *heap_buffer = new DataBufferHeap (byte_size, '\0');
+ DataBufferSP data_sp(heap_buffer);
+
+ Error error;
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ const size_t bytes_read = target->ReadMemory (range.GetBaseAddress(),
+ prefer_file_cache,
+ heap_buffer->GetBytes(),
+ heap_buffer->GetByteSize(),
+ error,
+ &load_addr);
+
+ if (bytes_read > 0)
+ {
+ if (bytes_read != heap_buffer->GetByteSize())
+ heap_buffer->SetByteSize (bytes_read);
+ DataExtractor data (data_sp,
+ m_arch.GetByteOrder(),
+ m_arch.GetAddressByteSize());
+ const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
+ return DecodeInstructions (range.GetBaseAddress(), data, 0, UINT32_MAX, false, data_from_file);
+ }
+ else if (error_strm_ptr)
+ {
+ const char *error_cstr = error.AsCString();
+ if (error_cstr)
+ {
+ error_strm_ptr->Printf("error: %s\n", error_cstr);
+ }
+ }
+ }
+ else if (error_strm_ptr)
+ {
+ error_strm_ptr->PutCString("error: invalid execution context\n");
+ }
+ return 0;
+}
+
+size_t
+Disassembler::ParseInstructions (const ExecutionContext *exe_ctx,
+ const Address &start,
+ uint32_t num_instructions,
+ bool prefer_file_cache)
+{
+ m_instruction_list.Clear();
+
+ if (exe_ctx == NULL || num_instructions == 0 || !start.IsValid())
+ return 0;
+
+ Target *target = exe_ctx->GetTargetPtr();
+ // Calculate the max buffer size we will need in order to disassemble
+ const addr_t byte_size = num_instructions * m_arch.GetMaximumOpcodeByteSize();
+
+ if (target == NULL || byte_size == 0)
+ return 0;
+
+ DataBufferHeap *heap_buffer = new DataBufferHeap (byte_size, '\0');
+ DataBufferSP data_sp (heap_buffer);
+
+ Error error;
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ const size_t bytes_read = target->ReadMemory (start,
+ prefer_file_cache,
+ heap_buffer->GetBytes(),
+ byte_size,
+ error,
+ &load_addr);
+
+ const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
+
+ if (bytes_read == 0)
+ return 0;
+ DataExtractor data (data_sp,
+ m_arch.GetByteOrder(),
+ m_arch.GetAddressByteSize());
+
+ const bool append_instructions = true;
+ DecodeInstructions (start,
+ data,
+ 0,
+ num_instructions,
+ append_instructions,
+ data_from_file);
+
+ return m_instruction_list.GetSize();
+}
+
+//----------------------------------------------------------------------
+// Disassembler copy constructor
+//----------------------------------------------------------------------
+Disassembler::Disassembler(const ArchSpec& arch, const char *flavor) :
+ m_arch (arch),
+ m_instruction_list(),
+ m_base_addr(LLDB_INVALID_ADDRESS),
+ m_flavor ()
+{
+ if (flavor == NULL)
+ m_flavor.assign("default");
+ else
+ m_flavor.assign(flavor);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Disassembler::~Disassembler()
+{
+}
+
+InstructionList &
+Disassembler::GetInstructionList ()
+{
+ return m_instruction_list;
+}
+
+const InstructionList &
+Disassembler::GetInstructionList () const
+{
+ return m_instruction_list;
+}
+
+//----------------------------------------------------------------------
+// Class PseudoInstruction
+//----------------------------------------------------------------------
+PseudoInstruction::PseudoInstruction () :
+ Instruction (Address(), eAddressClassUnknown),
+ m_description ()
+{
+}
+
+PseudoInstruction::~PseudoInstruction ()
+{
+}
+
+bool
+PseudoInstruction::DoesBranch ()
+{
+ // This is NOT a valid question for a pseudo instruction.
+ return false;
+}
+
+size_t
+PseudoInstruction::Decode (const lldb_private::Disassembler &disassembler,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t data_offset)
+{
+ return m_opcode.GetByteSize();
+}
+
+
+void
+PseudoInstruction::SetOpcode (size_t opcode_size, void *opcode_data)
+{
+ if (!opcode_data)
+ return;
+
+ switch (opcode_size)
+ {
+ case 8:
+ {
+ uint8_t value8 = *((uint8_t *) opcode_data);
+ m_opcode.SetOpcode8 (value8);
+ break;
+ }
+ case 16:
+ {
+ uint16_t value16 = *((uint16_t *) opcode_data);
+ m_opcode.SetOpcode16 (value16);
+ break;
+ }
+ case 32:
+ {
+ uint32_t value32 = *((uint32_t *) opcode_data);
+ m_opcode.SetOpcode32 (value32);
+ break;
+ }
+ case 64:
+ {
+ uint64_t value64 = *((uint64_t *) opcode_data);
+ m_opcode.SetOpcode64 (value64);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void
+PseudoInstruction::SetDescription (const char *description)
+{
+ if (description && strlen (description) > 0)
+ m_description = description;
+}
diff --git a/source/Core/DynamicLoader.cpp b/source/Core/DynamicLoader.cpp
new file mode 100644
index 0000000..82f8404
--- /dev/null
+++ b/source/Core/DynamicLoader.cpp
@@ -0,0 +1,76 @@
+//===-- 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/lldb-private.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Core/PluginManager.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+DynamicLoader*
+DynamicLoader::FindPlugin (Process *process, const char *plugin_name)
+{
+ DynamicLoaderCreateInstance create_callback = NULL;
+ 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.get())
+ return instance_ap.release();
+ }
+ }
+ else
+ {
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetDynamicLoaderCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ std::unique_ptr<DynamicLoader> instance_ap(create_callback(process, false));
+ if (instance_ap.get())
+ return instance_ap.release();
+ }
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// DynamicLoader constructor
+//----------------------------------------------------------------------
+DynamicLoader::DynamicLoader(Process *process) :
+ m_process (process)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DynamicLoader::~DynamicLoader()
+{
+}
+
+//----------------------------------------------------------------------
+// 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);
+}
+
diff --git a/source/Core/EmulateInstruction.cpp b/source/Core/EmulateInstruction.cpp
new file mode 100644
index 0000000..bf6c6d8
--- /dev/null
+++ b/source/Core/EmulateInstruction.cpp
@@ -0,0 +1,670 @@
+//===-- EmulateInstruction.h ------------------------------------*- 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/EmulateInstruction.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+EmulateInstruction*
+EmulateInstruction::FindPlugin (const ArchSpec &arch, InstructionType supported_inst_type, const char *plugin_name)
+{
+ EmulateInstructionCreateInstance create_callback = NULL;
+ if (plugin_name)
+ {
+ ConstString const_plugin_name (plugin_name);
+ create_callback = PluginManager::GetEmulateInstructionCreateCallbackForPluginName (const_plugin_name);
+ if (create_callback)
+ {
+ EmulateInstruction *emulate_insn_ptr = create_callback(arch, supported_inst_type);
+ if (emulate_insn_ptr)
+ return emulate_insn_ptr;
+ }
+ }
+ else
+ {
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetEmulateInstructionCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ EmulateInstruction *emulate_insn_ptr = create_callback(arch, supported_inst_type);
+ if (emulate_insn_ptr)
+ return emulate_insn_ptr;
+ }
+ }
+ return NULL;
+}
+
+EmulateInstruction::EmulateInstruction (const ArchSpec &arch) :
+ m_arch (arch),
+ m_baton (NULL),
+ m_read_mem_callback (&ReadMemoryDefault),
+ m_write_mem_callback (&WriteMemoryDefault),
+ m_read_reg_callback (&ReadRegisterDefault),
+ m_write_reg_callback (&WriteRegisterDefault),
+ m_addr (LLDB_INVALID_ADDRESS)
+{
+ ::memset (&m_opcode, 0, sizeof (m_opcode));
+}
+
+
+bool
+EmulateInstruction::ReadRegister (const RegisterInfo *reg_info, RegisterValue& reg_value)
+{
+ if (m_read_reg_callback)
+ return m_read_reg_callback (this, m_baton, reg_info, reg_value);
+ return false;
+}
+
+bool
+EmulateInstruction::ReadRegister (uint32_t reg_kind, uint32_t reg_num, RegisterValue& reg_value)
+{
+ RegisterInfo reg_info;
+ if (GetRegisterInfo(reg_kind, reg_num, reg_info))
+ return ReadRegister (&reg_info, reg_value);
+ return false;
+}
+
+uint64_t
+EmulateInstruction::ReadRegisterUnsigned (uint32_t reg_kind,
+ uint32_t reg_num,
+ uint64_t fail_value,
+ bool *success_ptr)
+{
+ RegisterValue reg_value;
+ if (ReadRegister (reg_kind, reg_num, reg_value))
+ return reg_value.GetAsUInt64(fail_value, success_ptr);
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+uint64_t
+EmulateInstruction::ReadRegisterUnsigned (const RegisterInfo *reg_info,
+ uint64_t fail_value,
+ bool *success_ptr)
+{
+ RegisterValue reg_value;
+ if (ReadRegister (reg_info, reg_value))
+ return reg_value.GetAsUInt64(fail_value, success_ptr);
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+bool
+EmulateInstruction::WriteRegister (const Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue& reg_value)
+{
+ if (m_write_reg_callback)
+ return m_write_reg_callback (this, m_baton, context, reg_info, reg_value);
+ return false;
+}
+
+bool
+EmulateInstruction::WriteRegister (const Context &context,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ const RegisterValue& reg_value)
+{
+ RegisterInfo reg_info;
+ if (GetRegisterInfo(reg_kind, reg_num, reg_info))
+ return WriteRegister (context, &reg_info, reg_value);
+ return false;
+}
+
+
+bool
+EmulateInstruction::WriteRegisterUnsigned (const Context &context,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ uint64_t uint_value)
+{
+
+ RegisterInfo reg_info;
+ if (GetRegisterInfo(reg_kind, reg_num, reg_info))
+ {
+ RegisterValue reg_value;
+ if (reg_value.SetUInt(uint_value, reg_info.byte_size))
+ return WriteRegister (context, &reg_info, reg_value);
+ }
+ return false;
+}
+
+bool
+EmulateInstruction::WriteRegisterUnsigned (const Context &context,
+ const RegisterInfo *reg_info,
+ uint64_t uint_value)
+{
+
+ if (reg_info)
+ {
+ RegisterValue reg_value;
+ if (reg_value.SetUInt(uint_value, reg_info->byte_size))
+ return WriteRegister (context, reg_info, reg_value);
+ }
+ return false;
+}
+
+size_t
+EmulateInstruction::ReadMemory (const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t dst_len)
+{
+ if (m_read_mem_callback)
+ return m_read_mem_callback (this, m_baton, context, addr, dst, dst_len) == dst_len;
+ return false;
+}
+
+uint64_t
+EmulateInstruction::ReadMemoryUnsigned (const Context &context, lldb::addr_t addr, size_t byte_size, uint64_t fail_value, bool *success_ptr)
+{
+ uint64_t uval64 = 0;
+ bool success = false;
+ if (byte_size <= 8)
+ {
+ uint8_t buf[sizeof(uint64_t)];
+ size_t bytes_read = m_read_mem_callback (this, m_baton, context, addr, buf, byte_size);
+ if (bytes_read == byte_size)
+ {
+ lldb::offset_t offset = 0;
+ DataExtractor data (buf, byte_size, GetByteOrder(), GetAddressByteSize());
+ uval64 = data.GetMaxU64 (&offset, byte_size);
+ success = true;
+ }
+ }
+
+ if (success_ptr)
+ *success_ptr = success;
+
+ if (!success)
+ uval64 = fail_value;
+ return uval64;
+}
+
+
+bool
+EmulateInstruction::WriteMemoryUnsigned (const Context &context,
+ lldb::addr_t addr,
+ uint64_t uval,
+ size_t uval_byte_size)
+{
+ StreamString strm(Stream::eBinary, GetAddressByteSize(), GetByteOrder());
+ strm.PutMaxHex64 (uval, uval_byte_size);
+
+ size_t bytes_written = m_write_mem_callback (this, m_baton, context, addr, strm.GetData(), uval_byte_size);
+ if (bytes_written == uval_byte_size)
+ return true;
+ return false;
+}
+
+bool
+EmulateInstruction::WriteMemory (const Context &context,
+ lldb::addr_t addr,
+ const void *src,
+ size_t src_len)
+{
+ if (m_write_mem_callback)
+ return m_write_mem_callback (this, m_baton, context, addr, src, src_len) == src_len;
+ return false;
+}
+
+
+void
+EmulateInstruction::SetBaton (void *baton)
+{
+ m_baton = baton;
+}
+
+void
+EmulateInstruction::SetCallbacks (ReadMemoryCallback read_mem_callback,
+ WriteMemoryCallback write_mem_callback,
+ ReadRegisterCallback read_reg_callback,
+ WriteRegisterCallback write_reg_callback)
+{
+ m_read_mem_callback = read_mem_callback;
+ m_write_mem_callback = write_mem_callback;
+ m_read_reg_callback = read_reg_callback;
+ m_write_reg_callback = write_reg_callback;
+}
+
+void
+EmulateInstruction::SetReadMemCallback (ReadMemoryCallback read_mem_callback)
+{
+ m_read_mem_callback = read_mem_callback;
+}
+
+
+void
+EmulateInstruction::SetWriteMemCallback (WriteMemoryCallback write_mem_callback)
+{
+ m_write_mem_callback = write_mem_callback;
+}
+
+
+void
+EmulateInstruction::SetReadRegCallback (ReadRegisterCallback read_reg_callback)
+{
+ m_read_reg_callback = read_reg_callback;
+}
+
+
+void
+EmulateInstruction::SetWriteRegCallback (WriteRegisterCallback write_reg_callback)
+{
+ m_write_reg_callback = write_reg_callback;
+}
+
+
+
+//
+// Read & Write Memory and Registers callback functions.
+//
+
+size_t
+EmulateInstruction::ReadMemoryFrame (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t dst_len)
+{
+ if (!baton || dst == NULL || dst_len == 0)
+ return 0;
+
+ StackFrame *frame = (StackFrame *) baton;
+
+ ProcessSP process_sp (frame->CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ return process_sp->ReadMemory (addr, dst, dst_len, error);
+ }
+ return 0;
+}
+
+size_t
+EmulateInstruction::WriteMemoryFrame (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ const void *src,
+ size_t src_len)
+{
+ if (!baton || src == NULL || src_len == 0)
+ return 0;
+
+ StackFrame *frame = (StackFrame *) baton;
+
+ ProcessSP process_sp (frame->CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ return process_sp->WriteMemory (addr, src, src_len, error);
+ }
+
+ return 0;
+}
+
+bool
+EmulateInstruction::ReadRegisterFrame (EmulateInstruction *instruction,
+ void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value)
+{
+ if (!baton)
+ return false;
+
+ StackFrame *frame = (StackFrame *) baton;
+ return frame->GetRegisterContext()->ReadRegister (reg_info, reg_value);
+}
+
+bool
+EmulateInstruction::WriteRegisterFrame (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value)
+{
+ if (!baton)
+ return false;
+
+ StackFrame *frame = (StackFrame *) baton;
+ return frame->GetRegisterContext()->WriteRegister (reg_info, reg_value);
+}
+
+size_t
+EmulateInstruction::ReadMemoryDefault (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length)
+{
+ StreamFile strm (stdout, false);
+ strm.Printf (" Read from Memory (address = 0x%" PRIx64 ", length = %" PRIu64 ", context = ", addr, (uint64_t)length);
+ context.Dump (strm, instruction);
+ strm.EOL();
+ *((uint64_t *) dst) = 0xdeadbeef;
+ return length;
+}
+
+size_t
+EmulateInstruction::WriteMemoryDefault (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length)
+{
+ StreamFile strm (stdout, false);
+ strm.Printf (" Write to Memory (address = 0x%" PRIx64 ", length = %" PRIu64 ", context = ", addr, (uint64_t)length);
+ context.Dump (strm, instruction);
+ strm.EOL();
+ return length;
+}
+
+bool
+EmulateInstruction::ReadRegisterDefault (EmulateInstruction *instruction,
+ void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value)
+{
+ StreamFile strm (stdout, false);
+ strm.Printf (" Read Register (%s)\n", reg_info->name);
+ uint32_t reg_kind, reg_num;
+ if (GetBestRegisterKindAndNumber (reg_info, reg_kind, reg_num))
+ reg_value.SetUInt64((uint64_t)reg_kind << 24 | reg_num);
+ else
+ reg_value.SetUInt64(0);
+
+ return true;
+}
+
+bool
+EmulateInstruction::WriteRegisterDefault (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value)
+{
+ StreamFile strm (stdout, false);
+ strm.Printf (" Write to Register (name = %s, value = " , reg_info->name);
+ reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
+ strm.PutCString (", context = ");
+ context.Dump (strm, instruction);
+ strm.EOL();
+ return true;
+}
+
+void
+EmulateInstruction::Context::Dump (Stream &strm,
+ EmulateInstruction *instruction) const
+{
+ switch (type)
+ {
+ case eContextReadOpcode:
+ strm.PutCString ("reading opcode");
+ break;
+
+ case eContextImmediate:
+ strm.PutCString ("immediate");
+ break;
+
+ case eContextPushRegisterOnStack:
+ strm.PutCString ("push register");
+ break;
+
+ case eContextPopRegisterOffStack:
+ strm.PutCString ("pop register");
+ break;
+
+ case eContextAdjustStackPointer:
+ strm.PutCString ("adjust sp");
+ break;
+
+ case eContextSetFramePointer:
+ strm.PutCString ("set frame pointer");
+ break;
+
+ case eContextAdjustBaseRegister:
+ strm.PutCString ("adjusting (writing value back to) a base register");
+ break;
+
+ case eContextRegisterPlusOffset:
+ strm.PutCString ("register + offset");
+ break;
+
+ case eContextRegisterStore:
+ strm.PutCString ("store register");
+ break;
+
+ case eContextRegisterLoad:
+ strm.PutCString ("load register");
+ break;
+
+ case eContextRelativeBranchImmediate:
+ strm.PutCString ("relative branch immediate");
+ break;
+
+ case eContextAbsoluteBranchRegister:
+ strm.PutCString ("absolute branch register");
+ break;
+
+ case eContextSupervisorCall:
+ strm.PutCString ("supervisor call");
+ break;
+
+ case eContextTableBranchReadMemory:
+ strm.PutCString ("table branch read memory");
+ break;
+
+ case eContextWriteRegisterRandomBits:
+ strm.PutCString ("write random bits to a register");
+ break;
+
+ case eContextWriteMemoryRandomBits:
+ strm.PutCString ("write random bits to a memory address");
+ break;
+
+ case eContextArithmetic:
+ strm.PutCString ("arithmetic");
+ break;
+
+ case eContextReturnFromException:
+ strm.PutCString ("return from exception");
+ break;
+
+ default:
+ strm.PutCString ("unrecognized context.");
+ break;
+ }
+
+ switch (info_type)
+ {
+ case eInfoTypeRegisterPlusOffset:
+ {
+ strm.Printf (" (reg_plus_offset = %s%+" PRId64 ")",
+ info.RegisterPlusOffset.reg.name,
+ info.RegisterPlusOffset.signed_offset);
+ }
+ break;
+
+ case eInfoTypeRegisterPlusIndirectOffset:
+ {
+ strm.Printf (" (reg_plus_reg = %s + %s)",
+ info.RegisterPlusIndirectOffset.base_reg.name,
+ info.RegisterPlusIndirectOffset.offset_reg.name);
+ }
+ break;
+
+ case eInfoTypeRegisterToRegisterPlusOffset:
+ {
+ strm.Printf (" (base_and_imm_offset = %s%+" PRId64 ", data_reg = %s)",
+ info.RegisterToRegisterPlusOffset.base_reg.name,
+ info.RegisterToRegisterPlusOffset.offset,
+ info.RegisterToRegisterPlusOffset.data_reg.name);
+ }
+ break;
+
+ case eInfoTypeRegisterToRegisterPlusIndirectOffset:
+ {
+ strm.Printf (" (base_and_reg_offset = %s + %s, data_reg = %s)",
+ info.RegisterToRegisterPlusIndirectOffset.base_reg.name,
+ info.RegisterToRegisterPlusIndirectOffset.offset_reg.name,
+ info.RegisterToRegisterPlusIndirectOffset.data_reg.name);
+ }
+ break;
+
+ case eInfoTypeRegisterRegisterOperands:
+ {
+ strm.Printf (" (register to register binary op: %s and %s)",
+ info.RegisterRegisterOperands.operand1.name,
+ info.RegisterRegisterOperands.operand2.name);
+ }
+ break;
+
+ case eInfoTypeOffset:
+ strm.Printf (" (signed_offset = %+" PRId64 ")", info.signed_offset);
+ break;
+
+ case eInfoTypeRegister:
+ strm.Printf (" (reg = %s)", info.reg.name);
+ break;
+
+ case eInfoTypeImmediate:
+ strm.Printf (" (unsigned_immediate = %" PRIu64 " (0x%16.16" PRIx64 "))",
+ info.unsigned_immediate,
+ info.unsigned_immediate);
+ break;
+
+ case eInfoTypeImmediateSigned:
+ strm.Printf (" (signed_immediate = %+" PRId64 " (0x%16.16" PRIx64 "))",
+ info.signed_immediate,
+ info.signed_immediate);
+ break;
+
+ case eInfoTypeAddress:
+ strm.Printf (" (address = 0x%" PRIx64 ")", info.address);
+ break;
+
+ case eInfoTypeISAAndImmediate:
+ strm.Printf (" (isa = %u, unsigned_immediate = %u (0x%8.8x))",
+ info.ISAAndImmediate.isa,
+ info.ISAAndImmediate.unsigned_data32,
+ info.ISAAndImmediate.unsigned_data32);
+ break;
+
+ case eInfoTypeISAAndImmediateSigned:
+ strm.Printf (" (isa = %u, signed_immediate = %i (0x%8.8x))",
+ info.ISAAndImmediateSigned.isa,
+ info.ISAAndImmediateSigned.signed_data32,
+ info.ISAAndImmediateSigned.signed_data32);
+ break;
+
+ case eInfoTypeISA:
+ strm.Printf (" (isa = %u)", info.isa);
+ break;
+
+ case eInfoTypeNoArgs:
+ break;
+ }
+}
+
+bool
+EmulateInstruction::SetInstruction (const Opcode &opcode, const Address &inst_addr, Target *target)
+{
+ m_opcode = opcode;
+ m_addr = LLDB_INVALID_ADDRESS;
+ if (inst_addr.IsValid())
+ {
+ if (target)
+ m_addr = inst_addr.GetLoadAddress (target);
+ if (m_addr == LLDB_INVALID_ADDRESS)
+ m_addr = inst_addr.GetFileAddress ();
+ }
+ return true;
+}
+
+bool
+EmulateInstruction::GetBestRegisterKindAndNumber (const RegisterInfo *reg_info,
+ uint32_t &reg_kind,
+ uint32_t &reg_num)
+{
+ // Generic and DWARF should be the two most popular register kinds when
+ // emulating instructions since they are the most platform agnostic...
+ reg_num = reg_info->kinds[eRegisterKindGeneric];
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ reg_kind = eRegisterKindGeneric;
+ return true;
+ }
+
+ reg_num = reg_info->kinds[eRegisterKindDWARF];
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ reg_kind = eRegisterKindDWARF;
+ return true;
+ }
+
+ reg_num = reg_info->kinds[eRegisterKindLLDB];
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ reg_kind = eRegisterKindLLDB;
+ return true;
+ }
+
+ reg_num = reg_info->kinds[eRegisterKindGCC];
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ reg_kind = eRegisterKindGCC;
+ return true;
+ }
+
+ reg_num = reg_info->kinds[eRegisterKindGDB];
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ reg_kind = eRegisterKindGDB;
+ return true;
+ }
+ return false;
+}
+
+uint32_t
+EmulateInstruction::GetInternalRegisterNumber (RegisterContext *reg_ctx, const RegisterInfo &reg_info)
+{
+ uint32_t reg_kind, reg_num;
+ if (reg_ctx && GetBestRegisterKindAndNumber (&reg_info, reg_kind, reg_num))
+ return reg_ctx->ConvertRegisterKindToRegisterNumber (reg_kind, reg_num);
+ return LLDB_INVALID_REGNUM;
+}
+
+
+bool
+EmulateInstruction::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ return false;
+}
+
+
diff --git a/source/Core/Error.cpp b/source/Core/Error.cpp
new file mode 100644
index 0000000..e29f12f
--- /dev/null
+++ b/source/Core/Error.cpp
@@ -0,0 +1,399 @@
+//===-- Error.cpp -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "llvm/ADT/SmallVector.h"
+#include <cstdarg>
+#include <cstdlib>
+#include <cstring>
+
+#if defined (__arm__) && defined (__APPLE__)
+#include <SpringBoardServices/SpringBoardServer.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+Error::Error ():
+ m_code (0),
+ m_type (eErrorTypeInvalid),
+ m_string ()
+{
+}
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+Error::Error(ValueType err, ErrorType type) :
+ m_code (err),
+ m_type (type),
+ m_string ()
+{
+}
+
+Error::Error (const Error &rhs) :
+ m_code (rhs.m_code),
+ m_type (rhs.m_type),
+ m_string (rhs.m_string)
+{
+}
+
+Error::Error (const char* err_str):
+ m_code (0),
+ m_type (eErrorTypeInvalid),
+ m_string ()
+{
+ SetErrorString(err_str);
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const Error&
+Error::operator = (const Error& rhs)
+{
+ if (this != &rhs)
+ {
+ m_code = rhs.m_code;
+ m_type = rhs.m_type;
+ m_string = rhs.m_string;
+ }
+ return *this;
+}
+
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const Error&
+Error::operator = (uint32_t err)
+{
+ m_code = err;
+ m_type = eErrorTypeMachKernel;
+ m_string.clear();
+ return *this;
+}
+
+Error::~Error()
+{
+}
+
+//----------------------------------------------------------------------
+// Get the error value as a NULL C string. The error string will be
+// fetched and cached on demand. The cached error string value will
+// remain until the error value is changed or cleared.
+//----------------------------------------------------------------------
+const char *
+Error::AsCString(const char *default_error_str) const
+{
+ if (Success())
+ return NULL;
+
+ if (m_string.empty())
+ {
+ const char *s = NULL;
+ switch (m_type)
+ {
+ case eErrorTypeMachKernel:
+#if defined (__APPLE__)
+ s = ::mach_error_string (m_code);
+#endif
+ break;
+
+ case eErrorTypePOSIX:
+ s = ::strerror (m_code);
+ break;
+
+ default:
+ break;
+ }
+ if (s)
+ m_string.assign(s);
+ }
+ if (m_string.empty())
+ {
+ if (default_error_str)
+ m_string.assign(default_error_str);
+ else
+ return NULL; // User wanted a NULL string back...
+ }
+ return m_string.c_str();
+}
+
+
+//----------------------------------------------------------------------
+// Clear the error and any cached error string that it might contain.
+//----------------------------------------------------------------------
+void
+Error::Clear ()
+{
+ m_code = 0;
+ m_type = eErrorTypeGeneric;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Access the error value.
+//----------------------------------------------------------------------
+Error::ValueType
+Error::GetError () const
+{
+ return m_code;
+}
+
+//----------------------------------------------------------------------
+// Access the error type.
+//----------------------------------------------------------------------
+ErrorType
+Error::GetType () const
+{
+ return m_type;
+}
+
+//----------------------------------------------------------------------
+// Retuns true if this object contains an value that describes an
+// error or otherwise non-success result.
+//----------------------------------------------------------------------
+bool
+Error::Fail () const
+{
+ return m_code != 0;
+}
+
+//----------------------------------------------------------------------
+// Log the error given a string with format. If the this object
+// contains an error code, update the error string to contain the
+// "error: " followed by the formatted string, followed by the error
+// value and any string that describes the current error. This
+// allows more context to be given to an error string that remains
+// cached in this object. Logging always occurs even when the error
+// code contains a non-error value.
+//----------------------------------------------------------------------
+void
+Error::PutToLog (Log *log, const char *format, ...)
+{
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ if (Fail())
+ {
+ const char *err_str = AsCString();
+ if (err_str == NULL)
+ err_str = "???";
+
+ SetErrorStringWithFormat("error: %s err = %s (0x%8.8x)", arg_msg, err_str, m_code);
+ if (log)
+ log->Error("%s", m_string.c_str());
+ }
+ else
+ {
+ if (log)
+ log->Printf("%s err = 0x%8.8x", arg_msg, m_code);
+ }
+ ::free (arg_msg);
+ }
+}
+
+//----------------------------------------------------------------------
+// Log the error given a string with format. If the this object
+// contains an error code, update the error string to contain the
+// "error: " followed by the formatted string, followed by the error
+// value and any string that describes the current error. This
+// allows more context to be given to an error string that remains
+// cached in this object. Logging only occurs even when the error
+// code contains a error value.
+//----------------------------------------------------------------------
+void
+Error::LogIfError (Log *log, const char *format, ...)
+{
+ if (Fail())
+ {
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ const char *err_str = AsCString();
+ if (err_str == NULL)
+ err_str = "???";
+
+ SetErrorStringWithFormat("error: %s err = %s (0x%8.8x)", arg_msg, err_str, m_code);
+ if (log)
+ log->Error("%s", m_string.c_str());
+
+ ::free (arg_msg);
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// Set accesssor for the error value to "err" and the type to
+// "eErrorTypeMachKernel"
+//----------------------------------------------------------------------
+void
+Error::SetMachError (uint32_t err)
+{
+ m_code = err;
+ m_type = eErrorTypeMachKernel;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Set accesssor for the error value and type.
+//----------------------------------------------------------------------
+void
+Error::SetError (ValueType err, ErrorType type)
+{
+ m_code = err;
+ m_type = type;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Update the error value to be "errno" and update the type to
+// be "POSIX".
+//----------------------------------------------------------------------
+void
+Error::SetErrorToErrno()
+{
+ m_code = errno;
+ m_type = eErrorTypePOSIX;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Update the error value to be LLDB_GENERIC_ERROR and update the type
+// to be "Generic".
+//----------------------------------------------------------------------
+void
+Error::SetErrorToGenericError ()
+{
+ m_code = LLDB_GENERIC_ERROR;
+ m_type = eErrorTypeGeneric;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Set accessor for the error string value for a specific error.
+// This allows any string to be supplied as an error explanation.
+// The error string value will remain until the error value is
+// cleared or a new error value/type is assigned.
+//----------------------------------------------------------------------
+void
+Error::SetErrorString (const char *err_str)
+{
+ if (err_str && err_str[0])
+ {
+ // If we have an error string, we should always at least have
+ // an error set to a generic value.
+ if (Success())
+ SetErrorToGenericError();
+ m_string = err_str;
+ }
+ else
+ m_string.clear();
+}
+
+//------------------------------------------------------------------
+/// Set the current error string to a formatted error string.
+///
+/// @param format
+/// A printf style format string
+//------------------------------------------------------------------
+int
+Error::SetErrorStringWithFormat (const char *format, ...)
+{
+ if (format && format[0])
+ {
+ va_list args;
+ va_start (args, format);
+ int length = SetErrorStringWithVarArg (format, args);
+ va_end (args);
+ return length;
+ }
+ else
+ {
+ m_string.clear();
+ }
+ return 0;
+}
+
+int
+Error::SetErrorStringWithVarArg (const char *format, va_list args)
+{
+ if (format && format[0])
+ {
+ // If we have an error string, we should always at least have
+ // an error set to a generic value.
+ if (Success())
+ SetErrorToGenericError();
+
+ // Try and fit our error into a 1024 byte buffer first...
+ llvm::SmallVector<char, 1024> buf;
+ buf.resize(1024);
+ // Copy in case our first call to vsnprintf doesn't fit into our
+ // allocated buffer above
+ va_list copy_args;
+ va_copy (copy_args, args);
+ unsigned length = ::vsnprintf (buf.data(), buf.size(), format, args);
+ if (length >= buf.size())
+ {
+ // The error formatted string didn't fit into our buffer, resize it
+ // to the exact needed size, and retry
+ buf.resize(length + 1);
+ length = ::vsnprintf (buf.data(), buf.size(), format, copy_args);
+ va_end (copy_args);
+ assert (length < buf.size());
+ }
+ m_string.assign(buf.data(), length);
+ va_end (args);
+ return length;
+ }
+ else
+ {
+ m_string.clear();
+ }
+ return 0;
+}
+
+
+//----------------------------------------------------------------------
+// Returns true if the error code in this object is considered a
+// successful return value.
+//----------------------------------------------------------------------
+bool
+Error::Success() const
+{
+ return m_code == 0;
+}
+
+bool
+Error::WasInterrupted() const
+{
+ if (m_type == eErrorTypePOSIX && m_code == EINTR)
+ return true;
+ else
+ return false;
+}
+
diff --git a/source/Core/Event.cpp b/source/Core/Event.cpp
new file mode 100644
index 0000000..2d4899d
--- /dev/null
+++ b/source/Core/Event.cpp
@@ -0,0 +1,225 @@
+//===-- Event.cpp -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Event.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Target/Process.h"
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Event constructor
+//----------------------------------------------------------------------
+Event::Event (Broadcaster *broadcaster, uint32_t event_type, EventData *data) :
+ m_broadcaster (broadcaster),
+ m_type (event_type),
+ m_data_ap (data)
+{
+}
+
+Event::Event(uint32_t event_type, EventData *data) :
+ m_broadcaster (NULL), // Set by the broadcaster when this event gets broadcast
+ m_type (event_type),
+ m_data_ap (data)
+{
+}
+
+
+//----------------------------------------------------------------------
+// Event destructor
+//----------------------------------------------------------------------
+Event::~Event ()
+{
+}
+
+void
+Event::Dump (Stream *s) const
+{
+ if (m_broadcaster)
+ {
+ StreamString event_name;
+ if (m_broadcaster->GetEventNames (event_name, m_type, false))
+ s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x (%s), data = ",
+ this,
+ m_broadcaster,
+ m_broadcaster->GetBroadcasterName().GetCString(),
+ m_type,
+ event_name.GetString().c_str());
+ else
+ s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x, data = ",
+ this,
+ m_broadcaster,
+ m_broadcaster->GetBroadcasterName().GetCString(),
+ m_type);
+ }
+ else
+ s->Printf("%p Event: broadcaster = NULL, type = 0x%8.8x, data = ", this, m_type);
+
+ if (m_data_ap.get() == NULL)
+ s->Printf ("<NULL>");
+ else
+ {
+ s->PutChar('{');
+ m_data_ap->Dump (s);
+ s->PutChar('}');
+ }
+}
+
+void
+Event::DoOnRemoval ()
+{
+ if (m_data_ap.get())
+ m_data_ap->DoOnRemoval (this);
+}
+
+EventData::EventData()
+{
+}
+
+EventData::~EventData()
+{
+}
+
+void
+EventData::Dump (Stream *s) const
+{
+ s->PutCString ("Generic Event Data");
+}
+
+EventDataBytes::EventDataBytes () :
+ m_bytes()
+{
+}
+
+EventDataBytes::EventDataBytes (const char *cstr) :
+ m_bytes()
+{
+ SetBytesFromCString (cstr);
+}
+
+EventDataBytes::EventDataBytes (const void *src, size_t src_len) :
+ m_bytes()
+{
+ SetBytes (src, src_len);
+}
+
+EventDataBytes::~EventDataBytes()
+{
+}
+
+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.size() > 0)
+ {
+ DataExtractor data;
+ data.SetData(&m_bytes[0], m_bytes.size(), lldb::endian::InlHostByteOrder());
+ data.Dump(s, 0, eFormatBytes, 1, m_bytes.size(), 32, LLDB_INVALID_ADDRESS, 0, 0);
+ }
+}
+
+const void *
+EventDataBytes::GetBytes() const
+{
+ if (m_bytes.empty())
+ return NULL;
+ return &m_bytes[0];
+}
+
+size_t
+EventDataBytes::GetByteSize() const
+{
+ return m_bytes.size ();
+}
+
+void
+EventDataBytes::SetBytes (const void *src, size_t src_len)
+{
+ if (src && src_len > 0)
+ m_bytes.assign ((const char *)src, src_len);
+ else
+ m_bytes.clear();
+}
+
+void
+EventDataBytes::SetBytesFromCString (const char *cstr)
+{
+ if (cstr && 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)
+ return e->GetBytes();
+ return NULL;
+}
+
+size_t
+EventDataBytes::GetByteSizeFromEvent (const Event *event_ptr)
+{
+ const EventDataBytes *e = GetEventDataFromEvent (event_ptr);
+ if (e)
+ return e->GetByteSize();
+ return 0;
+}
+
+const EventDataBytes *
+EventDataBytes::GetEventDataFromEvent (const Event *event_ptr)
+{
+ if (event_ptr)
+ {
+ const EventData *event_data = event_ptr->GetData();
+ if (event_data && event_data->GetFlavor() == EventDataBytes::GetFlavorString())
+ return static_cast <const EventDataBytes *> (event_data);
+ }
+ return NULL;
+}
+
+void
+EventDataBytes::SwapBytes (std::string &new_bytes)
+{
+ m_bytes.swap (new_bytes);
+}
+
+
diff --git a/source/Core/FileLineResolver.cpp b/source/Core/FileLineResolver.cpp
new file mode 100644
index 0000000..15cbbe6
--- /dev/null
+++ b/source/Core/FileLineResolver.cpp
@@ -0,0 +1,117 @@
+//===-- 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/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+
+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, 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;
+}
+
diff --git a/source/Core/FileSpecList.cpp b/source/Core/FileSpecList.cpp
new file mode 100644
index 0000000..0cec8fa
--- /dev/null
+++ b/source/Core/FileSpecList.cpp
@@ -0,0 +1,234 @@
+//===-- 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/Core/Stream.h"
+#include <algorithm>
+
+using namespace lldb_private;
+using namespace std;
+
+//------------------------------------------------------------------
+// Default constructor
+//------------------------------------------------------------------
+FileSpecList::FileSpecList() :
+ m_files()
+{
+}
+
+//------------------------------------------------------------------
+// Copy constructor
+//------------------------------------------------------------------
+FileSpecList::FileSpecList(const FileSpecList& rhs) :
+ m_files(rhs.m_files)
+{
+}
+
+//------------------------------------------------------------------
+// Destructor
+//------------------------------------------------------------------
+FileSpecList::~FileSpecList()
+{
+}
+
+//------------------------------------------------------------------
+// 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 pos, 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 UINT32_MAX is returned.
+//------------------------------------------------------------------
+size_t
+FileSpecList::FindFileIndex (size_t start_idx, const FileSpec &file_spec, bool full) 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 (m_files[idx].GetFilename() == file_spec.GetFilename())
+ return idx;
+ }
+ else
+ {
+ if (FileSpec::Equal (m_files[idx], file_spec, full))
+ 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 NULL;
+}
+
+//------------------------------------------------------------------
+// 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)
+{
+#if 0 // FIXME: Just sketching...
+ matches.Clear();
+ FileSpec path_spec = FileSpec (path);
+ if (path_spec.Exists ())
+ {
+ FileSpec::FileType type = path_spec.GetFileType();
+ if (type == FileSpec::eFileTypeSymbolicLink)
+ // Shouldn't there be a Resolve on a file spec that real-path's it?
+ {
+ }
+
+ if (type == FileSpec::eFileTypeRegular
+ || (type == FileSpec::eFileTypeDirectory && dir_okay))
+ {
+ matches.Append (path_spec);
+ return 1;
+ }
+ else if (type == FileSpec::eFileTypeDirectory)
+ {
+ // Fill the match list with all the files in the directory:
+
+ }
+ else
+ {
+ return 0;
+ }
+
+ }
+ else
+ {
+ ConstString dir_name = path_spec.GetDirectory();
+ Constring file_name = GetFilename();
+ if (dir_name == NULL)
+ {
+ // Match files in the CWD.
+ }
+ else
+ {
+ // Match files in the given directory:
+
+ }
+ }
+#endif
+ return 0;
+}
diff --git a/source/Core/History.cpp b/source/Core/History.cpp
new file mode 100644
index 0000000..0105dce
--- /dev/null
+++ b/source/Core/History.cpp
@@ -0,0 +1,26 @@
+//===-- History.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/History.h"
+
+// C Includes
+#include <inttypes.h>
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+HistorySourceUInt::DumpHistoryEvent (Stream &strm, HistoryEvent event)
+{
+ strm.Printf ("%s %" PRIu64, m_name.c_str(), (uint64_t)((uintptr_t)event));
+}
diff --git a/source/Core/InputReader.cpp b/source/Core/InputReader.cpp
new file mode 100644
index 0000000..cbaa671
--- /dev/null
+++ b/source/Core/InputReader.cpp
@@ -0,0 +1,387 @@
+//===-- InputReader.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/lldb-python.h"
+
+#include <string>
+
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+InputReader::InputReader (Debugger &debugger) :
+ m_debugger (debugger),
+ m_callback (NULL),
+ m_callback_baton (NULL),
+ m_end_token (),
+ m_granularity (eInputReaderGranularityInvalid),
+ m_done (true),
+ m_echo (true),
+ m_active (false),
+ m_reader_done (false),
+ m_user_input(),
+ m_save_user_input(false)
+{
+}
+
+InputReader::~InputReader ()
+{
+}
+
+Error
+InputReader::Initialize
+(
+ Callback callback,
+ void *baton,
+ lldb::InputReaderGranularity granularity,
+ const char *end_token,
+ const char *prompt,
+ bool echo
+)
+{
+ Error err;
+ m_callback = callback;
+ m_callback_baton = baton,
+ m_granularity = granularity;
+ if (end_token != NULL)
+ m_end_token = end_token;
+ if (prompt != NULL)
+ m_prompt = prompt;
+ m_done = true;
+ m_echo = echo;
+
+ if (m_granularity == eInputReaderGranularityInvalid)
+ {
+ err.SetErrorString ("Invalid read token size: Reader must be initialized with a token size other than 'eInputReaderGranularityInvalid'.");
+ }
+ else
+ if (end_token != NULL && granularity != eInputReaderGranularityInvalid)
+ {
+ if (granularity == eInputReaderGranularityByte)
+ {
+ // Check to see if end_token is longer than one byte.
+
+ if (strlen (end_token) > 1)
+ {
+ err.SetErrorString ("Invalid end token: End token cannot be larger than specified token size (byte).");
+ }
+ }
+ else if (granularity == eInputReaderGranularityWord)
+ {
+ // Check to see if m_end_token contains any white space (i.e. is multiple words).
+
+ const char *white_space = " \t\n";
+ size_t pos = m_end_token.find_first_of (white_space);
+ if (pos != std::string::npos)
+ {
+ err.SetErrorString ("Invalid end token: End token cannot be larger than specified token size (word).");
+ }
+ }
+ else
+ {
+ // Check to see if m_end_token contains any newlines; cannot handle multi-line end tokens.
+
+ size_t pos = m_end_token.find_first_of ('\n');
+ if (pos != std::string::npos)
+ {
+ err.SetErrorString ("Invalid end token: End token cannot contain a newline.");
+ }
+ }
+ }
+
+ m_done = err.Fail();
+
+ return err;
+}
+
+size_t
+InputReader::HandleRawBytes (const char *bytes, size_t bytes_len)
+{
+ const char *end_token = NULL;
+
+ if (m_end_token.empty() == false)
+ {
+ end_token = ::strstr (bytes, m_end_token.c_str());
+ if (end_token >= bytes + bytes_len)
+ end_token = NULL;
+ }
+
+ const char *p = bytes;
+ const char *end = bytes + bytes_len;
+
+ switch (m_granularity)
+ {
+ case eInputReaderGranularityInvalid:
+ break;
+
+ case eInputReaderGranularityByte:
+ while (p < end)
+ {
+ if (end_token == p)
+ {
+ p += m_end_token.size();
+ SetIsDone(true);
+ break;
+ }
+
+ if (m_callback (m_callback_baton, *this, eInputReaderGotToken, p, 1) == 0)
+ break;
+ ++p;
+ if (IsDone())
+ break;
+ }
+ // Return how many bytes were handled.
+ return p - bytes;
+ break;
+
+
+ case eInputReaderGranularityWord:
+ {
+ char quote = '\0';
+ const char *word_start = NULL;
+ bool send_word = false;
+ for (; p < end; ++p, send_word = false)
+ {
+ if (end_token && end_token == p)
+ {
+ m_end_token.size();
+ SetIsDone(true);
+ break;
+ }
+
+ const char ch = *p;
+ if (isspace(ch) && (!quote || (quote == ch && p[-1] != '\\')))
+ {
+ // We have a space character or the terminating quote
+ send_word = word_start != NULL;
+ quote = '\0';
+ }
+ else if (quote)
+ {
+ // We are in the middle of a quoted character
+ continue;
+ }
+ else if (ch == '"' || ch == '\'' || ch == '`')
+ quote = ch;
+ else if (word_start == NULL)
+ {
+ // We have the first character in a word
+ word_start = p;
+ }
+
+ if (send_word)
+ {
+ const size_t word_len = p - word_start;
+ size_t bytes_handled = m_callback (m_callback_baton,
+ *this,
+ eInputReaderGotToken,
+ word_start,
+ word_len);
+
+ if (bytes_handled != word_len)
+ return word_start - bytes + bytes_handled;
+
+ if (IsDone())
+ return p - bytes;
+ }
+ }
+ }
+ break;
+
+
+ case eInputReaderGranularityLine:
+ {
+ const char *line_start = bytes;
+ const char *end_line = NULL;
+ while (p < end)
+ {
+ const char ch = *p;
+ if (ch == '\n' || ch == '\r')
+ {
+ size_t line_length = p - line_start;
+ // Now skip the newline character
+ ++p;
+ // Skip a complete DOS newline if we run into one
+ if (ch == 0xd && p < end && *p == 0xa)
+ ++p;
+
+ if (line_start <= end_token && end_token < line_start + line_length)
+ {
+ SetIsDone(true);
+ m_callback (m_callback_baton,
+ *this,
+ eInputReaderGotToken,
+ line_start,
+ end_token - line_start);
+
+ return p - bytes;
+ }
+
+ size_t bytes_handled = m_callback (m_callback_baton,
+ *this,
+ eInputReaderGotToken,
+ line_start,
+ line_length);
+
+ end_line = p;
+
+ if (bytes_handled != line_length)
+ {
+ // The input reader wasn't able to handle all the data
+ return line_start - bytes + bytes_handled;
+ }
+
+
+ if (IsDone())
+ return p - bytes;
+
+ line_start = p;
+ }
+ else
+ {
+ ++p;
+ }
+ }
+
+ if (end_line)
+ return end_line - bytes;
+ }
+ break;
+
+
+ case eInputReaderGranularityAll:
+ {
+ // Nothing should be handle unless we see our end token
+ if (end_token)
+ {
+ size_t length = end_token - bytes;
+ size_t bytes_handled = m_callback (m_callback_baton,
+ *this,
+ eInputReaderGotToken,
+ bytes,
+ length);
+ m_done = true;
+
+ p += bytes_handled + m_end_token.size();
+
+ // Consume any white space, such as newlines, beyond the end token
+
+ while (p < end && isspace(*p))
+ ++p;
+
+ if (bytes_handled != length)
+ return bytes_handled;
+ else
+ {
+ return p - bytes;
+ //return bytes_handled + m_end_token.size();
+ }
+ }
+ return 0;
+ }
+ break;
+ }
+ return 0;
+}
+
+const char *
+InputReader::GetPrompt () const
+{
+ if (!m_prompt.empty())
+ return m_prompt.c_str();
+ else
+ return NULL;
+}
+
+void
+InputReader::RefreshPrompt ()
+{
+ if (m_debugger.GetCommandInterpreter().GetBatchCommandMode())
+ return;
+
+ if (!m_prompt.empty())
+ {
+ File &out_file = m_debugger.GetOutputFile();
+ if (out_file.IsValid())
+ {
+ out_file.Printf ("%s", m_prompt.c_str());
+ out_file.Flush();
+ }
+ }
+}
+
+void
+InputReader::Notify (InputReaderAction notification)
+{
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ case eInputReaderReactivate:
+ m_active = true;
+ m_reader_done.SetValue(false, eBroadcastAlways);
+ break;
+
+ case eInputReaderDeactivate:
+ case eInputReaderDone:
+ m_active = false;
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderInterrupt:
+ case eInputReaderEndOfFile:
+ break;
+
+ case eInputReaderGotToken:
+ return; // We don't notify the tokens here, it is done in HandleRawBytes
+ }
+ if (m_callback)
+ m_callback (m_callback_baton, *this, notification, NULL, 0);
+ if (notification == eInputReaderDone)
+ m_reader_done.SetValue(true, eBroadcastAlways);
+}
+
+void
+InputReader::WaitOnReaderIsDone ()
+{
+ m_reader_done.WaitForValueEqualTo (true);
+}
+
+const char *
+InputReader::GranularityAsCString (lldb::InputReaderGranularity granularity)
+{
+ switch (granularity)
+ {
+ case eInputReaderGranularityInvalid: return "invalid";
+ case eInputReaderGranularityByte: return "byte";
+ case eInputReaderGranularityWord: return "word";
+ case eInputReaderGranularityLine: return "line";
+ case eInputReaderGranularityAll: return "all";
+ }
+
+ static char unknown_state_string[64];
+ snprintf(unknown_state_string, sizeof (unknown_state_string), "InputReaderGranularity = %i", granularity);
+ return unknown_state_string;
+}
+
+bool
+InputReader::HandlerData::GetBatchMode()
+{
+ return reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+}
+
+lldb::StreamSP
+InputReader::HandlerData::GetOutStream()
+{
+ return reader.GetDebugger().GetAsyncOutputStream();
+}
diff --git a/source/Core/InputReaderEZ.cpp b/source/Core/InputReaderEZ.cpp
new file mode 100644
index 0000000..7a865bd
--- /dev/null
+++ b/source/Core/InputReaderEZ.cpp
@@ -0,0 +1,91 @@
+//===-- InputReaderEZ.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/InputReaderEZ.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+size_t
+InputReaderEZ::Callback_Impl(void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len)
+
+{
+ HandlerData hand_data(reader,
+ bytes,
+ bytes_len,
+ baton);
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ reader.ActivateHandler(hand_data);
+ break;
+ case eInputReaderDeactivate:
+ reader.DeactivateHandler(hand_data);
+ break;
+ case eInputReaderReactivate:
+ reader.ReactivateHandler(hand_data);
+ break;
+ case eInputReaderAsynchronousOutputWritten:
+ reader.AsynchronousOutputWrittenHandler(hand_data);
+ break;
+ case eInputReaderGotToken:
+ {
+ if (reader.GetSaveUserInput())
+ reader.GetUserInput().AppendString(bytes, bytes_len);
+ reader.GotTokenHandler(hand_data);
+ }
+ break;
+ case eInputReaderInterrupt:
+ reader.InterruptHandler(hand_data);
+ break;
+ case eInputReaderEndOfFile:
+ reader.EOFHandler(hand_data);
+ break;
+ case eInputReaderDone:
+ reader.DoneHandler(hand_data);
+ break;
+ }
+ return bytes_len;
+}
+
+Error
+InputReaderEZ::Initialize(void* baton,
+ lldb::InputReaderGranularity token_size,
+ const char* end_token,
+ const char *prompt,
+ bool echo)
+{
+ return InputReader::Initialize(Callback_Impl,
+ baton,
+ token_size,
+ end_token,
+ prompt,
+ echo);
+}
+
+Error
+InputReaderEZ::Initialize(InitializationParameters& params)
+{
+ Error ret = Initialize(params.m_baton,
+ params.m_token_size,
+ params.m_end_token,
+ params.m_prompt,
+ params.m_echo);
+ m_save_user_input = params.m_save_user_input;
+ return ret;
+}
+
+InputReaderEZ::~InputReaderEZ ()
+{
+}
diff --git a/source/Core/InputReaderStack.cpp b/source/Core/InputReaderStack.cpp
new file mode 100644
index 0000000..764ea26
--- /dev/null
+++ b/source/Core/InputReaderStack.cpp
@@ -0,0 +1,80 @@
+//===-- InputReaderStack.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/InputReaderStack.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+InputReaderStack::InputReaderStack () :
+ m_input_readers (),
+ m_input_readers_mutex (Mutex::eMutexTypeRecursive)
+{
+}
+
+InputReaderStack::~InputReaderStack ()
+{
+}
+
+size_t
+InputReaderStack::GetSize () const
+{
+ Mutex::Locker locker (m_input_readers_mutex);
+ return m_input_readers.size();
+}
+
+void
+InputReaderStack::Push (const lldb::InputReaderSP& reader_sp)
+{
+ if (reader_sp)
+ {
+ Mutex::Locker locker (m_input_readers_mutex);
+ m_input_readers.push (reader_sp);
+ }
+}
+
+bool
+InputReaderStack::IsEmpty () const
+{
+ Mutex::Locker locker (m_input_readers_mutex);
+ return m_input_readers.empty();
+}
+
+InputReaderSP
+InputReaderStack::Top ()
+{
+ InputReaderSP input_reader_sp;
+ {
+ Mutex::Locker locker (m_input_readers_mutex);
+ if (!m_input_readers.empty())
+ input_reader_sp = m_input_readers.top();
+ }
+
+ return input_reader_sp;
+}
+
+void
+InputReaderStack::Pop ()
+{
+ Mutex::Locker locker (m_input_readers_mutex);
+ if (!m_input_readers.empty())
+ m_input_readers.pop();
+}
+
+Mutex &
+InputReaderStack::GetStackMutex ()
+{
+ return m_input_readers_mutex;
+}
diff --git a/source/Core/Language.cpp b/source/Core/Language.cpp
new file mode 100644
index 0000000..af62af3
--- /dev/null
+++ b/source/Core/Language.cpp
@@ -0,0 +1,151 @@
+//===-- Language.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/lldb-private.h"
+#include "lldb/Core/Language.h"
+#include "lldb/Core/Stream.h"
+#include <string.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define ENUM_TO_DCSTREAM(x) case x: s->PutCString(#x); return
+
+struct LanguageStrings
+{
+ const char * names[3];
+};
+
+static LanguageStrings
+g_languages[] =
+{
+ { { "unknown" , NULL , NULL } },
+ { { "c89" , NULL , "ISO C:1989" } },
+ { { NULL , NULL , "K&R C" } },
+ { { "ada83" , "Ada83" , "ISO Ada:1983" } },
+ { { "c++" , "cxx" , "ISO C++:1998" } },
+ { { "cobol74" , "Cobol74" , "ISO Cobol:1974" } },
+ { { "cobol" , "Cobol85" , "ISO Cobol:1985." } },
+ { { "f77" , "Fortran77" , "ISO Fortran 77." } },
+ { { "f90" , "Fortran90" , "ISO Fortran 90" } },
+ { { "pascal" , "Pascal83" , "ISO Pascal:1983" } },
+ { { "modula2" , "Modula2" , "ISO Modula-2:1996" } },
+ { { "java" , NULL , "Java" } },
+ { { "c" , "C99" , "ISO C:1999" } },
+ { { "ada" , "Ada95" , "ISO Ada:1995" } },
+ { { "f95" , "Fortran95" , "ISO Fortran 95" } },
+ { { "PLI" , NULL , "ANSI PL/I:1976" } },
+ { { "objc" , NULL , "Objective-C" } },
+ { { "objc++" , NULL , "Objective-C++" } },
+ { { "upc" , NULL , "Unified Parallel C" } },
+ { { "d" , NULL , "D" } },
+ { { "python" , NULL , "Python" } }
+};
+
+static const size_t
+g_num_languages = sizeof(g_languages)/sizeof(LanguageStrings);
+
+Language::Language(LanguageType language) :
+ m_language (language)
+{
+}
+
+Language::~Language()
+{
+}
+
+LanguageType
+Language::GetLanguage() const
+{
+ return m_language;
+}
+
+void
+Language::Clear ()
+{
+ m_language = eLanguageTypeUnknown;
+}
+
+void
+Language::SetLanguage(LanguageType language)
+{
+ m_language = language;
+}
+
+bool
+Language::SetLanguageFromCString(const char *language_cstr)
+{
+ size_t i, desc_idx;
+ const char *name;
+
+ // First check the most common name for the languages
+ for (desc_idx=lldb::eDescriptionLevelBrief; desc_idx<kNumDescriptionLevels; ++desc_idx)
+ {
+ for (i=0; i<g_num_languages; ++i)
+ {
+ name = g_languages[i].names[desc_idx];
+ if (name == NULL)
+ continue;
+
+ if (::strcasecmp (language_cstr, name) == 0)
+ {
+ m_language = (LanguageType)i;
+ return true;
+ }
+ }
+ }
+
+ m_language = eLanguageTypeUnknown;
+ return false;
+}
+
+
+const char *
+Language::AsCString (lldb::DescriptionLevel level) const
+{
+ if (m_language < g_num_languages && level < kNumDescriptionLevels)
+ {
+ const char *name = g_languages[m_language].names[level];
+ if (name)
+ return name;
+ else if (level + 1 < kNumDescriptionLevels)
+ return AsCString ((lldb::DescriptionLevel)(level + 1));
+ else
+ return NULL;
+ }
+ return NULL;
+}
+
+void
+Language::Dump(Stream *s) const
+{
+ GetDescription(s, lldb::eDescriptionLevelVerbose);
+}
+
+void
+Language::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+ const char *lang_cstr = AsCString(level);
+
+ if (lang_cstr)
+ s->PutCString(lang_cstr);
+ else
+ s->Printf("Language(language = 0x%4.4x)", m_language);
+}
+
+
+
+
+Stream&
+lldb_private::operator << (Stream& s, const Language& language)
+{
+ language.Dump(&s);
+ return s;
+}
+
diff --git a/source/Core/Listener.cpp b/source/Core/Listener.cpp
new file mode 100644
index 0000000..aca2b37
--- /dev/null
+++ b/source/Core/Listener.cpp
@@ -0,0 +1,557 @@
+//===-- 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"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/lldb-private-log.h"
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+
+Listener::Listener(const char *name) :
+ m_name (name),
+ m_broadcasters(),
+ m_broadcasters_mutex (Mutex::eMutexTypeRecursive),
+ m_events (),
+ m_events_mutex (Mutex::eMutexTypeRecursive),
+ m_cond_wait()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Listener::Listener('%s')", this, m_name.c_str());
+}
+
+Listener::~Listener()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ Mutex::Locker locker (m_broadcasters_mutex);
+
+ size_t num_managers = m_broadcaster_managers.size();
+
+ for (size_t i = 0; i < num_managers; i++)
+ m_broadcaster_managers[i]->RemoveListener(*this);
+
+ if (log)
+ log->Printf ("%p Listener::~Listener('%s')", this, m_name.c_str());
+ Clear();
+}
+
+void
+Listener::Clear()
+{
+ Mutex::Locker locker(m_broadcasters_mutex);
+ broadcaster_collection::iterator pos, end = m_broadcasters.end();
+ for (pos = m_broadcasters.begin(); pos != end; ++pos)
+ pos->first->RemoveListener (this, pos->second.event_mask);
+ m_broadcasters.clear();
+ m_cond_wait.SetValue (false, eBroadcastNever);
+ m_broadcasters.clear();
+ Mutex::Locker event_locker(m_events_mutex);
+ m_events.clear();
+}
+
+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
+ {
+ Mutex::Locker locker(m_broadcasters_mutex);
+ m_broadcasters.insert(std::make_pair(broadcaster, BroadcasterInfo(event_mask)));
+ }
+
+ uint32_t acquired_mask = broadcaster->AddListener (this, event_mask);
+
+ if (event_mask != acquired_mask)
+ {
+
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS));
+ if (log)
+ log->Printf ("%p Listener::StartListeningForEvents (broadcaster = %p, mask = 0x%8.8x) acquired_mask = 0x%8.8x for %s",
+ this,
+ 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
+ {
+ Mutex::Locker locker(m_broadcasters_mutex);
+ m_broadcasters.insert(std::make_pair(broadcaster, BroadcasterInfo(event_mask, callback, callback_user_data)));
+ }
+
+ uint32_t acquired_mask = broadcaster->AddListener (this, event_mask);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS));
+ if (log)
+ log->Printf ("%p Listener::StartListeningForEvents (broadcaster = %p, mask = 0x%8.8x, callback = %p, user_data = %p) acquired_mask = 0x%8.8x for %s",
+ this, broadcaster, event_mask, callback, 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"
+ {
+ Mutex::Locker locker(m_broadcasters_mutex);
+ m_broadcasters.erase (broadcaster);
+ }
+ // Remove the broadcaster from our set of broadcasters
+ return broadcaster->RemoveListener (this, event_mask);
+ }
+
+ return false;
+}
+
+// Called when a Broadcaster is in its destuctor. 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"
+ {
+ Mutex::Locker broadcasters_locker(m_broadcasters_mutex);
+ m_broadcasters.erase (broadcaster);
+ }
+
+ // Scope for "event_locker"
+ {
+ Mutex::Locker event_locker(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;
+ }
+
+ if (m_events.empty())
+ m_cond_wait.SetValue (false, eBroadcastNever);
+
+ }
+}
+
+void
+Listener::BroadcasterManagerWillDestruct (BroadcasterManager *manager)
+{
+ // Just need to remove this broadcast manager from the list of managers:
+ broadcaster_manager_collection::iterator iter, end_iter = m_broadcaster_managers.end();
+ iter = find(m_broadcaster_managers.begin(), end_iter, manager);
+ 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)
+ log->Printf ("%p Listener('%s')::AddEvent (event_sp = {%p})", this, m_name.c_str(), event_sp.get());
+
+ // Scope for "locker"
+ {
+ Mutex::Locker locker(m_events_mutex);
+ m_events.push_back (event_sp);
+ }
+ m_cond_wait.SetValue (true, eBroadcastAlways);
+}
+
+class EventBroadcasterMatches
+{
+public:
+ EventBroadcasterMatches (Broadcaster *broadcaster) :
+ m_broadcaster (broadcaster) {
+ }
+
+ bool operator() (const EventSP &event_sp) const
+ {
+ if (event_sp->BroadcasterIs(m_broadcaster))
+ return true;
+ else
+ return false;
+ }
+
+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
+(
+ Broadcaster *broadcaster, // NULL for any broadcaster
+ const ConstString *broadcaster_names, // NULL for any event
+ uint32_t num_broadcaster_names,
+ uint32_t event_type_mask,
+ EventSP &event_sp,
+ bool remove)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS));
+
+ Mutex::Locker lock(m_events_mutex);
+
+ if (m_events.empty())
+ return false;
+
+
+ Listener::event_collection::iterator pos = m_events.end();
+
+ if (broadcaster == NULL && broadcaster_names == NULL && 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)
+ log->Printf ("%p '%s' Listener::FindNextEventInternal(broadcaster=%p, broadcaster_names=%p[%u], event_type_mask=0x%8.8x, remove=%i) event %p",
+ this,
+ GetName(),
+ broadcaster,
+ broadcaster_names,
+ num_broadcaster_names,
+ event_type_mask,
+ remove,
+ event_sp.get());
+
+ if (remove)
+ {
+ m_events.erase(pos);
+
+ if (m_events.empty())
+ m_cond_wait.SetValue (false, eBroadcastNever);
+ }
+
+ // 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();
+
+ // Don't call DoOnRemoval if you aren't removing the event...
+ if (remove)
+ event_sp->DoOnRemoval();
+
+ return true;
+ }
+
+ event_sp.reset();
+ return false;
+}
+
+Event *
+Listener::PeekAtNextEvent ()
+{
+ EventSP event_sp;
+ if (FindNextEventInternal (NULL, NULL, 0, 0, event_sp, false))
+ return event_sp.get();
+ return NULL;
+}
+
+Event *
+Listener::PeekAtNextEventForBroadcaster (Broadcaster *broadcaster)
+{
+ EventSP event_sp;
+ if (FindNextEventInternal (broadcaster, NULL, 0, 0, event_sp, false))
+ return event_sp.get();
+ return NULL;
+}
+
+Event *
+Listener::PeekAtNextEventForBroadcasterWithType (Broadcaster *broadcaster, uint32_t event_type_mask)
+{
+ EventSP event_sp;
+ if (FindNextEventInternal (broadcaster, NULL, 0, event_type_mask, event_sp, false))
+ return event_sp.get();
+ return NULL;
+}
+
+
+bool
+Listener::GetNextEventInternal
+(
+ Broadcaster *broadcaster, // NULL for any broadcaster
+ const ConstString *broadcaster_names, // NULL for any event
+ uint32_t num_broadcaster_names,
+ uint32_t event_type_mask,
+ EventSP &event_sp
+)
+{
+ return FindNextEventInternal (broadcaster, broadcaster_names, num_broadcaster_names, event_type_mask, event_sp, true);
+}
+
+bool
+Listener::GetNextEvent (EventSP &event_sp)
+{
+ return GetNextEventInternal (NULL, NULL, 0, 0, event_sp);
+}
+
+
+bool
+Listener::GetNextEventForBroadcaster (Broadcaster *broadcaster, EventSP &event_sp)
+{
+ return GetNextEventInternal (broadcaster, NULL, 0, 0, event_sp);
+}
+
+bool
+Listener::GetNextEventForBroadcasterWithType (Broadcaster *broadcaster, uint32_t event_type_mask, EventSP &event_sp)
+{
+ return GetNextEventInternal (broadcaster, NULL, 0, event_type_mask, event_sp);
+}
+
+
+bool
+Listener::WaitForEventsInternal
+(
+ const TimeValue *timeout,
+ Broadcaster *broadcaster, // NULL for any broadcaster
+ const ConstString *broadcaster_names, // NULL for any event
+ uint32_t num_broadcaster_names,
+ uint32_t event_type_mask,
+ EventSP &event_sp
+)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS));
+ bool timed_out = false;
+
+ if (log)
+ {
+ log->Printf ("%p Listener::WaitForEventsInternal (timeout = { %p }) for %s",
+ this, timeout, m_name.c_str());
+ }
+
+ while (1)
+ {
+ // Note, we don't want to lock the m_events_mutex in the call to GetNextEventInternal, since the DoOnRemoval
+ // code might require that new events be serviced. For instance, the Breakpoint Command's
+ if (GetNextEventInternal (broadcaster, broadcaster_names, num_broadcaster_names, event_type_mask, event_sp))
+ return true;
+
+ {
+ // Reset condition value to false, so we can wait for new events to be
+ // added that might meet our current filter
+ // But first poll for any new event that might satisfy our condition, and if so consume it,
+ // otherwise wait.
+
+ Mutex::Locker event_locker(m_events_mutex);
+ const bool remove = false;
+ if (FindNextEventInternal (broadcaster, broadcaster_names, num_broadcaster_names, event_type_mask, event_sp, remove))
+ continue;
+ else
+ m_cond_wait.SetValue (false, eBroadcastNever);
+ }
+
+ if (m_cond_wait.WaitForValueEqualTo (true, timeout, &timed_out))
+ continue;
+
+ else if (timed_out)
+ {
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS);
+ if (log)
+ log->Printf ("%p Listener::WaitForEventsInternal() timed out for %s", this, m_name.c_str());
+ break;
+ }
+ else
+ {
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS);
+ if (log)
+ log->Printf ("%p Listener::WaitForEventsInternal() unknown error for %s", this, m_name.c_str());
+ break;
+ }
+ }
+
+ return false;
+}
+
+bool
+Listener::WaitForEventForBroadcasterWithType
+(
+ const TimeValue *timeout,
+ Broadcaster *broadcaster,
+ uint32_t event_type_mask,
+ EventSP &event_sp
+)
+{
+ return WaitForEventsInternal (timeout, broadcaster, NULL, 0, event_type_mask, event_sp);
+}
+
+bool
+Listener::WaitForEventForBroadcaster
+(
+ const TimeValue *timeout,
+ Broadcaster *broadcaster,
+ EventSP &event_sp
+)
+{
+ return WaitForEventsInternal (timeout, broadcaster, NULL, 0, 0, event_sp);
+}
+
+bool
+Listener::WaitForEvent (const TimeValue *timeout, EventSP &event_sp)
+{
+ return WaitForEventsInternal (timeout, NULL, NULL, 0, 0, event_sp);
+}
+
+//Listener::broadcaster_collection::iterator
+//Listener::FindBroadcasterWithMask (Broadcaster *broadcaster, uint32_t event_mask, bool exact)
+//{
+// broadcaster_collection::iterator pos;
+// broadcaster_collection::iterator end = m_broadcasters.end();
+// for (pos = m_broadcasters.find (broadcaster);
+// pos != end && pos->first == broadcaster;
+// ++pos)
+// {
+// if (exact)
+// {
+// if ((event_mask & pos->second.event_mask) == event_mask)
+// return pos;
+// }
+// else
+// {
+// if (event_mask & pos->second.event_mask)
+// return pos;
+// }
+// }
+// return end;
+//}
+
+size_t
+Listener::HandleBroadcastEvent (EventSP &event_sp)
+{
+ size_t num_handled = 0;
+ Mutex::Locker locker(m_broadcasters_mutex);
+ Broadcaster *broadcaster = event_sp->GetBroadcaster();
+ broadcaster_collection::iterator pos;
+ broadcaster_collection::iterator end = m_broadcasters.end();
+ for (pos = m_broadcasters.find (broadcaster);
+ pos != end && pos->first == broadcaster;
+ ++pos)
+ {
+ BroadcasterInfo info = pos->second;
+ if (event_sp->GetType () & info.event_mask)
+ {
+ if (info.callback != NULL)
+ {
+ info.callback (event_sp, info.callback_user_data);
+ ++num_handled;
+ }
+ }
+ }
+ return num_handled;
+}
+
+uint32_t
+Listener::StartListeningForEventSpec (BroadcasterManager &manager,
+ const BroadcastEventSpec &event_spec)
+{
+ // The BroadcasterManager mutex must be locked before m_broadcasters_mutex
+ // to avoid violating the lock hierarchy (manager before broadcasters).
+ Mutex::Locker manager_locker(manager.m_manager_mutex);
+ Mutex::Locker locker(m_broadcasters_mutex);
+
+ uint32_t bits_acquired = manager.RegisterListenerForEvents(*this, event_spec);
+ if (bits_acquired)
+ m_broadcaster_managers.push_back(&manager);
+
+ return bits_acquired;
+}
+
+bool
+Listener::StopListeningForEventSpec (BroadcasterManager &manager,
+ const BroadcastEventSpec &event_spec)
+{
+ Mutex::Locker locker(m_broadcasters_mutex);
+ return manager.UnregisterListenerForEvents (*this, event_spec);
+
+}
+
+
diff --git a/source/Core/Log.cpp b/source/Core/Log.cpp
new file mode 100644
index 0000000..d73ab15
--- /dev/null
+++ b/source/Core/Log.cpp
@@ -0,0 +1,529 @@
+//===-- Log.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/lldb-python.h"
+
+// C Includes
+#include <pthread.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+// C++ Includes
+#include <map>
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Interpreter/Args.h"
+using namespace lldb;
+using namespace lldb_private;
+
+Log::Log () :
+ m_stream_sp(),
+ m_options(0),
+ m_mask_bits(0)
+{
+}
+
+Log::Log (const StreamSP &stream_sp) :
+ m_stream_sp(stream_sp),
+ m_options(0),
+ m_mask_bits(0)
+{
+}
+
+Log::~Log ()
+{
+}
+
+Flags &
+Log::GetOptions()
+{
+ return m_options;
+}
+
+const Flags &
+Log::GetOptions() const
+{
+ return m_options;
+}
+
+Flags &
+Log::GetMask()
+{
+ return m_mask_bits;
+}
+
+const Flags &
+Log::GetMask() const
+{
+ return m_mask_bits;
+}
+
+
+//----------------------------------------------------------------------
+// All logging eventually boils down to this function call. If we have
+// a callback registered, then we call the logging callback. If we have
+// a valid file handle, we also log to the file.
+//----------------------------------------------------------------------
+void
+Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args)
+{
+ if (m_stream_sp)
+ {
+ static uint32_t g_sequence_id = 0;
+ StreamString header;
+ // Enabling the thread safe logging actually deadlocks right now.
+ // Need to fix this at some point.
+// static Mutex g_LogThreadedMutex(Mutex::eMutexTypeRecursive);
+// Mutex::Locker locker (g_LogThreadedMutex);
+
+ // Add a sequence ID if requested
+ if (m_options.Test (LLDB_LOG_OPTION_PREPEND_SEQUENCE))
+ header.Printf ("%u ", ++g_sequence_id);
+
+ // Timestamp if requested
+ if (m_options.Test (LLDB_LOG_OPTION_PREPEND_TIMESTAMP))
+ {
+ struct timeval tv = TimeValue::Now().GetAsTimeVal();
+ header.Printf ("%9ld.%6.6d ", tv.tv_sec, (int32_t)tv.tv_usec);
+ }
+
+ // Add the process and thread if requested
+ if (m_options.Test (LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD))
+ header.Printf ("[%4.4x/%4.4" PRIx64 "]: ", getpid(), Host::GetCurrentThreadID());
+
+ // Add the process and thread if requested
+ if (m_options.Test (LLDB_LOG_OPTION_PREPEND_THREAD_NAME))
+ {
+ std::string thread_name (Host::GetThreadName (getpid(), Host::GetCurrentThreadID()));
+ if (!thread_name.empty())
+ header.Printf ("%s ", thread_name.c_str());
+ }
+
+ header.PrintfVarArg (format, args);
+ m_stream_sp->Printf("%s\n", header.GetData());
+
+ if (m_options.Test (LLDB_LOG_OPTION_BACKTRACE))
+ Host::Backtrace (*m_stream_sp, 1024);
+ m_stream_sp->Flush();
+ }
+}
+
+
+void
+Log::PutCString (const char *cstr)
+{
+ Printf ("%s", cstr);
+}
+
+
+//----------------------------------------------------------------------
+// Simple variable argument logging with flags.
+//----------------------------------------------------------------------
+void
+Log::Printf(const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ PrintfWithFlagsVarArg (0, format, args);
+ va_end (args);
+}
+
+void
+Log::VAPrintf (const char *format, va_list args)
+{
+ PrintfWithFlagsVarArg (0, format, args);
+}
+
+
+//----------------------------------------------------------------------
+// Simple variable argument logging with flags.
+//----------------------------------------------------------------------
+void
+Log::PrintfWithFlags (uint32_t flags, const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ PrintfWithFlagsVarArg (flags, format, args);
+ va_end (args);
+}
+
+//----------------------------------------------------------------------
+// Print debug strings if and only if the global debug option is set to
+// a non-zero value.
+//----------------------------------------------------------------------
+void
+Log::Debug (const char *format, ...)
+{
+ if (GetOptions().Test(LLDB_LOG_OPTION_DEBUG))
+ {
+ va_list args;
+ va_start (args, format);
+ PrintfWithFlagsVarArg (LLDB_LOG_FLAG_DEBUG, format, args);
+ va_end (args);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Print debug strings if and only if the global debug option is set to
+// a non-zero value.
+//----------------------------------------------------------------------
+void
+Log::DebugVerbose (const char *format, ...)
+{
+ if (GetOptions().AllSet (LLDB_LOG_OPTION_DEBUG | LLDB_LOG_OPTION_VERBOSE))
+ {
+ va_list args;
+ va_start (args, format);
+ PrintfWithFlagsVarArg (LLDB_LOG_FLAG_DEBUG | LLDB_LOG_FLAG_VERBOSE, format, args);
+ va_end (args);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Log only if all of the bits are set
+//----------------------------------------------------------------------
+void
+Log::LogIf (uint32_t bits, const char *format, ...)
+{
+ if (m_options.AllSet (bits))
+ {
+ va_list args;
+ va_start (args, format);
+ PrintfWithFlagsVarArg (0, format, args);
+ va_end (args);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Printing of errors that are not fatal.
+//----------------------------------------------------------------------
+void
+Log::Error (const char *format, ...)
+{
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ PrintfWithFlags (LLDB_LOG_FLAG_ERROR, "error: %s", arg_msg);
+ free (arg_msg);
+ }
+}
+
+//----------------------------------------------------------------------
+// Printing of errors that ARE fatal. Exit with ERR exit code
+// immediately.
+//----------------------------------------------------------------------
+void
+Log::FatalError (int err, const char *format, ...)
+{
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ PrintfWithFlags (LLDB_LOG_FLAG_ERROR | LLDB_LOG_FLAG_FATAL, "error: %s", arg_msg);
+ ::free (arg_msg);
+ }
+ ::exit (err);
+}
+
+
+//----------------------------------------------------------------------
+// Printing of warnings that are not fatal only if verbose mode is
+// enabled.
+//----------------------------------------------------------------------
+void
+Log::Verbose (const char *format, ...)
+{
+ if (m_options.Test(LLDB_LOG_OPTION_VERBOSE))
+ {
+ va_list args;
+ va_start (args, format);
+ PrintfWithFlagsVarArg (LLDB_LOG_FLAG_VERBOSE, format, args);
+ va_end (args);
+ }
+}
+
+//----------------------------------------------------------------------
+// Printing of warnings that are not fatal only if verbose mode is
+// enabled.
+//----------------------------------------------------------------------
+void
+Log::WarningVerbose (const char *format, ...)
+{
+ if (m_options.Test(LLDB_LOG_OPTION_VERBOSE))
+ {
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ PrintfWithFlags (LLDB_LOG_FLAG_WARNING | LLDB_LOG_FLAG_VERBOSE, "warning: %s", arg_msg);
+ free (arg_msg);
+ }
+ }
+}
+//----------------------------------------------------------------------
+// Printing of warnings that are not fatal.
+//----------------------------------------------------------------------
+void
+Log::Warning (const char *format, ...)
+{
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ PrintfWithFlags (LLDB_LOG_FLAG_WARNING, "warning: %s", arg_msg);
+ free (arg_msg);
+ }
+}
+
+typedef std::map <ConstString, Log::Callbacks> CallbackMap;
+typedef CallbackMap::iterator CallbackMapIter;
+
+typedef std::map <ConstString, LogChannelSP> LogChannelMap;
+typedef LogChannelMap::iterator LogChannelMapIter;
+
+
+// Surround our callback map with a singleton function so we don't have any
+// global initializers.
+static CallbackMap &
+GetCallbackMap ()
+{
+ static CallbackMap g_callback_map;
+ return g_callback_map;
+}
+
+static LogChannelMap &
+GetChannelMap ()
+{
+ static LogChannelMap g_channel_map;
+ return g_channel_map;
+}
+
+void
+Log::RegisterLogChannel (const ConstString &channel, const Log::Callbacks &log_callbacks)
+{
+ GetCallbackMap().insert(std::make_pair(channel, log_callbacks));
+}
+
+bool
+Log::UnregisterLogChannel (const ConstString &channel)
+{
+ return GetCallbackMap().erase(channel) != 0;
+}
+
+bool
+Log::GetLogChannelCallbacks (const ConstString &channel, Log::Callbacks &log_callbacks)
+{
+ CallbackMap &callback_map = GetCallbackMap ();
+ CallbackMapIter pos = callback_map.find(channel);
+ if (pos != callback_map.end())
+ {
+ log_callbacks = pos->second;
+ return true;
+ }
+ ::memset (&log_callbacks, 0, sizeof(log_callbacks));
+ return false;
+}
+
+void
+Log::EnableAllLogChannels
+(
+ StreamSP &log_stream_sp,
+ uint32_t log_options,
+ const char **categories,
+ Stream *feedback_strm
+)
+{
+ CallbackMap &callback_map = GetCallbackMap ();
+ CallbackMapIter pos, end = callback_map.end();
+
+ for (pos = callback_map.begin(); pos != end; ++pos)
+ pos->second.enable (log_stream_sp, log_options, categories, feedback_strm);
+
+ LogChannelMap &channel_map = GetChannelMap ();
+ LogChannelMapIter channel_pos, channel_end = channel_map.end();
+ for (channel_pos = channel_map.begin(); channel_pos != channel_end; ++channel_pos)
+ {
+ channel_pos->second->Enable (log_stream_sp, log_options, feedback_strm, categories);
+ }
+
+}
+
+void
+Log::AutoCompleteChannelName (const char *channel_name, StringList &matches)
+{
+ LogChannelMap &map = GetChannelMap ();
+ LogChannelMapIter pos, end = map.end();
+ for (pos = map.begin(); pos != end; ++pos)
+ {
+ const char *pos_channel_name = pos->first.GetCString();
+ if (channel_name && channel_name[0])
+ {
+ if (NameMatches (channel_name, eNameMatchStartsWith, pos_channel_name))
+ {
+ matches.AppendString(pos_channel_name);
+ }
+ }
+ else
+ matches.AppendString(pos_channel_name);
+
+ }
+}
+
+void
+Log::DisableAllLogChannels (Stream *feedback_strm)
+{
+ CallbackMap &callback_map = GetCallbackMap ();
+ CallbackMapIter pos, end = callback_map.end();
+ const char *categories[1] = {NULL};
+
+ for (pos = callback_map.begin(); pos != end; ++pos)
+ pos->second.disable (categories, feedback_strm);
+
+ LogChannelMap &channel_map = GetChannelMap ();
+ LogChannelMapIter channel_pos, channel_end = channel_map.end();
+ for (channel_pos = channel_map.begin(); channel_pos != channel_end; ++channel_pos)
+ channel_pos->second->Disable (categories, feedback_strm);
+}
+
+void
+Log::Initialize()
+{
+ Log::Callbacks log_callbacks = { DisableLog, EnableLog, ListLogCategories };
+ Log::RegisterLogChannel (ConstString("lldb"), log_callbacks);
+}
+
+void
+Log::Terminate ()
+{
+ DisableAllLogChannels (NULL);
+}
+
+void
+Log::ListAllLogChannels (Stream *strm)
+{
+ CallbackMap &callback_map = GetCallbackMap ();
+ LogChannelMap &channel_map = GetChannelMap ();
+
+ if (callback_map.empty() && channel_map.empty())
+ {
+ strm->PutCString ("No logging channels are currently registered.\n");
+ return;
+ }
+
+ CallbackMapIter pos, end = callback_map.end();
+ for (pos = callback_map.begin(); pos != end; ++pos)
+ pos->second.list_categories (strm);
+
+ uint32_t idx = 0;
+ const char *name;
+ for (idx = 0; (name = PluginManager::GetLogChannelCreateNameAtIndex (idx)) != NULL; ++idx)
+ {
+ LogChannelSP log_channel_sp(LogChannel::FindPlugin (name));
+ if (log_channel_sp)
+ log_channel_sp->ListCategories (strm);
+ }
+}
+
+bool
+Log::GetVerbose() const
+{
+ // FIXME: This has to be centralized between the stream and the log...
+ if (m_options.Test(LLDB_LOG_OPTION_VERBOSE))
+ return true;
+
+ if (m_stream_sp)
+ return m_stream_sp->GetVerbose();
+ return false;
+}
+
+//------------------------------------------------------------------
+// Returns true if the debug flag bit is set in this stream.
+//------------------------------------------------------------------
+bool
+Log::GetDebug() const
+{
+ if (m_stream_sp)
+ return m_stream_sp->GetDebug();
+ return false;
+}
+
+
+LogChannelSP
+LogChannel::FindPlugin (const char *plugin_name)
+{
+ LogChannelSP log_channel_sp;
+ LogChannelMap &channel_map = GetChannelMap ();
+ ConstString log_channel_name (plugin_name);
+ LogChannelMapIter pos = channel_map.find (log_channel_name);
+ if (pos == channel_map.end())
+ {
+ ConstString const_plugin_name (plugin_name);
+ LogChannelCreateInstance create_callback = PluginManager::GetLogChannelCreateCallbackForPluginName (const_plugin_name);
+ if (create_callback)
+ {
+ log_channel_sp.reset(create_callback());
+ if (log_channel_sp)
+ {
+ // Cache the one and only loaded instance of each log channel
+ // plug-in after it has been loaded once.
+ channel_map[log_channel_name] = log_channel_sp;
+ }
+ }
+ }
+ else
+ {
+ // We have already loaded an instance of this log channel class,
+ // so just return the cached instance.
+ log_channel_sp = pos->second;
+ }
+ return log_channel_sp;
+}
+
+LogChannel::LogChannel () :
+ m_log_ap ()
+{
+}
+
+LogChannel::~LogChannel ()
+{
+}
+
+
diff --git a/source/Core/Mangled.cpp b/source/Core/Mangled.cpp
new file mode 100644
index 0000000..4655eb1
--- /dev/null
+++ b/source/Core/Mangled.cpp
@@ -0,0 +1,313 @@
+//===-- Mangled.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// FreeBSD9-STABLE requires this to know about size_t in cxxabi.h
+#include <cstddef>
+#include <cxxabi.h>
+
+
+#include "llvm/ADT/DenseMap.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+using namespace lldb_private;
+
+static inline bool
+cstring_is_mangled (const char *s)
+{
+ if (s)
+ return s[0] == '_' && s[1] == 'Z';
+ return false;
+}
+
+#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 (const ConstString &s) :
+ m_mangled(),
+ m_demangled()
+{
+ if (s)
+ SetValue(s);
+}
+
+//----------------------------------------------------------------------
+// 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 the string values.
+//----------------------------------------------------------------------
+int
+Mangled::Compare (const Mangled& a, const Mangled& b)
+{
+ return ConstString::Compare(a.GetName(ePreferMangled), a.GetName(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 () 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.
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "Mangled::GetDemangledName (m_mangled = %s)",
+ m_mangled.GetCString());
+
+ // Don't bother running anything that isn't mangled
+ const char *mangled_cstr = m_mangled.GetCString();
+ if (cstring_is_mangled(mangled_cstr))
+ {
+ if (!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 = abi::__cxa_demangle (mangled_cstr, NULL, NULL, NULL);
+
+ 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;
+}
+
+
+bool
+Mangled::NameMatches (const RegularExpression& regex) const
+{
+ if (m_mangled && regex.Execute (m_mangled.AsCString()))
+ return true;
+
+ if (GetDemangledName() && regex.Execute (m_demangled.AsCString()))
+ return true;
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Get the demangled name if there is one, else return the mangled name.
+//----------------------------------------------------------------------
+const ConstString&
+Mangled::GetName (Mangled::NamePreference preference) const
+{
+ if (preference == ePreferDemangled)
+ {
+ // Call the accessor to make sure we get a demangled name in case
+ // it hasn't been demangled yet...
+ if (GetDemangledName())
+ return m_demangled;
+ return m_mangled;
+ }
+ else
+ {
+ if (m_mangled)
+ return m_mangled;
+ return GetDemangledName();
+ }
+}
+
+//----------------------------------------------------------------------
+// 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 = ", (int)sizeof(void*) * 2, 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();
+}
+
+//----------------------------------------------------------------------
+// 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();
+ if (demangled)
+ s << ", demangled = '" << demangled << '\'';
+ else
+ s << ", demangled = <error>";
+ return s;
+}
diff --git a/source/Core/Module.cpp b/source/Core/Module.cpp
new file mode 100644
index 0000000..4252ed4
--- /dev/null
+++ b/source/Core/Module.cpp
@@ -0,0 +1,1609 @@
+//===-- Module.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/lldb-python.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Symbol/SymbolFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Shared pointers to modules track module lifetimes in
+// targets and in the global module, but this collection
+// will track all module objects that are still alive
+typedef std::vector<Module *> ModuleCollection;
+
+static ModuleCollection &
+GetModuleCollection()
+{
+ // This module collection needs to live past any module, so we could either make it a
+ // shared pointer in each module or just leak is. Since it is only an empty vector by
+ // the time all the modules have gone away, we just leak it for now. If we decide this
+ // is a big problem we can introduce a Finalize method that will tear everything down in
+ // a predictable order.
+
+ static ModuleCollection *g_module_collection = NULL;
+ if (g_module_collection == NULL)
+ g_module_collection = new ModuleCollection();
+
+ return *g_module_collection;
+}
+
+Mutex *
+Module::GetAllocationModuleCollectionMutex()
+{
+ // NOTE: The mutex below must be leaked since the global module list in
+ // the ModuleList class will get torn at some point, and we can't know
+ // if it will tear itself down before the "g_module_collection_mutex" below
+ // will. So we leak a Mutex object below to safeguard against that
+
+ static Mutex *g_module_collection_mutex = NULL;
+ if (g_module_collection_mutex == NULL)
+ g_module_collection_mutex = new Mutex (Mutex::eMutexTypeRecursive); // NOTE: known leak
+ return g_module_collection_mutex;
+}
+
+size_t
+Module::GetNumberAllocatedModules ()
+{
+ Mutex::Locker locker (GetAllocationModuleCollectionMutex());
+ return GetModuleCollection().size();
+}
+
+Module *
+Module::GetAllocatedModuleAtIndex (size_t idx)
+{
+ Mutex::Locker locker (GetAllocationModuleCollectionMutex());
+ ModuleCollection &modules = GetModuleCollection();
+ if (idx < modules.size())
+ return modules[idx];
+ return NULL;
+}
+#if 0
+
+// These functions help us to determine if modules are still loaded, yet don't require that
+// you have a command interpreter and can easily be called from an external debugger.
+namespace lldb {
+
+ void
+ ClearModuleInfo (void)
+ {
+ const bool mandatory = true;
+ ModuleList::RemoveOrphanSharedModules(mandatory);
+ }
+
+ void
+ DumpModuleInfo (void)
+ {
+ Mutex::Locker locker (Module::GetAllocationModuleCollectionMutex());
+ ModuleCollection &modules = GetModuleCollection();
+ const size_t count = modules.size();
+ printf ("%s: %" PRIu64 " modules:\n", __PRETTY_FUNCTION__, (uint64_t)count);
+ for (size_t i=0; i<count; ++i)
+ {
+
+ StreamString strm;
+ Module *module = modules[i];
+ const bool in_shared_module_list = ModuleList::ModuleIsInCache (module);
+ module->GetDescription(&strm, eDescriptionLevelFull);
+ printf ("%p: shared = %i, ref_count = %3u, module = %s\n",
+ module,
+ in_shared_module_list,
+ (uint32_t)module->use_count(),
+ strm.GetString().c_str());
+ }
+ }
+}
+
+#endif
+
+Module::Module (const ModuleSpec &module_spec) :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_mod_time (module_spec.GetFileSpec().GetModificationTime()),
+ m_arch (module_spec.GetArchitecture()),
+ m_uuid (),
+ m_file (module_spec.GetFileSpec()),
+ m_platform_file(module_spec.GetPlatformFileSpec()),
+ m_symfile_spec (module_spec.GetSymbolFileSpec()),
+ m_object_name (module_spec.GetObjectName()),
+ m_object_offset (module_spec.GetObjectOffset()),
+ m_object_mod_time (module_spec.GetObjectModificationTime()),
+ m_objfile_sp (),
+ m_symfile_ap (),
+ m_ast (),
+ m_source_mappings (),
+ m_did_load_objfile (false),
+ m_did_load_symbol_vendor (false),
+ m_did_parse_uuid (false),
+ m_did_init_ast (false),
+ m_is_dynamic_loader_module (false),
+ m_file_has_changed (false),
+ m_first_file_changed_log (false)
+{
+ // Scope for locker below...
+ {
+ Mutex::Locker locker (GetAllocationModuleCollectionMutex());
+ GetModuleCollection().push_back(this);
+ }
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT|LIBLLDB_LOG_MODULES));
+ if (log)
+ log->Printf ("%p Module::Module((%s) '%s%s%s%s')",
+ this,
+ m_arch.GetArchitectureName(),
+ m_file.GetPath().c_str(),
+ m_object_name.IsEmpty() ? "" : "(",
+ m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
+ m_object_name.IsEmpty() ? "" : ")");
+}
+
+Module::Module(const FileSpec& file_spec,
+ const ArchSpec& arch,
+ const ConstString *object_name,
+ off_t object_offset,
+ const TimeValue *object_mod_time_ptr) :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_mod_time (file_spec.GetModificationTime()),
+ m_arch (arch),
+ m_uuid (),
+ m_file (file_spec),
+ m_platform_file(),
+ m_symfile_spec (),
+ m_object_name (),
+ m_object_offset (object_offset),
+ m_object_mod_time (),
+ m_objfile_sp (),
+ m_symfile_ap (),
+ m_ast (),
+ m_source_mappings (),
+ m_did_load_objfile (false),
+ m_did_load_symbol_vendor (false),
+ m_did_parse_uuid (false),
+ m_did_init_ast (false),
+ m_is_dynamic_loader_module (false),
+ m_file_has_changed (false),
+ m_first_file_changed_log (false)
+{
+ // Scope for locker below...
+ {
+ Mutex::Locker locker (GetAllocationModuleCollectionMutex());
+ GetModuleCollection().push_back(this);
+ }
+
+ if (object_name)
+ m_object_name = *object_name;
+
+ if (object_mod_time_ptr)
+ m_object_mod_time = *object_mod_time_ptr;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT|LIBLLDB_LOG_MODULES));
+ if (log)
+ log->Printf ("%p Module::Module((%s) '%s%s%s%s')",
+ this,
+ m_arch.GetArchitectureName(),
+ m_file.GetPath().c_str(),
+ m_object_name.IsEmpty() ? "" : "(",
+ m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
+ m_object_name.IsEmpty() ? "" : ")");
+}
+
+Module::~Module()
+{
+ // Lock our module down while we tear everything down to make sure
+ // we don't get any access to the module while it is being destroyed
+ Mutex::Locker locker (m_mutex);
+ // Scope for locker below...
+ {
+ Mutex::Locker locker (GetAllocationModuleCollectionMutex());
+ ModuleCollection &modules = GetModuleCollection();
+ ModuleCollection::iterator end = modules.end();
+ ModuleCollection::iterator pos = std::find(modules.begin(), end, this);
+ assert (pos != end);
+ modules.erase(pos);
+ }
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT|LIBLLDB_LOG_MODULES));
+ if (log)
+ log->Printf ("%p Module::~Module((%s) '%s%s%s%s')",
+ this,
+ m_arch.GetArchitectureName(),
+ m_file.GetPath().c_str(),
+ m_object_name.IsEmpty() ? "" : "(",
+ m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
+ m_object_name.IsEmpty() ? "" : ")");
+ // Release any auto pointers before we start tearing down our member
+ // variables since the object file and symbol files might need to make
+ // function calls back into this module object. The ordering is important
+ // here because symbol files can require the module object file. So we tear
+ // down the symbol file first, then the object file.
+ m_sections_ap.reset();
+ m_symfile_ap.reset();
+ m_objfile_sp.reset();
+}
+
+ObjectFile *
+Module::GetMemoryObjectFile (const lldb::ProcessSP &process_sp, lldb::addr_t header_addr, Error &error)
+{
+ if (m_objfile_sp)
+ {
+ error.SetErrorString ("object file already exists");
+ }
+ else
+ {
+ Mutex::Locker locker (m_mutex);
+ if (process_sp)
+ {
+ m_did_load_objfile = true;
+ std::unique_ptr<DataBufferHeap> data_ap (new DataBufferHeap (512, 0));
+ Error readmem_error;
+ const size_t bytes_read = process_sp->ReadMemory (header_addr,
+ data_ap->GetBytes(),
+ data_ap->GetByteSize(),
+ readmem_error);
+ if (bytes_read == 512)
+ {
+ DataBufferSP data_sp(data_ap.release());
+ m_objfile_sp = ObjectFile::FindPlugin(shared_from_this(), process_sp, header_addr, data_sp);
+ if (m_objfile_sp)
+ {
+ StreamString s;
+ s.Printf("0x%16.16" PRIx64, header_addr);
+ m_object_name.SetCString (s.GetData());
+
+ // Once we get the object file, update our module with the object file's
+ // architecture since it might differ in vendor/os if some parts were
+ // unknown.
+ m_objfile_sp->GetArchitecture (m_arch);
+ }
+ else
+ {
+ error.SetErrorString ("unable to find suitable object file plug-in");
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unable to read header from memory: %s", readmem_error.AsCString());
+ }
+ }
+ else
+ {
+ error.SetErrorString ("invalid process");
+ }
+ }
+ return m_objfile_sp.get();
+}
+
+
+const lldb_private::UUID&
+Module::GetUUID()
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_did_parse_uuid == false)
+ {
+ ObjectFile * obj_file = GetObjectFile ();
+
+ if (obj_file != NULL)
+ {
+ obj_file->GetUUID(&m_uuid);
+ m_did_parse_uuid = true;
+ }
+ }
+ return m_uuid;
+}
+
+ClangASTContext &
+Module::GetClangASTContext ()
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_did_init_ast == false)
+ {
+ ObjectFile * objfile = GetObjectFile();
+ ArchSpec object_arch;
+ if (objfile && objfile->GetArchitecture(object_arch))
+ {
+ m_did_init_ast = true;
+
+ // LLVM wants this to be set to iOS or MacOSX; if we're working on
+ // a bare-boards type image, change the triple for llvm's benefit.
+ if (object_arch.GetTriple().getVendor() == llvm::Triple::Apple
+ && object_arch.GetTriple().getOS() == llvm::Triple::UnknownOS)
+ {
+ if (object_arch.GetTriple().getArch() == llvm::Triple::arm ||
+ object_arch.GetTriple().getArch() == llvm::Triple::thumb)
+ {
+ object_arch.GetTriple().setOS(llvm::Triple::IOS);
+ }
+ else
+ {
+ object_arch.GetTriple().setOS(llvm::Triple::MacOSX);
+ }
+ }
+ m_ast.SetArchitecture (object_arch);
+ }
+ }
+ return m_ast;
+}
+
+void
+Module::ParseAllDebugSymbols()
+{
+ Mutex::Locker locker (m_mutex);
+ size_t num_comp_units = GetNumCompileUnits();
+ if (num_comp_units == 0)
+ return;
+
+ SymbolContext sc;
+ sc.module_sp = shared_from_this();
+ SymbolVendor *symbols = GetSymbolVendor ();
+
+ for (size_t cu_idx = 0; cu_idx < num_comp_units; cu_idx++)
+ {
+ sc.comp_unit = symbols->GetCompileUnitAtIndex(cu_idx).get();
+ if (sc.comp_unit)
+ {
+ sc.function = NULL;
+ symbols->ParseVariablesForContext(sc);
+
+ symbols->ParseCompileUnitFunctions(sc);
+
+ for (size_t func_idx = 0; (sc.function = sc.comp_unit->GetFunctionAtIndex(func_idx).get()) != NULL; ++func_idx)
+ {
+ symbols->ParseFunctionBlocks(sc);
+
+ // Parse the variables for this function and all its blocks
+ symbols->ParseVariablesForContext(sc);
+ }
+
+
+ // Parse all types for this compile unit
+ sc.function = NULL;
+ symbols->ParseTypes(sc);
+ }
+ }
+}
+
+void
+Module::CalculateSymbolContext(SymbolContext* sc)
+{
+ sc->module_sp = shared_from_this();
+}
+
+ModuleSP
+Module::CalculateSymbolContextModule ()
+{
+ return shared_from_this();
+}
+
+void
+Module::DumpSymbolContext(Stream *s)
+{
+ s->Printf(", Module{%p}", this);
+}
+
+size_t
+Module::GetNumCompileUnits()
+{
+ Mutex::Locker locker (m_mutex);
+ Timer scoped_timer(__PRETTY_FUNCTION__, "Module::GetNumCompileUnits (module = %p)", this);
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->GetNumCompileUnits();
+ return 0;
+}
+
+CompUnitSP
+Module::GetCompileUnitAtIndex (size_t index)
+{
+ Mutex::Locker locker (m_mutex);
+ size_t num_comp_units = GetNumCompileUnits ();
+ CompUnitSP cu_sp;
+
+ if (index < num_comp_units)
+ {
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ cu_sp = symbols->GetCompileUnitAtIndex(index);
+ }
+ return cu_sp;
+}
+
+bool
+Module::ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr)
+{
+ Mutex::Locker locker (m_mutex);
+ Timer scoped_timer(__PRETTY_FUNCTION__, "Module::ResolveFileAddress (vm_addr = 0x%" PRIx64 ")", vm_addr);
+ SectionList *section_list = GetSectionList();
+ if (section_list)
+ return so_addr.ResolveAddressUsingFileSections(vm_addr, section_list);
+ return false;
+}
+
+uint32_t
+Module::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc)
+{
+ Mutex::Locker locker (m_mutex);
+ uint32_t resolved_flags = 0;
+
+ // Clear the result symbol context in case we don't find anything, but don't clear the target
+ sc.Clear(false);
+
+ // Get the section from the section/offset address.
+ SectionSP section_sp (so_addr.GetSection());
+
+ // Make sure the section matches this module before we try and match anything
+ if (section_sp && section_sp->GetModule().get() == this)
+ {
+ // If the section offset based address resolved itself, then this
+ // is the right module.
+ sc.module_sp = shared_from_this();
+ resolved_flags |= eSymbolContextModule;
+
+ // Resolve the compile unit, function, block, line table or line
+ // entry if requested.
+ if (resolve_scope & eSymbolContextCompUnit ||
+ resolve_scope & eSymbolContextFunction ||
+ resolve_scope & eSymbolContextBlock ||
+ resolve_scope & eSymbolContextLineEntry )
+ {
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ resolved_flags |= symbols->ResolveSymbolContext (so_addr, resolve_scope, sc);
+ }
+
+ // Resolve the symbol if requested, but don't re-look it up if we've already found it.
+ if (resolve_scope & eSymbolContextSymbol && !(resolved_flags & eSymbolContextSymbol))
+ {
+ SymbolVendor* sym_vendor = GetSymbolVendor();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ {
+ if (so_addr.IsSectionOffset())
+ {
+ sc.symbol = symtab->FindSymbolContainingFileAddress(so_addr.GetFileAddress());
+ if (sc.symbol)
+ resolved_flags |= eSymbolContextSymbol;
+ }
+ }
+ }
+ }
+ }
+ return resolved_flags;
+}
+
+uint32_t
+Module::ResolveSymbolContextForFilePath
+(
+ const char *file_path,
+ uint32_t line,
+ bool check_inlines,
+ uint32_t resolve_scope,
+ SymbolContextList& sc_list
+)
+{
+ FileSpec file_spec(file_path, false);
+ return ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
+}
+
+uint32_t
+Module::ResolveSymbolContextsForFileSpec (const FileSpec &file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
+{
+ Mutex::Locker locker (m_mutex);
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::ResolveSymbolContextForFilePath (%s:%u, check_inlines = %s, resolve_scope = 0x%8.8x)",
+ file_spec.GetPath().c_str(),
+ line,
+ check_inlines ? "yes" : "no",
+ resolve_scope);
+
+ const uint32_t initial_count = sc_list.GetSize();
+
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ symbols->ResolveSymbolContext (file_spec, line, check_inlines, resolve_scope, sc_list);
+
+ return sc_list.GetSize() - initial_count;
+}
+
+
+size_t
+Module::FindGlobalVariables (const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ bool append,
+ size_t max_matches,
+ VariableList& variables)
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindGlobalVariables(name, namespace_decl, append, max_matches, variables);
+ return 0;
+}
+
+size_t
+Module::FindGlobalVariables (const RegularExpression& regex,
+ bool append,
+ size_t max_matches,
+ VariableList& variables)
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindGlobalVariables(regex, append, max_matches, variables);
+ return 0;
+}
+
+size_t
+Module::FindCompileUnits (const FileSpec &path,
+ bool append,
+ SymbolContextList &sc_list)
+{
+ if (!append)
+ sc_list.Clear();
+
+ const size_t start_size = sc_list.GetSize();
+ const size_t num_compile_units = GetNumCompileUnits();
+ SymbolContext sc;
+ sc.module_sp = shared_from_this();
+ const bool compare_directory = path.GetDirectory();
+ for (size_t i=0; i<num_compile_units; ++i)
+ {
+ sc.comp_unit = GetCompileUnitAtIndex(i).get();
+ if (sc.comp_unit)
+ {
+ if (FileSpec::Equal (*sc.comp_unit, path, compare_directory))
+ sc_list.Append(sc);
+ }
+ }
+ return sc_list.GetSize() - start_size;
+}
+
+size_t
+Module::FindFunctions (const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ uint32_t name_type_mask,
+ bool include_symbols,
+ bool include_inlines,
+ bool append,
+ SymbolContextList& sc_list)
+{
+ if (!append)
+ sc_list.Clear();
+
+ const size_t old_size = sc_list.GetSize();
+
+ // Find all the functions (not symbols, but debug information functions...
+ SymbolVendor *symbols = GetSymbolVendor ();
+
+ if (name_type_mask & eFunctionNameTypeAuto)
+ {
+ ConstString lookup_name;
+ uint32_t lookup_name_type_mask = 0;
+ bool match_name_after_lookup = false;
+ Module::PrepareForFunctionNameLookup (name,
+ name_type_mask,
+ lookup_name,
+ lookup_name_type_mask,
+ match_name_after_lookup);
+
+ if (symbols)
+ {
+ symbols->FindFunctions(lookup_name,
+ namespace_decl,
+ lookup_name_type_mask,
+ include_inlines,
+ append,
+ sc_list);
+
+ // Now check our symbol table for symbols that are code symbols if requested
+ if (include_symbols)
+ {
+ Symtab *symtab = symbols->GetSymtab();
+ if (symtab)
+ symtab->FindFunctionSymbols(lookup_name, lookup_name_type_mask, sc_list);
+ }
+ }
+
+ if (match_name_after_lookup)
+ {
+ SymbolContext sc;
+ size_t i = old_size;
+ while (i<sc_list.GetSize())
+ {
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ const char *func_name = sc.GetFunctionName().GetCString();
+ if (func_name && strstr (func_name, name.GetCString()) == NULL)
+ {
+ // Remove the current context
+ sc_list.RemoveContextAtIndex(i);
+ // Don't increment i and continue in the loop
+ continue;
+ }
+ }
+ ++i;
+ }
+ }
+ }
+ else
+ {
+ if (symbols)
+ {
+ symbols->FindFunctions(name, namespace_decl, name_type_mask, include_inlines, append, sc_list);
+
+ // Now check our symbol table for symbols that are code symbols if requested
+ if (include_symbols)
+ {
+ Symtab *symtab = symbols->GetSymtab();
+ if (symtab)
+ symtab->FindFunctionSymbols(name, name_type_mask, sc_list);
+ }
+ }
+ }
+
+ return sc_list.GetSize() - old_size;
+}
+
+size_t
+Module::FindFunctions (const RegularExpression& regex,
+ bool include_symbols,
+ bool include_inlines,
+ bool append,
+ SymbolContextList& sc_list)
+{
+ if (!append)
+ sc_list.Clear();
+
+ const size_t start_size = sc_list.GetSize();
+
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ {
+ symbols->FindFunctions(regex, include_inlines, append, sc_list);
+
+ // Now check our symbol table for symbols that are code symbols if requested
+ if (include_symbols)
+ {
+ Symtab *symtab = symbols->GetSymtab();
+ if (symtab)
+ {
+ std::vector<uint32_t> symbol_indexes;
+ symtab->AppendSymbolIndexesMatchingRegExAndType (regex, eSymbolTypeAny, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes);
+ const size_t num_matches = symbol_indexes.size();
+ if (num_matches)
+ {
+ SymbolContext sc(this);
+ const size_t end_functions_added_index = sc_list.GetSize();
+ size_t num_functions_added_to_sc_list = end_functions_added_index - start_size;
+ if (num_functions_added_to_sc_list == 0)
+ {
+ // No functions were added, just symbols, so we can just append them
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]);
+ SymbolType sym_type = sc.symbol->GetType();
+ if (sc.symbol && (sym_type == eSymbolTypeCode ||
+ sym_type == eSymbolTypeResolver))
+ sc_list.Append(sc);
+ }
+ }
+ else
+ {
+ typedef std::map<lldb::addr_t, uint32_t> FileAddrToIndexMap;
+ FileAddrToIndexMap file_addr_to_index;
+ for (size_t i=start_size; i<end_functions_added_index; ++i)
+ {
+ const SymbolContext &sc = sc_list[i];
+ if (sc.block)
+ continue;
+ file_addr_to_index[sc.function->GetAddressRange().GetBaseAddress().GetFileAddress()] = i;
+ }
+
+ FileAddrToIndexMap::const_iterator end = file_addr_to_index.end();
+ // Functions were added so we need to merge symbols into any
+ // existing function symbol contexts
+ for (size_t i=start_size; i<num_matches; ++i)
+ {
+ sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]);
+ SymbolType sym_type = sc.symbol->GetType();
+ if (sc.symbol && (sym_type == eSymbolTypeCode ||
+ sym_type == eSymbolTypeResolver))
+ {
+ FileAddrToIndexMap::const_iterator pos = file_addr_to_index.find(sc.symbol->GetAddress().GetFileAddress());
+ if (pos == end)
+ sc_list.Append(sc);
+ else
+ sc_list[pos->second].symbol = sc.symbol;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return sc_list.GetSize() - start_size;
+}
+
+size_t
+Module::FindTypes_Impl (const SymbolContext& sc,
+ const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ bool append,
+ size_t max_matches,
+ TypeList& types)
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+ if (sc.module_sp.get() == NULL || sc.module_sp.get() == this)
+ {
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindTypes(sc, name, namespace_decl, append, max_matches, types);
+ }
+ return 0;
+}
+
+size_t
+Module::FindTypesInNamespace (const SymbolContext& sc,
+ const ConstString &type_name,
+ const ClangNamespaceDecl *namespace_decl,
+ size_t max_matches,
+ TypeList& type_list)
+{
+ const bool append = true;
+ return FindTypes_Impl(sc, type_name, namespace_decl, append, max_matches, type_list);
+}
+
+lldb::TypeSP
+Module::FindFirstType (const SymbolContext& sc,
+ const ConstString &name,
+ bool exact_match)
+{
+ TypeList type_list;
+ const size_t num_matches = FindTypes (sc, name, exact_match, 1, type_list);
+ if (num_matches)
+ return type_list.GetTypeAtIndex(0);
+ return TypeSP();
+}
+
+
+size_t
+Module::FindTypes (const SymbolContext& sc,
+ const ConstString &name,
+ bool exact_match,
+ size_t max_matches,
+ TypeList& types)
+{
+ size_t num_matches = 0;
+ const char *type_name_cstr = name.GetCString();
+ std::string type_scope;
+ std::string type_basename;
+ const bool append = true;
+ TypeClass type_class = eTypeClassAny;
+ if (Type::GetTypeScopeAndBasename (type_name_cstr, type_scope, type_basename, type_class))
+ {
+ // Check if "name" starts with "::" which means the qualified type starts
+ // from the root namespace and implies and exact match. The typenames we
+ // get back from clang do not start with "::" so we need to strip this off
+ // in order to get the qualfied names to match
+
+ if (type_scope.size() >= 2 && type_scope[0] == ':' && type_scope[1] == ':')
+ {
+ type_scope.erase(0,2);
+ exact_match = true;
+ }
+ ConstString type_basename_const_str (type_basename.c_str());
+ if (FindTypes_Impl(sc, type_basename_const_str, NULL, append, max_matches, types))
+ {
+ types.RemoveMismatchedTypes (type_scope, type_basename, type_class, exact_match);
+ num_matches = types.GetSize();
+ }
+ }
+ else
+ {
+ // The type is not in a namespace/class scope, just search for it by basename
+ if (type_class != eTypeClassAny)
+ {
+ // The "type_name_cstr" will have been modified if we have a valid type class
+ // prefix (like "struct", "class", "union", "typedef" etc).
+ num_matches = FindTypes_Impl(sc, ConstString(type_name_cstr), NULL, append, max_matches, types);
+ types.RemoveMismatchedTypes (type_class);
+ num_matches = types.GetSize();
+ }
+ else
+ {
+ num_matches = FindTypes_Impl(sc, name, NULL, append, max_matches, types);
+ }
+ }
+
+ return num_matches;
+
+}
+
+SymbolVendor*
+Module::GetSymbolVendor (bool can_create, lldb_private::Stream *feedback_strm)
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_did_load_symbol_vendor == false && can_create)
+ {
+ ObjectFile *obj_file = GetObjectFile ();
+ if (obj_file != NULL)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+ m_symfile_ap.reset(SymbolVendor::FindPlugin(shared_from_this(), feedback_strm));
+ m_did_load_symbol_vendor = true;
+ }
+ }
+ return m_symfile_ap.get();
+}
+
+void
+Module::SetFileSpecAndObjectName (const FileSpec &file, const ConstString &object_name)
+{
+ // Container objects whose paths do not specify a file directly can call
+ // this function to correct the file and object names.
+ m_file = file;
+ m_mod_time = file.GetModificationTime();
+ m_object_name = object_name;
+}
+
+const ArchSpec&
+Module::GetArchitecture () const
+{
+ return m_arch;
+}
+
+std::string
+Module::GetSpecificationDescription () const
+{
+ std::string spec(GetFileSpec().GetPath());
+ if (m_object_name)
+ {
+ spec += '(';
+ spec += m_object_name.GetCString();
+ spec += ')';
+ }
+ return spec;
+}
+
+void
+Module::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ Mutex::Locker locker (m_mutex);
+
+ if (level >= eDescriptionLevelFull)
+ {
+ if (m_arch.IsValid())
+ s->Printf("(%s) ", m_arch.GetArchitectureName());
+ }
+
+ if (level == eDescriptionLevelBrief)
+ {
+ const char *filename = m_file.GetFilename().GetCString();
+ if (filename)
+ s->PutCString (filename);
+ }
+ else
+ {
+ char path[PATH_MAX];
+ if (m_file.GetPath(path, sizeof(path)))
+ s->PutCString(path);
+ }
+
+ const char *object_name = m_object_name.GetCString();
+ if (object_name)
+ s->Printf("(%s)", object_name);
+}
+
+void
+Module::ReportError (const char *format, ...)
+{
+ if (format && format[0])
+ {
+ StreamString strm;
+ strm.PutCString("error: ");
+ GetDescription(&strm, lldb::eDescriptionLevelBrief);
+ strm.PutChar (' ');
+ va_list args;
+ va_start (args, format);
+ strm.PrintfVarArg(format, args);
+ va_end (args);
+
+ const int format_len = strlen(format);
+ if (format_len > 0)
+ {
+ const char last_char = format[format_len-1];
+ if (last_char != '\n' || last_char != '\r')
+ strm.EOL();
+ }
+ Host::SystemLog (Host::eSystemLogError, "%s", strm.GetString().c_str());
+
+ }
+}
+
+bool
+Module::FileHasChanged () const
+{
+ if (m_file_has_changed == false)
+ m_file_has_changed = (m_file.GetModificationTime() != m_mod_time);
+ return m_file_has_changed;
+}
+
+void
+Module::ReportErrorIfModifyDetected (const char *format, ...)
+{
+ if (m_first_file_changed_log == false)
+ {
+ if (FileHasChanged ())
+ {
+ m_first_file_changed_log = true;
+ if (format)
+ {
+ StreamString strm;
+ strm.PutCString("error: the object file ");
+ GetDescription(&strm, lldb::eDescriptionLevelFull);
+ strm.PutCString (" has been modified\n");
+
+ va_list args;
+ va_start (args, format);
+ strm.PrintfVarArg(format, args);
+ va_end (args);
+
+ const int format_len = strlen(format);
+ if (format_len > 0)
+ {
+ const char last_char = format[format_len-1];
+ if (last_char != '\n' || last_char != '\r')
+ strm.EOL();
+ }
+ strm.PutCString("The debug session should be aborted as the original debug information has been overwritten.\n");
+ Host::SystemLog (Host::eSystemLogError, "%s", strm.GetString().c_str());
+ }
+ }
+ }
+}
+
+void
+Module::ReportWarning (const char *format, ...)
+{
+ if (format && format[0])
+ {
+ StreamString strm;
+ strm.PutCString("warning: ");
+ GetDescription(&strm, lldb::eDescriptionLevelFull);
+ strm.PutChar (' ');
+
+ va_list args;
+ va_start (args, format);
+ strm.PrintfVarArg(format, args);
+ va_end (args);
+
+ const int format_len = strlen(format);
+ if (format_len > 0)
+ {
+ const char last_char = format[format_len-1];
+ if (last_char != '\n' || last_char != '\r')
+ strm.EOL();
+ }
+ Host::SystemLog (Host::eSystemLogWarning, "%s", strm.GetString().c_str());
+ }
+}
+
+void
+Module::LogMessage (Log *log, const char *format, ...)
+{
+ if (log)
+ {
+ StreamString log_message;
+ GetDescription(&log_message, lldb::eDescriptionLevelFull);
+ log_message.PutCString (": ");
+ va_list args;
+ va_start (args, format);
+ log_message.PrintfVarArg (format, args);
+ va_end (args);
+ log->PutCString(log_message.GetString().c_str());
+ }
+}
+
+void
+Module::LogMessageVerboseBacktrace (Log *log, const char *format, ...)
+{
+ if (log)
+ {
+ StreamString log_message;
+ GetDescription(&log_message, lldb::eDescriptionLevelFull);
+ log_message.PutCString (": ");
+ va_list args;
+ va_start (args, format);
+ log_message.PrintfVarArg (format, args);
+ va_end (args);
+ if (log->GetVerbose())
+ Host::Backtrace (log_message, 1024);
+ log->PutCString(log_message.GetString().c_str());
+ }
+}
+
+void
+Module::Dump(Stream *s)
+{
+ Mutex::Locker locker (m_mutex);
+ //s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ s->Printf("Module %s%s%s%s\n",
+ m_file.GetPath().c_str(),
+ m_object_name ? "(" : "",
+ m_object_name ? m_object_name.GetCString() : "",
+ m_object_name ? ")" : "");
+
+ s->IndentMore();
+
+ ObjectFile *objfile = GetObjectFile ();
+ if (objfile)
+ objfile->Dump(s);
+
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ symbols->Dump(s);
+
+ s->IndentLess();
+}
+
+
+TypeList*
+Module::GetTypeList ()
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return &symbols->GetTypeList();
+ return NULL;
+}
+
+const ConstString &
+Module::GetObjectName() const
+{
+ return m_object_name;
+}
+
+ObjectFile *
+Module::GetObjectFile()
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_did_load_objfile == false)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::GetObjectFile () module = %s", GetFileSpec().GetFilename().AsCString(""));
+ DataBufferSP data_sp;
+ lldb::offset_t data_offset = 0;
+ const lldb::offset_t file_size = m_file.GetByteSize();
+ if (file_size > m_object_offset)
+ {
+ m_did_load_objfile = true;
+ m_objfile_sp = ObjectFile::FindPlugin (shared_from_this(),
+ &m_file,
+ m_object_offset,
+ file_size - m_object_offset,
+ data_sp,
+ data_offset);
+ if (m_objfile_sp)
+ {
+ // Once we get the object file, update our module with the object file's
+ // architecture since it might differ in vendor/os if some parts were
+ // unknown.
+ m_objfile_sp->GetArchitecture (m_arch);
+ }
+ }
+ }
+ return m_objfile_sp.get();
+}
+
+SectionList *
+Module::GetSectionList()
+{
+ // Populate m_unified_sections_ap with sections from objfile.
+ if (m_sections_ap.get() == NULL)
+ {
+ ObjectFile *obj_file = GetObjectFile();
+ if (obj_file)
+ obj_file->CreateSections(*GetUnifiedSectionList());
+ }
+ return m_sections_ap.get();
+}
+
+SectionList *
+Module::GetUnifiedSectionList()
+{
+ // Populate m_unified_sections_ap with sections from objfile.
+ if (m_sections_ap.get() == NULL)
+ m_sections_ap.reset(new SectionList());
+ return m_sections_ap.get();
+}
+
+const Symbol *
+Module::FindFirstSymbolWithNameAndType (const ConstString &name, SymbolType symbol_type)
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::FindFirstSymbolWithNameAndType (name = %s, type = %i)",
+ name.AsCString(),
+ symbol_type);
+ SymbolVendor* sym_vendor = GetSymbolVendor();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ return symtab->FindFirstSymbolWithNameAndType (name, symbol_type, Symtab::eDebugAny, Symtab::eVisibilityAny);
+ }
+ return NULL;
+}
+void
+Module::SymbolIndicesToSymbolContextList (Symtab *symtab, std::vector<uint32_t> &symbol_indexes, SymbolContextList &sc_list)
+{
+ // No need to protect this call using m_mutex all other method calls are
+ // already thread safe.
+
+ size_t num_indices = symbol_indexes.size();
+ if (num_indices > 0)
+ {
+ SymbolContext sc;
+ CalculateSymbolContext (&sc);
+ for (size_t i = 0; i < num_indices; i++)
+ {
+ sc.symbol = symtab->SymbolAtIndex (symbol_indexes[i]);
+ if (sc.symbol)
+ sc_list.Append (sc);
+ }
+ }
+}
+
+size_t
+Module::FindFunctionSymbols (const ConstString &name,
+ uint32_t name_type_mask,
+ SymbolContextList& sc_list)
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::FindSymbolsFunctions (name = %s, mask = 0x%8.8x)",
+ name.AsCString(),
+ name_type_mask);
+ SymbolVendor* sym_vendor = GetSymbolVendor();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ return symtab->FindFunctionSymbols (name, name_type_mask, sc_list);
+ }
+ return 0;
+}
+
+size_t
+Module::FindSymbolsWithNameAndType (const ConstString &name, SymbolType symbol_type, SymbolContextList &sc_list)
+{
+ // No need to protect this call using m_mutex all other method calls are
+ // already thread safe.
+
+
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::FindSymbolsWithNameAndType (name = %s, type = %i)",
+ name.AsCString(),
+ symbol_type);
+ const size_t initial_size = sc_list.GetSize();
+ SymbolVendor* sym_vendor = GetSymbolVendor();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ {
+ std::vector<uint32_t> symbol_indexes;
+ symtab->FindAllSymbolsWithNameAndType (name, symbol_type, symbol_indexes);
+ SymbolIndicesToSymbolContextList (symtab, symbol_indexes, sc_list);
+ }
+ }
+ return sc_list.GetSize() - initial_size;
+}
+
+size_t
+Module::FindSymbolsMatchingRegExAndType (const RegularExpression &regex, SymbolType symbol_type, SymbolContextList &sc_list)
+{
+ // No need to protect this call using m_mutex all other method calls are
+ // already thread safe.
+
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::FindSymbolsMatchingRegExAndType (regex = %s, type = %i)",
+ regex.GetText(),
+ symbol_type);
+ const size_t initial_size = sc_list.GetSize();
+ SymbolVendor* sym_vendor = GetSymbolVendor();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ {
+ std::vector<uint32_t> symbol_indexes;
+ symtab->FindAllSymbolsMatchingRexExAndType (regex, symbol_type, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes);
+ SymbolIndicesToSymbolContextList (symtab, symbol_indexes, sc_list);
+ }
+ }
+ return sc_list.GetSize() - initial_size;
+}
+
+void
+Module::SetSymbolFileFileSpec (const FileSpec &file)
+{
+ // Remove any sections in the unified section list that come from the current symbol vendor.
+ if (m_symfile_ap)
+ {
+ SectionList *section_list = GetSectionList();
+ SymbolFile *symbol_file = m_symfile_ap->GetSymbolFile();
+ if (section_list && symbol_file)
+ {
+ ObjectFile *obj_file = symbol_file->GetObjectFile();
+ // Make sure we have an object file and that the symbol vendor's objfile isn't
+ // the same as the module's objfile before we remove any sections for it...
+ if (obj_file && obj_file != m_objfile_sp.get())
+ {
+ size_t num_sections = section_list->GetNumSections (0);
+ for (size_t idx = num_sections; idx > 0; --idx)
+ {
+ lldb::SectionSP section_sp (section_list->GetSectionAtIndex (idx - 1));
+ if (section_sp->GetObjectFile() == obj_file)
+ {
+ section_list->DeleteSection (idx - 1);
+ }
+ }
+ }
+ }
+ }
+
+ m_symfile_spec = file;
+ m_symfile_ap.reset();
+ m_did_load_symbol_vendor = false;
+}
+
+bool
+Module::IsExecutable ()
+{
+ if (GetObjectFile() == NULL)
+ return false;
+ else
+ return GetObjectFile()->IsExecutable();
+}
+
+bool
+Module::IsLoadedInTarget (Target *target)
+{
+ ObjectFile *obj_file = GetObjectFile();
+ if (obj_file)
+ {
+ SectionList *sections = GetSectionList();
+ if (sections != NULL)
+ {
+ size_t num_sections = sections->GetSize();
+ for (size_t sect_idx = 0; sect_idx < num_sections; sect_idx++)
+ {
+ SectionSP section_sp = sections->GetSectionAtIndex(sect_idx);
+ if (section_sp->GetLoadBaseAddress(target) != LLDB_INVALID_ADDRESS)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool
+Module::LoadScriptingResourceInTarget (Target *target, Error& error, Stream* feedback_stream)
+{
+ if (!target)
+ {
+ error.SetErrorString("invalid destination Target");
+ return false;
+ }
+
+ LoadScriptFromSymFile shoud_load = target->TargetProperties::GetLoadScriptFromSymbolFile();
+
+ Debugger &debugger = target->GetDebugger();
+ const ScriptLanguage script_language = debugger.GetScriptLanguage();
+ if (script_language != eScriptLanguageNone)
+ {
+
+ PlatformSP platform_sp(target->GetPlatform());
+
+ if (!platform_sp)
+ {
+ error.SetErrorString("invalid Platform");
+ return false;
+ }
+
+ FileSpecList file_specs = platform_sp->LocateExecutableScriptingResources (target,
+ *this);
+
+
+ const uint32_t num_specs = file_specs.GetSize();
+ if (num_specs)
+ {
+ ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interpreter)
+ {
+ for (uint32_t i=0; i<num_specs; ++i)
+ {
+ FileSpec scripting_fspec (file_specs.GetFileSpecAtIndex(i));
+ if (scripting_fspec && scripting_fspec.Exists())
+ {
+ if (shoud_load == eLoadScriptFromSymFileFalse)
+ return false;
+ if (shoud_load == eLoadScriptFromSymFileWarn)
+ {
+ if (feedback_stream)
+ feedback_stream->Printf("warning: '%s' contains a debug script. To run this script in "
+ "this debug session:\n\n command script import \"%s\"\n\n"
+ "To run all discovered debug scripts in this session:\n\n"
+ " settings set target.load-script-from-symbol-file true\n",
+ GetFileSpec().GetFileNameStrippingExtension().GetCString(),
+ scripting_fspec.GetPath().c_str());
+ return false;
+ }
+ StreamString scripting_stream;
+ scripting_fspec.Dump(&scripting_stream);
+ const bool can_reload = true;
+ const bool init_lldb_globals = false;
+ bool did_load = script_interpreter->LoadScriptingModule(scripting_stream.GetData(),
+ can_reload,
+ init_lldb_globals,
+ error);
+ if (!did_load)
+ return false;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("invalid ScriptInterpreter");
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool
+Module::SetArchitecture (const ArchSpec &new_arch)
+{
+ if (!m_arch.IsValid())
+ {
+ m_arch = new_arch;
+ return true;
+ }
+ return m_arch.IsExactMatch(new_arch);
+}
+
+bool
+Module::SetLoadAddress (Target &target, lldb::addr_t offset, bool &changed)
+{
+ size_t num_loaded_sections = 0;
+ SectionList *section_list = GetSectionList ();
+ if (section_list)
+ {
+ const size_t num_sections = section_list->GetSize();
+ size_t sect_idx = 0;
+ for (sect_idx = 0; sect_idx < num_sections; ++sect_idx)
+ {
+ // Iterate through the object file sections to find the
+ // first section that starts of file offset zero and that
+ // has bytes in the file...
+ SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx));
+ // Only load non-thread specific sections when given a slide
+ if (section_sp && !section_sp->IsThreadSpecific())
+ {
+ if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + offset))
+ ++num_loaded_sections;
+ }
+ }
+ }
+ changed = num_loaded_sections > 0;
+ return num_loaded_sections > 0;
+}
+
+
+bool
+Module::MatchesModuleSpec (const ModuleSpec &module_ref)
+{
+ const UUID &uuid = module_ref.GetUUID();
+
+ if (uuid.IsValid())
+ {
+ // If the UUID matches, then nothing more needs to match...
+ if (uuid == GetUUID())
+ return true;
+ else
+ return false;
+ }
+
+ const FileSpec &file_spec = module_ref.GetFileSpec();
+ if (file_spec)
+ {
+ if (!FileSpec::Equal (file_spec, m_file, file_spec.GetDirectory()))
+ return false;
+ }
+
+ const FileSpec &platform_file_spec = module_ref.GetPlatformFileSpec();
+ if (platform_file_spec)
+ {
+ if (!FileSpec::Equal (platform_file_spec, GetPlatformFileSpec (), platform_file_spec.GetDirectory()))
+ return false;
+ }
+
+ const ArchSpec &arch = module_ref.GetArchitecture();
+ if (arch.IsValid())
+ {
+ if (!m_arch.IsCompatibleMatch(arch))
+ return false;
+ }
+
+ const ConstString &object_name = module_ref.GetObjectName();
+ if (object_name)
+ {
+ if (object_name != GetObjectName())
+ return false;
+ }
+ return true;
+}
+
+bool
+Module::FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const
+{
+ Mutex::Locker locker (m_mutex);
+ return m_source_mappings.FindFile (orig_spec, new_spec);
+}
+
+bool
+Module::RemapSourceFile (const char *path, std::string &new_path) const
+{
+ Mutex::Locker locker (m_mutex);
+ return m_source_mappings.RemapPath(path, new_path);
+}
+
+uint32_t
+Module::GetVersion (uint32_t *versions, uint32_t num_versions)
+{
+ ObjectFile *obj_file = GetObjectFile();
+ if (obj_file)
+ return obj_file->GetVersion (versions, num_versions);
+
+ if (versions && num_versions)
+ {
+ for (uint32_t i=0; i<num_versions; ++i)
+ versions[i] = UINT32_MAX;
+ }
+ return 0;
+}
+
+void
+Module::PrepareForFunctionNameLookup (const ConstString &name,
+ uint32_t name_type_mask,
+ ConstString &lookup_name,
+ uint32_t &lookup_name_type_mask,
+ bool &match_name_after_lookup)
+{
+ const char *name_cstr = name.GetCString();
+ lookup_name_type_mask = eFunctionNameTypeNone;
+ match_name_after_lookup = false;
+ const char *base_name_start = NULL;
+ const char *base_name_end = NULL;
+
+ if (name_type_mask & eFunctionNameTypeAuto)
+ {
+ if (CPPLanguageRuntime::IsCPPMangledName (name_cstr))
+ lookup_name_type_mask = eFunctionNameTypeFull;
+ else if (ObjCLanguageRuntime::IsPossibleObjCMethodName (name_cstr))
+ lookup_name_type_mask = eFunctionNameTypeFull;
+ else
+ {
+ if (ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr))
+ lookup_name_type_mask |= eFunctionNameTypeSelector;
+
+ CPPLanguageRuntime::MethodName cpp_method (name);
+ llvm::StringRef basename (cpp_method.GetBasename());
+ if (basename.empty())
+ {
+ if (CPPLanguageRuntime::StripNamespacesFromVariableName (name_cstr, base_name_start, base_name_end))
+ lookup_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase);
+ }
+ else
+ {
+ base_name_start = basename.data();
+ base_name_end = base_name_start + basename.size();
+ lookup_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase);
+ }
+ }
+ }
+ else
+ {
+ lookup_name_type_mask = name_type_mask;
+ if (lookup_name_type_mask & eFunctionNameTypeMethod || name_type_mask & eFunctionNameTypeBase)
+ {
+ // If they've asked for a CPP method or function name and it can't be that, we don't
+ // even need to search for CPP methods or names.
+ CPPLanguageRuntime::MethodName cpp_method (name);
+ if (cpp_method.IsValid())
+ {
+ llvm::StringRef basename (cpp_method.GetBasename());
+ base_name_start = basename.data();
+ base_name_end = base_name_start + basename.size();
+
+ if (!cpp_method.GetQualifiers().empty())
+ {
+ // There is a "const" or other qualifer following the end of the fucntion parens,
+ // this can't be a eFunctionNameTypeBase
+ lookup_name_type_mask &= ~(eFunctionNameTypeBase);
+ if (lookup_name_type_mask == eFunctionNameTypeNone)
+ return;
+ }
+ }
+ else
+ {
+ if (!CPPLanguageRuntime::StripNamespacesFromVariableName (name_cstr, base_name_start, base_name_end))
+ {
+ lookup_name_type_mask &= ~(eFunctionNameTypeMethod | eFunctionNameTypeBase);
+ if (lookup_name_type_mask == eFunctionNameTypeNone)
+ return;
+ }
+ }
+ }
+
+ if (lookup_name_type_mask & eFunctionNameTypeSelector)
+ {
+ if (!ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr))
+ {
+ lookup_name_type_mask &= ~(eFunctionNameTypeSelector);
+ if (lookup_name_type_mask == eFunctionNameTypeNone)
+ return;
+ }
+ }
+ }
+
+ if (base_name_start &&
+ base_name_end &&
+ base_name_start != name_cstr &&
+ base_name_start < base_name_end)
+ {
+ // The name supplied was a partial C++ path like "a::count". In this case we want to do a
+ // lookup on the basename "count" and then make sure any matching results contain "a::count"
+ // so that it would match "b::a::count" and "a::count". This is why we set "match_name_after_lookup"
+ // to true
+ lookup_name.SetCStringWithLength(base_name_start, base_name_end - base_name_start);
+ match_name_after_lookup = true;
+ }
+ else
+ {
+ // The name is already correct, just use the exact name as supplied, and we won't need
+ // to check if any matches contain "name"
+ lookup_name = name;
+ match_name_after_lookup = false;
+ }
+} \ No newline at end of file
diff --git a/source/Core/ModuleChild.cpp b/source/Core/ModuleChild.cpp
new file mode 100644
index 0000000..9637fc3
--- /dev/null
+++ b/source/Core/ModuleChild.cpp
@@ -0,0 +1,46 @@
+//===-- ModuleChild.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/ModuleChild.h"
+
+using namespace lldb_private;
+
+ModuleChild::ModuleChild (const lldb::ModuleSP &module_sp) :
+ m_module_wp (module_sp)
+{
+}
+
+ModuleChild::ModuleChild (const ModuleChild& rhs) :
+ m_module_wp(rhs.m_module_wp)
+{
+}
+
+ModuleChild::~ModuleChild()
+{
+}
+
+const ModuleChild&
+ModuleChild::operator= (const ModuleChild& rhs)
+{
+ if (this != &rhs)
+ m_module_wp = rhs.m_module_wp;
+ return *this;
+}
+
+lldb::ModuleSP
+ModuleChild::GetModule () const
+{
+ return m_module_wp.lock();
+}
+
+void
+ModuleChild::SetModule (const lldb::ModuleSP &module_sp)
+{
+ m_module_wp = module_sp;
+}
diff --git a/source/Core/ModuleList.cpp b/source/Core/ModuleList.cpp
new file mode 100644
index 0000000..ebc6702
--- /dev/null
+++ b/source/Core/ModuleList.cpp
@@ -0,0 +1,1103 @@
+//===-- ModuleList.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/ModuleList.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/VariableList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ModuleList constructor
+//----------------------------------------------------------------------
+ModuleList::ModuleList() :
+ m_modules(),
+ m_modules_mutex (Mutex::eMutexTypeRecursive),
+ m_notifier(NULL)
+{
+}
+
+//----------------------------------------------------------------------
+// Copy constructor
+//----------------------------------------------------------------------
+ModuleList::ModuleList(const ModuleList& rhs) :
+ m_modules(),
+ m_modules_mutex (Mutex::eMutexTypeRecursive)
+{
+ Mutex::Locker lhs_locker(m_modules_mutex);
+ Mutex::Locker rhs_locker(rhs.m_modules_mutex);
+ m_modules = rhs.m_modules;
+}
+
+ModuleList::ModuleList (ModuleList::Notifier* notifier) :
+ m_modules(),
+ m_modules_mutex (Mutex::eMutexTypeRecursive),
+ m_notifier(notifier)
+{
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const ModuleList&
+ModuleList::operator= (const ModuleList& rhs)
+{
+ if (this != &rhs)
+ {
+ Mutex::Locker lhs_locker(m_modules_mutex);
+ Mutex::Locker rhs_locker(rhs.m_modules_mutex);
+ m_modules = rhs.m_modules;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ModuleList::~ModuleList()
+{
+}
+
+void
+ModuleList::AppendImpl (const ModuleSP &module_sp, bool use_notifier)
+{
+ if (module_sp)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ m_modules.push_back(module_sp);
+ if (use_notifier && m_notifier)
+ m_notifier->ModuleAdded(*this, module_sp);
+ }
+}
+
+void
+ModuleList::Append (const ModuleSP &module_sp)
+{
+ AppendImpl (module_sp);
+}
+
+void
+ModuleList::ReplaceEquivalent (const ModuleSP &module_sp)
+{
+ if (module_sp)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+
+ // First remove any equivalent modules. Equivalent modules are modules
+ // whose path, platform path and architecture match.
+ ModuleSpec equivalent_module_spec (module_sp->GetFileSpec(), module_sp->GetArchitecture());
+ equivalent_module_spec.GetPlatformFileSpec() = module_sp->GetPlatformFileSpec();
+
+ size_t idx = 0;
+ while (idx < m_modules.size())
+ {
+ ModuleSP module_sp (m_modules[idx]);
+ if (module_sp->MatchesModuleSpec (equivalent_module_spec))
+ RemoveImpl(m_modules.begin() + idx);
+ else
+ ++idx;
+ }
+ // Now add the new module to the list
+ Append(module_sp);
+ }
+}
+
+bool
+ModuleList::AppendIfNeeded (const ModuleSP &module_sp)
+{
+ if (module_sp)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if (pos->get() == module_sp.get())
+ return false; // Already in the list
+ }
+ // Only push module_sp on the list if it wasn't already in there.
+ Append(module_sp);
+ return true;
+ }
+ return false;
+}
+
+void
+ModuleList::Append (const ModuleList& module_list)
+{
+ for (auto pos : module_list.m_modules)
+ Append(pos);
+}
+
+bool
+ModuleList::AppendIfNeeded (const ModuleList& module_list)
+{
+ bool any_in = false;
+ for (auto pos : module_list.m_modules)
+ {
+ if (AppendIfNeeded(pos))
+ any_in = true;
+ }
+ return any_in;
+}
+
+bool
+ModuleList::RemoveImpl (const ModuleSP &module_sp, bool use_notifier)
+{
+ if (module_sp)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if (pos->get() == module_sp.get())
+ {
+ m_modules.erase (pos);
+ if (use_notifier && m_notifier)
+ m_notifier->ModuleRemoved(*this, module_sp);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ModuleList::collection::iterator
+ModuleList::RemoveImpl (ModuleList::collection::iterator pos, bool use_notifier)
+{
+ ModuleSP module_sp(*pos);
+ collection::iterator retval = m_modules.erase(pos);
+ if (use_notifier && m_notifier)
+ m_notifier->ModuleRemoved(*this, module_sp);
+ return retval;
+}
+
+bool
+ModuleList::Remove (const ModuleSP &module_sp)
+{
+ return RemoveImpl (module_sp);
+}
+
+bool
+ModuleList::ReplaceModule (const lldb::ModuleSP &old_module_sp, const lldb::ModuleSP &new_module_sp)
+{
+ if (!RemoveImpl(old_module_sp, false))
+ return false;
+ AppendImpl (new_module_sp, false);
+ if (m_notifier)
+ m_notifier->ModuleUpdated(*this, old_module_sp,new_module_sp);
+ return true;
+}
+
+bool
+ModuleList::RemoveIfOrphaned (const Module *module_ptr)
+{
+ if (module_ptr)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if (pos->get() == module_ptr)
+ {
+ if (pos->unique())
+ {
+ pos = RemoveImpl(pos);
+ return true;
+ }
+ else
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+size_t
+ModuleList::RemoveOrphans (bool mandatory)
+{
+ Mutex::Locker locker;
+
+ if (mandatory)
+ {
+ locker.Lock (m_modules_mutex);
+ }
+ else
+ {
+ // Not mandatory, remove orphans if we can get the mutex
+ if (!locker.TryLock(m_modules_mutex))
+ return 0;
+ }
+ collection::iterator pos = m_modules.begin();
+ size_t remove_count = 0;
+ while (pos != m_modules.end())
+ {
+ if (pos->unique())
+ {
+ pos = RemoveImpl(pos);
+ ++remove_count;
+ }
+ else
+ {
+ ++pos;
+ }
+ }
+ return remove_count;
+}
+
+size_t
+ModuleList::Remove (ModuleList &module_list)
+{
+ Mutex::Locker locker(m_modules_mutex);
+ size_t num_removed = 0;
+ collection::iterator pos, end = module_list.m_modules.end();
+ for (pos = module_list.m_modules.begin(); pos != end; ++pos)
+ {
+ if (Remove (*pos))
+ ++num_removed;
+ }
+ return num_removed;
+}
+
+
+void
+ModuleList::Clear()
+{
+ ClearImpl();
+}
+
+void
+ModuleList::Destroy()
+{
+ ClearImpl();
+}
+
+void
+ModuleList::ClearImpl (bool use_notifier)
+{
+ Mutex::Locker locker(m_modules_mutex);
+ if (use_notifier && m_notifier)
+ m_notifier->WillClearList(*this);
+ m_modules.clear();
+}
+
+Module*
+ModuleList::GetModulePointerAtIndex (size_t idx) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ return GetModulePointerAtIndexUnlocked(idx);
+}
+
+Module*
+ModuleList::GetModulePointerAtIndexUnlocked (size_t idx) const
+{
+ if (idx < m_modules.size())
+ return m_modules[idx].get();
+ return NULL;
+}
+
+ModuleSP
+ModuleList::GetModuleAtIndex(size_t idx) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ return GetModuleAtIndexUnlocked(idx);
+}
+
+ModuleSP
+ModuleList::GetModuleAtIndexUnlocked(size_t idx) const
+{
+ ModuleSP module_sp;
+ if (idx < m_modules.size())
+ module_sp = m_modules[idx];
+ return module_sp;
+}
+
+size_t
+ModuleList::FindFunctions (const ConstString &name,
+ uint32_t name_type_mask,
+ bool include_symbols,
+ bool include_inlines,
+ bool append,
+ SymbolContextList &sc_list) const
+{
+ if (!append)
+ sc_list.Clear();
+
+ const size_t old_size = sc_list.GetSize();
+
+ if (name_type_mask & eFunctionNameTypeAuto)
+ {
+ ConstString lookup_name;
+ uint32_t lookup_name_type_mask = 0;
+ bool match_name_after_lookup = false;
+ Module::PrepareForFunctionNameLookup (name, name_type_mask,
+ lookup_name,
+ lookup_name_type_mask,
+ match_name_after_lookup);
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindFunctions (lookup_name,
+ NULL,
+ lookup_name_type_mask,
+ include_symbols,
+ include_inlines,
+ true,
+ sc_list);
+ }
+
+ if (match_name_after_lookup)
+ {
+ SymbolContext sc;
+ size_t i = old_size;
+ while (i<sc_list.GetSize())
+ {
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ const char *func_name = sc.GetFunctionName().GetCString();
+ if (func_name && strstr (func_name, name.GetCString()) == NULL)
+ {
+ // Remove the current context
+ sc_list.RemoveContextAtIndex(i);
+ // Don't increment i and continue in the loop
+ continue;
+ }
+ }
+ ++i;
+ }
+ }
+
+ }
+ else
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindFunctions (name, NULL, name_type_mask, include_symbols, include_inlines, true, sc_list);
+ }
+ }
+ return sc_list.GetSize() - old_size;
+}
+
+size_t
+ModuleList::FindFunctionSymbols (const ConstString &name,
+ uint32_t name_type_mask,
+ SymbolContextList& sc_list)
+{
+ const size_t old_size = sc_list.GetSize();
+
+ if (name_type_mask & eFunctionNameTypeAuto)
+ {
+ ConstString lookup_name;
+ uint32_t lookup_name_type_mask = 0;
+ bool match_name_after_lookup = false;
+ Module::PrepareForFunctionNameLookup (name, name_type_mask,
+ lookup_name,
+ lookup_name_type_mask,
+ match_name_after_lookup);
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindFunctionSymbols (lookup_name,
+ lookup_name_type_mask,
+ sc_list);
+ }
+
+ if (match_name_after_lookup)
+ {
+ SymbolContext sc;
+ size_t i = old_size;
+ while (i<sc_list.GetSize())
+ {
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ const char *func_name = sc.GetFunctionName().GetCString();
+ if (func_name && strstr (func_name, name.GetCString()) == NULL)
+ {
+ // Remove the current context
+ sc_list.RemoveContextAtIndex(i);
+ // Don't increment i and continue in the loop
+ continue;
+ }
+ }
+ ++i;
+ }
+ }
+
+ }
+ else
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindFunctionSymbols (name, name_type_mask, sc_list);
+ }
+ }
+
+ return sc_list.GetSize() - old_size;
+}
+
+size_t
+ModuleList::FindCompileUnits (const FileSpec &path,
+ bool append,
+ SymbolContextList &sc_list) const
+{
+ if (!append)
+ sc_list.Clear();
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindCompileUnits (path, true, sc_list);
+ }
+
+ return sc_list.GetSize();
+}
+
+size_t
+ModuleList::FindGlobalVariables (const ConstString &name,
+ bool append,
+ size_t max_matches,
+ VariableList& variable_list) const
+{
+ size_t initial_size = variable_list.GetSize();
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindGlobalVariables (name, NULL, append, max_matches, variable_list);
+ }
+ return variable_list.GetSize() - initial_size;
+}
+
+
+size_t
+ModuleList::FindGlobalVariables (const RegularExpression& regex,
+ bool append,
+ size_t max_matches,
+ VariableList& variable_list) const
+{
+ size_t initial_size = variable_list.GetSize();
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindGlobalVariables (regex, append, max_matches, variable_list);
+ }
+ return variable_list.GetSize() - initial_size;
+}
+
+
+size_t
+ModuleList::FindSymbolsWithNameAndType (const ConstString &name,
+ SymbolType symbol_type,
+ SymbolContextList &sc_list,
+ bool append) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ if (!append)
+ sc_list.Clear();
+ size_t initial_size = sc_list.GetSize();
+
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ (*pos)->FindSymbolsWithNameAndType (name, symbol_type, sc_list);
+ return sc_list.GetSize() - initial_size;
+}
+
+size_t
+ModuleList::FindSymbolsMatchingRegExAndType (const RegularExpression &regex,
+ lldb::SymbolType symbol_type,
+ SymbolContextList &sc_list,
+ bool append) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ if (!append)
+ sc_list.Clear();
+ size_t initial_size = sc_list.GetSize();
+
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ (*pos)->FindSymbolsMatchingRegExAndType (regex, symbol_type, sc_list);
+ return sc_list.GetSize() - initial_size;
+}
+
+size_t
+ModuleList::FindModules (const ModuleSpec &module_spec, ModuleList& matching_module_list) const
+{
+ size_t existing_matches = matching_module_list.GetSize();
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ ModuleSP module_sp(*pos);
+ if (module_sp->MatchesModuleSpec (module_spec))
+ matching_module_list.Append(module_sp);
+ }
+ return matching_module_list.GetSize() - existing_matches;
+}
+
+ModuleSP
+ModuleList::FindModule (const Module *module_ptr) const
+{
+ ModuleSP module_sp;
+
+ // Scope for "locker"
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if ((*pos).get() == module_ptr)
+ {
+ module_sp = (*pos);
+ break;
+ }
+ }
+ }
+ return module_sp;
+
+}
+
+ModuleSP
+ModuleList::FindModule (const UUID &uuid) const
+{
+ ModuleSP module_sp;
+
+ if (uuid.IsValid())
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetUUID() == uuid)
+ {
+ module_sp = (*pos);
+ break;
+ }
+ }
+ }
+ return module_sp;
+}
+
+
+size_t
+ModuleList::FindTypes (const SymbolContext& sc, const ConstString &name, bool name_is_fully_qualified, size_t max_matches, TypeList& types) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+
+ size_t total_matches = 0;
+ collection::const_iterator pos, end = m_modules.end();
+ if (sc.module_sp)
+ {
+ // The symbol context "sc" contains a module so we want to search that
+ // one first if it is in our list...
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if (sc.module_sp.get() == (*pos).get())
+ {
+ total_matches += (*pos)->FindTypes (sc, name, name_is_fully_qualified, max_matches, types);
+
+ if (total_matches >= max_matches)
+ break;
+ }
+ }
+ }
+
+ if (total_matches < max_matches)
+ {
+ SymbolContext world_sc;
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ // Search the module if the module is not equal to the one in the symbol
+ // context "sc". If "sc" contains a empty module shared pointer, then
+ // the comparisong will always be true (valid_module_ptr != NULL).
+ if (sc.module_sp.get() != (*pos).get())
+ total_matches += (*pos)->FindTypes (world_sc, name, name_is_fully_qualified, max_matches, types);
+
+ if (total_matches >= max_matches)
+ break;
+ }
+ }
+
+ return total_matches;
+}
+
+bool
+ModuleList::FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->FindSourceFile (orig_spec, new_spec))
+ return true;
+ }
+ return false;
+}
+
+
+
+ModuleSP
+ModuleList::FindFirstModule (const ModuleSpec &module_spec) const
+{
+ ModuleSP module_sp;
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ ModuleSP module_sp(*pos);
+ if (module_sp->MatchesModuleSpec (module_spec))
+ return module_sp;
+ }
+ return module_sp;
+
+}
+
+size_t
+ModuleList::GetSize() const
+{
+ size_t size = 0;
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ size = m_modules.size();
+ }
+ return size;
+}
+
+
+void
+ModuleList::Dump(Stream *s) const
+{
+// s.Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+// s.Indent();
+// s << "ModuleList\n";
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->Dump(s);
+ }
+}
+
+void
+ModuleList::LogUUIDAndPaths (Log *log, const char *prefix_cstr)
+{
+ if (log)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, begin = m_modules.begin(), end = m_modules.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ Module *module = pos->get();
+ const FileSpec &module_file_spec = module->GetFileSpec();
+ log->Printf ("%s[%u] %s (%s) \"%s\"",
+ prefix_cstr ? prefix_cstr : "",
+ (uint32_t)std::distance (begin, pos),
+ module->GetUUID().GetAsString().c_str(),
+ module->GetArchitecture().GetArchitectureName(),
+ module_file_spec.GetPath().c_str());
+ }
+ }
+}
+
+bool
+ModuleList::ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->ResolveFileAddress (vm_addr, so_addr))
+ return true;
+ }
+
+ return false;
+}
+
+uint32_t
+ModuleList::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc) const
+{
+ // The address is already section offset so it has a module
+ uint32_t resolved_flags = 0;
+ ModuleSP module_sp (so_addr.GetModule());
+ if (module_sp)
+ {
+ resolved_flags = module_sp->ResolveSymbolContextForAddress (so_addr,
+ resolve_scope,
+ sc);
+ }
+ else
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ resolved_flags = (*pos)->ResolveSymbolContextForAddress (so_addr,
+ resolve_scope,
+ sc);
+ if (resolved_flags != 0)
+ break;
+ }
+ }
+
+ return resolved_flags;
+}
+
+uint32_t
+ModuleList::ResolveSymbolContextForFilePath
+(
+ const char *file_path,
+ uint32_t line,
+ bool check_inlines,
+ uint32_t resolve_scope,
+ SymbolContextList& sc_list
+) const
+{
+ FileSpec file_spec(file_path, false);
+ return ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
+}
+
+uint32_t
+ModuleList::ResolveSymbolContextsForFileSpec (const FileSpec &file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
+ }
+
+ return sc_list.GetSize();
+}
+
+size_t
+ModuleList::GetIndexForModule (const Module *module) const
+{
+ if (module)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos;
+ collection::const_iterator begin = m_modules.begin();
+ collection::const_iterator end = m_modules.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ if ((*pos).get() == module)
+ return std::distance (begin, pos);
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+static ModuleList &
+GetSharedModuleList ()
+{
+ // NOTE: Intentionally leak the module list so a program doesn't have to
+ // cleanup all modules and object files as it exits. This just wastes time
+ // doing a bunch of cleanup that isn't required.
+ static ModuleList *g_shared_module_list = NULL;
+ if (g_shared_module_list == NULL)
+ g_shared_module_list = new ModuleList(); // <--- Intentional leak!!!
+
+ return *g_shared_module_list;
+}
+
+bool
+ModuleList::ModuleIsInCache (const Module *module_ptr)
+{
+ if (module_ptr)
+ {
+ ModuleList &shared_module_list = GetSharedModuleList ();
+ return shared_module_list.FindModule (module_ptr).get() != NULL;
+ }
+ return false;
+}
+
+size_t
+ModuleList::FindSharedModules (const ModuleSpec &module_spec, ModuleList &matching_module_list)
+{
+ return GetSharedModuleList ().FindModules (module_spec, matching_module_list);
+}
+
+size_t
+ModuleList::RemoveOrphanSharedModules (bool mandatory)
+{
+ return GetSharedModuleList ().RemoveOrphans(mandatory);
+}
+
+Error
+ModuleList::GetSharedModule
+(
+ const ModuleSpec &module_spec,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr,
+ bool always_create
+)
+{
+ ModuleList &shared_module_list = GetSharedModuleList ();
+ Mutex::Locker locker(shared_module_list.m_modules_mutex);
+ char path[PATH_MAX];
+
+ Error error;
+
+ module_sp.reset();
+
+ if (did_create_ptr)
+ *did_create_ptr = false;
+ if (old_module_sp_ptr)
+ old_module_sp_ptr->reset();
+
+ const UUID *uuid_ptr = module_spec.GetUUIDPtr();
+ const FileSpec &module_file_spec = module_spec.GetFileSpec();
+ const ArchSpec &arch = module_spec.GetArchitecture();
+
+ // Make sure no one else can try and get or create a module while this
+ // function is actively working on it by doing an extra lock on the
+ // global mutex list.
+ if (always_create == false)
+ {
+ ModuleList matching_module_list;
+ const size_t num_matching_modules = shared_module_list.FindModules (module_spec, matching_module_list);
+ if (num_matching_modules > 0)
+ {
+ for (size_t module_idx = 0; module_idx < num_matching_modules; ++module_idx)
+ {
+ module_sp = matching_module_list.GetModuleAtIndex(module_idx);
+
+ // Make sure the file for the module hasn't been modified
+ if (module_sp->FileHasChanged())
+ {
+ if (old_module_sp_ptr && !old_module_sp_ptr->get())
+ *old_module_sp_ptr = module_sp;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_MODULES));
+ if (log)
+ log->Printf("module changed: %p, removing from global module list", module_sp.get());
+
+ shared_module_list.Remove (module_sp);
+ module_sp.reset();
+ }
+ else
+ {
+ // The module matches and the module was not modified from
+ // when it was last loaded.
+ return error;
+ }
+ }
+ }
+ }
+
+ if (module_sp)
+ return error;
+ else
+ {
+ module_sp.reset (new Module (module_spec));
+ // Make sure there are a module and an object file since we can specify
+ // a valid file path with an architecture that might not be in that file.
+ // By getting the object file we can guarantee that the architecture matches
+ if (module_sp)
+ {
+ if (module_sp->GetObjectFile())
+ {
+ // If we get in here we got the correct arch, now we just need
+ // to verify the UUID if one was given
+ if (uuid_ptr && *uuid_ptr != module_sp->GetUUID())
+ module_sp.reset();
+ else
+ {
+ if (did_create_ptr)
+ *did_create_ptr = true;
+
+ shared_module_list.ReplaceEquivalent(module_sp);
+ return error;
+ }
+ }
+ else
+ module_sp.reset();
+ }
+ }
+
+ // Either the file didn't exist where at the path, or no path was given, so
+ // we now have to use more extreme measures to try and find the appropriate
+ // module.
+
+ // Fixup the incoming path in case the path points to a valid file, yet
+ // the arch or UUID (if one was passed in) don't match.
+ FileSpec file_spec = Symbols::LocateExecutableObjectFile (module_spec);
+
+ // Don't look for the file if it appears to be the same one we already
+ // checked for above...
+ if (file_spec != module_file_spec)
+ {
+ if (!file_spec.Exists())
+ {
+ file_spec.GetPath(path, sizeof(path));
+ if (path[0] == '\0')
+ module_file_spec.GetPath(path, sizeof(path));
+ if (file_spec.Exists())
+ {
+ std::string uuid_str;
+ if (uuid_ptr && uuid_ptr->IsValid())
+ uuid_str = uuid_ptr->GetAsString();
+
+ if (arch.IsValid())
+ {
+ if (!uuid_str.empty())
+ error.SetErrorStringWithFormat("'%s' does not contain the %s architecture and UUID %s", path, arch.GetArchitectureName(), uuid_str.c_str());
+ else
+ error.SetErrorStringWithFormat("'%s' does not contain the %s architecture.", path, arch.GetArchitectureName());
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' does not exist", path);
+ }
+ if (error.Fail())
+ module_sp.reset();
+ return error;
+ }
+
+
+ // Make sure no one else can try and get or create a module while this
+ // function is actively working on it by doing an extra lock on the
+ // global mutex list.
+ ModuleSpec platform_module_spec(module_spec);
+ platform_module_spec.GetFileSpec() = file_spec;
+ platform_module_spec.GetPlatformFileSpec() = file_spec;
+ ModuleList matching_module_list;
+ if (shared_module_list.FindModules (platform_module_spec, matching_module_list) > 0)
+ {
+ module_sp = matching_module_list.GetModuleAtIndex(0);
+
+ // If we didn't have a UUID in mind when looking for the object file,
+ // then we should make sure the modification time hasn't changed!
+ if (platform_module_spec.GetUUIDPtr() == NULL)
+ {
+ TimeValue file_spec_mod_time(file_spec.GetModificationTime());
+ if (file_spec_mod_time.IsValid())
+ {
+ if (file_spec_mod_time != module_sp->GetModificationTime())
+ {
+ if (old_module_sp_ptr)
+ *old_module_sp_ptr = module_sp;
+ shared_module_list.Remove (module_sp);
+ module_sp.reset();
+ }
+ }
+ }
+ }
+
+ if (module_sp.get() == NULL)
+ {
+ module_sp.reset (new Module (platform_module_spec));
+ // Make sure there are a module and an object file since we can specify
+ // a valid file path with an architecture that might not be in that file.
+ // By getting the object file we can guarantee that the architecture matches
+ if (module_sp && module_sp->GetObjectFile())
+ {
+ if (did_create_ptr)
+ *did_create_ptr = true;
+
+ shared_module_list.ReplaceEquivalent(module_sp);
+ }
+ else
+ {
+ file_spec.GetPath(path, sizeof(path));
+
+ if (file_spec)
+ {
+ if (arch.IsValid())
+ error.SetErrorStringWithFormat("unable to open %s architecture in '%s'", arch.GetArchitectureName(), path);
+ else
+ error.SetErrorStringWithFormat("unable to open '%s'", path);
+ }
+ else
+ {
+ std::string uuid_str;
+ if (uuid_ptr && uuid_ptr->IsValid())
+ uuid_str = uuid_ptr->GetAsString();
+
+ if (!uuid_str.empty())
+ error.SetErrorStringWithFormat("cannot locate a module for UUID '%s'", uuid_str.c_str());
+ else
+ error.SetErrorStringWithFormat("cannot locate a module");
+ }
+ }
+ }
+ }
+
+ return error;
+}
+
+bool
+ModuleList::RemoveSharedModule (lldb::ModuleSP &module_sp)
+{
+ return GetSharedModuleList ().Remove (module_sp);
+}
+
+bool
+ModuleList::RemoveSharedModuleIfOrphaned (const Module *module_ptr)
+{
+ return GetSharedModuleList ().RemoveIfOrphaned (module_ptr);
+}
+
+bool
+ModuleList::LoadScriptingResourcesInTarget (Target *target,
+ std::list<Error>& errors,
+ Stream *feedback_stream,
+ bool continue_on_error)
+{
+ if (!target)
+ return false;
+ Mutex::Locker locker(m_modules_mutex);
+ for (auto module : m_modules)
+ {
+ Error error;
+ if (module)
+ {
+ if (!module->LoadScriptingResourceInTarget(target, error, feedback_stream))
+ {
+ if (error.Fail() && error.AsCString())
+ {
+ error.SetErrorStringWithFormat("unable to load scripting data for module %s - error reported was %s",
+ module->GetFileSpec().GetFileNameStrippingExtension().GetCString(),
+ error.AsCString());
+ errors.push_back(error);
+ }
+ if (!continue_on_error)
+ return false;
+ }
+ }
+ }
+ return errors.size() == 0;
+}
diff --git a/source/Core/Opcode.cpp b/source/Core/Opcode.cpp
new file mode 100644
index 0000000..d987865
--- /dev/null
+++ b/source/Core/Opcode.cpp
@@ -0,0 +1,134 @@
+//===-- Opcode.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/Opcode.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "llvm/ADT/Triple.h"
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/Endian.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+int
+Opcode::Dump (Stream *s, uint32_t min_byte_width)
+{
+ int bytes_written = 0;
+ switch (m_type)
+ {
+ case Opcode::eTypeInvalid:
+ bytes_written = s->PutCString ("<invalid>");
+ break;
+ case Opcode::eType8:
+ bytes_written = s->Printf ("0x%2.2x", m_data.inst8);
+ break;
+ case Opcode::eType16:
+ bytes_written = s->Printf ("0x%4.4x", m_data.inst16);
+ break;
+ case Opcode::eType16_2:
+ case Opcode::eType32:
+ bytes_written = s->Printf ("0x%8.8x", m_data.inst32);
+ break;
+
+ case Opcode::eType64:
+ bytes_written = s->Printf ("0x%16.16" PRIx64, m_data.inst64);
+ break;
+
+ case Opcode::eTypeBytes:
+ {
+ for (uint32_t i=0; i<m_data.inst.length; ++i)
+ {
+ if (i > 0)
+ bytes_written += s->PutChar (' ');
+ bytes_written += s->Printf ("%2.2x", m_data.inst.bytes[i]);
+ }
+ }
+ break;
+ }
+
+ // Add spaces to make sure bytes dispay comes out even in case opcodes
+ // aren't all the same size
+ if (bytes_written < min_byte_width)
+ bytes_written = s->Printf ("%*s", min_byte_width - bytes_written, "");
+ return bytes_written;
+}
+
+lldb::ByteOrder
+Opcode::GetDataByteOrder () const
+{
+ switch (m_type)
+ {
+ case Opcode::eTypeInvalid: break;
+ case Opcode::eType8:
+ case Opcode::eType16:
+ case Opcode::eType16_2:
+ case Opcode::eType32:
+ case Opcode::eType64: return lldb::endian::InlHostByteOrder();
+ case Opcode::eTypeBytes:
+ break;
+ }
+ return eByteOrderInvalid;
+}
+
+uint32_t
+Opcode::GetData (DataExtractor &data) const
+{
+ uint32_t byte_size = GetByteSize ();
+
+ DataBufferSP buffer_sp;
+ if (byte_size > 0)
+ {
+ switch (m_type)
+ {
+ case Opcode::eTypeInvalid:
+ break;
+
+ case Opcode::eType8: buffer_sp.reset (new DataBufferHeap (&m_data.inst8, byte_size)); break;
+ case Opcode::eType16: buffer_sp.reset (new DataBufferHeap (&m_data.inst16, byte_size)); break;
+ case Opcode::eType16_2:
+ {
+ // 32 bit thumb instruction, we need to sizzle this a bit
+ uint8_t buf[4];
+ buf[0] = m_data.inst.bytes[2];
+ buf[1] = m_data.inst.bytes[3];
+ buf[2] = m_data.inst.bytes[0];
+ buf[3] = m_data.inst.bytes[1];
+ buffer_sp.reset (new DataBufferHeap (buf, byte_size));
+ }
+ break;
+ case Opcode::eType32:
+ buffer_sp.reset (new DataBufferHeap (&m_data.inst32, byte_size));
+ break;
+ case Opcode::eType64: buffer_sp.reset (new DataBufferHeap (&m_data.inst64, byte_size)); break;
+ case Opcode::eTypeBytes:buffer_sp.reset (new DataBufferHeap (GetOpcodeBytes(), byte_size)); break;
+ break;
+ }
+ }
+
+ if (buffer_sp)
+ {
+ data.SetByteOrder(GetDataByteOrder());
+ data.SetData (buffer_sp);
+ return byte_size;
+ }
+ data.Clear();
+ return 0;
+}
+
+
+
diff --git a/source/Core/PluginManager.cpp b/source/Core/PluginManager.cpp
new file mode 100644
index 0000000..7a2d377
--- /dev/null
+++ b/source/Core/PluginManager.cpp
@@ -0,0 +1,2064 @@
+//===-- PluginManager.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/lldb-python.h"
+
+#include "lldb/Core/PluginManager.h"
+
+#include <limits.h>
+
+#include <string>
+#include <vector>
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum PluginAction
+{
+ ePluginRegisterInstance,
+ ePluginUnregisterInstance,
+ ePluginGetInstanceAtIndex
+};
+
+
+typedef bool (*PluginInitCallback) (void);
+typedef void (*PluginTermCallback) (void);
+
+struct PluginInfo
+{
+ void *plugin_handle;
+ PluginInitCallback plugin_init_callback;
+ PluginTermCallback plugin_term_callback;
+};
+
+typedef std::map<FileSpec, PluginInfo> PluginTerminateMap;
+
+static Mutex &
+GetPluginMapMutex ()
+{
+ static Mutex g_plugin_map_mutex (Mutex::eMutexTypeRecursive);
+ return g_plugin_map_mutex;
+}
+
+static PluginTerminateMap &
+GetPluginMap ()
+{
+ static PluginTerminateMap g_plugin_map;
+ return g_plugin_map;
+}
+
+static bool
+PluginIsLoaded (const FileSpec &plugin_file_spec)
+{
+ Mutex::Locker locker (GetPluginMapMutex ());
+ PluginTerminateMap &plugin_map = GetPluginMap ();
+ return plugin_map.find (plugin_file_spec) != plugin_map.end();
+}
+
+static void
+SetPluginInfo (const FileSpec &plugin_file_spec, const PluginInfo &plugin_info)
+{
+ Mutex::Locker locker (GetPluginMapMutex ());
+ PluginTerminateMap &plugin_map = GetPluginMap ();
+ assert (plugin_map.find (plugin_file_spec) == plugin_map.end());
+ plugin_map[plugin_file_spec] = plugin_info;
+}
+
+
+static FileSpec::EnumerateDirectoryResult
+LoadPluginCallback
+(
+ void *baton,
+ FileSpec::FileType file_type,
+ const FileSpec &file_spec
+)
+{
+// PluginManager *plugin_manager = (PluginManager *)baton;
+ Error error;
+
+ // If we have a regular file, a symbolic link or unknown file type, try
+ // and process the file. We must handle unknown as sometimes the directory
+ // enumeration might be enumerating a file system that doesn't have correct
+ // file type information.
+ if (file_type == FileSpec::eFileTypeRegular ||
+ file_type == FileSpec::eFileTypeSymbolicLink ||
+ file_type == FileSpec::eFileTypeUnknown )
+ {
+ FileSpec plugin_file_spec (file_spec);
+ plugin_file_spec.ResolvePath();
+
+ if (PluginIsLoaded (plugin_file_spec))
+ return FileSpec::eEnumerateDirectoryResultNext;
+ else
+ {
+ PluginInfo plugin_info = { NULL, NULL, NULL };
+ uint32_t flags = Host::eDynamicLibraryOpenOptionLazy |
+ Host::eDynamicLibraryOpenOptionLocal |
+ Host::eDynamicLibraryOpenOptionLimitGetSymbol;
+
+ plugin_info.plugin_handle = Host::DynamicLibraryOpen (plugin_file_spec, flags, error);
+ if (plugin_info.plugin_handle)
+ {
+ bool success = false;
+ plugin_info.plugin_init_callback = (PluginInitCallback)Host::DynamicLibraryGetSymbol (plugin_info.plugin_handle, "LLDBPluginInitialize", error);
+ if (plugin_info.plugin_init_callback)
+ {
+ // Call the plug-in "bool LLDBPluginInitialize(void)" function
+ success = plugin_info.plugin_init_callback();
+ }
+
+ if (success)
+ {
+ // It is ok for the "LLDBPluginTerminate" symbol to be NULL
+ plugin_info.plugin_term_callback = (PluginTermCallback)Host::DynamicLibraryGetSymbol (plugin_info.plugin_handle, "LLDBPluginTerminate", error);
+ }
+ else
+ {
+ // The initialize function returned FALSE which means the
+ // plug-in might not be compatible, or might be too new or
+ // too old, or might not want to run on this machine.
+ Host::DynamicLibraryClose (plugin_info.plugin_handle);
+ plugin_info.plugin_handle = NULL;
+ plugin_info.plugin_init_callback = NULL;
+ }
+
+ // Regardless of success or failure, cache the plug-in load
+ // in our plug-in info so we don't try to load it again and
+ // again.
+ SetPluginInfo (plugin_file_spec, plugin_info);
+
+ return FileSpec::eEnumerateDirectoryResultNext;
+ }
+ }
+ }
+
+ if (file_type == FileSpec::eFileTypeUnknown ||
+ file_type == FileSpec::eFileTypeDirectory ||
+ file_type == FileSpec::eFileTypeSymbolicLink )
+ {
+ // Try and recurse into anything that a directory or symbolic link.
+ // We must also do this for unknown as sometimes the directory enumeration
+ // might be enurating a file system that doesn't have correct file type
+ // information.
+ return FileSpec::eEnumerateDirectoryResultEnter;
+ }
+
+ return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+
+void
+PluginManager::Initialize ()
+{
+#if 1
+ FileSpec dir_spec;
+ const bool find_directories = true;
+ const bool find_files = true;
+ const bool find_other = true;
+ char dir_path[PATH_MAX];
+ if (Host::GetLLDBPath (ePathTypeLLDBSystemPlugins, dir_spec))
+ {
+ if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path)))
+ {
+ FileSpec::EnumerateDirectory (dir_path,
+ find_directories,
+ find_files,
+ find_other,
+ LoadPluginCallback,
+ NULL);
+ }
+ }
+
+ if (Host::GetLLDBPath (ePathTypeLLDBUserPlugins, dir_spec))
+ {
+ if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path)))
+ {
+ FileSpec::EnumerateDirectory (dir_path,
+ find_directories,
+ find_files,
+ find_other,
+ LoadPluginCallback,
+ NULL);
+ }
+ }
+#endif
+}
+
+void
+PluginManager::Terminate ()
+{
+ Mutex::Locker locker (GetPluginMapMutex ());
+ PluginTerminateMap &plugin_map = GetPluginMap ();
+
+ PluginTerminateMap::const_iterator pos, end = plugin_map.end();
+ for (pos = plugin_map.begin(); pos != end; ++pos)
+ {
+ // Call the plug-in "void LLDBPluginTerminate (void)" function if there
+ // is one (if the symbol was not NULL).
+ if (pos->second.plugin_handle)
+ {
+ if (pos->second.plugin_term_callback)
+ pos->second.plugin_term_callback();
+ Host::DynamicLibraryClose (pos->second.plugin_handle);
+ }
+ }
+ plugin_map.clear();
+}
+
+
+#pragma mark ABI
+
+
+struct ABIInstance
+{
+ ABIInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ ABICreateInstance create_callback;
+};
+
+typedef std::vector<ABIInstance> ABIInstances;
+
+static Mutex &
+GetABIInstancesMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static ABIInstances &
+GetABIInstances ()
+{
+ static ABIInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ ABICreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ ABIInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetABIInstancesMutex ());
+ GetABIInstances ().push_back (instance);
+ return true;
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ABICreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetABIInstancesMutex ());
+ ABIInstances &instances = GetABIInstances ();
+
+ ABIInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ABICreateInstance
+PluginManager::GetABICreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetABIInstancesMutex ());
+ ABIInstances &instances = GetABIInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+ABICreateInstance
+PluginManager::GetABICreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetABIInstancesMutex ());
+ ABIInstances &instances = GetABIInstances ();
+
+ ABIInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+#pragma mark Disassembler
+
+
+struct DisassemblerInstance
+{
+ DisassemblerInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ DisassemblerCreateInstance create_callback;
+};
+
+typedef std::vector<DisassemblerInstance> DisassemblerInstances;
+
+static Mutex &
+GetDisassemblerMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static DisassemblerInstances &
+GetDisassemblerInstances ()
+{
+ static DisassemblerInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ DisassemblerCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ DisassemblerInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetDisassemblerMutex ());
+ GetDisassemblerInstances ().push_back (instance);
+ return true;
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (DisassemblerCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetDisassemblerMutex ());
+ DisassemblerInstances &instances = GetDisassemblerInstances ();
+
+ DisassemblerInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+DisassemblerCreateInstance
+PluginManager::GetDisassemblerCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetDisassemblerMutex ());
+ DisassemblerInstances &instances = GetDisassemblerInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+DisassemblerCreateInstance
+PluginManager::GetDisassemblerCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetDisassemblerMutex ());
+ DisassemblerInstances &instances = GetDisassemblerInstances ();
+
+ DisassemblerInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+#pragma mark DynamicLoader
+
+
+struct DynamicLoaderInstance
+{
+ DynamicLoaderInstance() :
+ name(),
+ description(),
+ create_callback(NULL),
+ debugger_init_callback (NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ DynamicLoaderCreateInstance create_callback;
+ DebuggerInitializeCallback debugger_init_callback;
+};
+
+typedef std::vector<DynamicLoaderInstance> DynamicLoaderInstances;
+
+
+static Mutex &
+GetDynamicLoaderMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static DynamicLoaderInstances &
+GetDynamicLoaderInstances ()
+{
+ static DynamicLoaderInstances g_instances;
+ return g_instances;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ DynamicLoaderCreateInstance create_callback,
+ DebuggerInitializeCallback debugger_init_callback
+)
+{
+ if (create_callback)
+ {
+ DynamicLoaderInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ instance.debugger_init_callback = debugger_init_callback;
+ Mutex::Locker locker (GetDynamicLoaderMutex ());
+ GetDynamicLoaderInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (DynamicLoaderCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetDynamicLoaderMutex ());
+ DynamicLoaderInstances &instances = GetDynamicLoaderInstances ();
+
+ DynamicLoaderInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+DynamicLoaderCreateInstance
+PluginManager::GetDynamicLoaderCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetDynamicLoaderMutex ());
+ DynamicLoaderInstances &instances = GetDynamicLoaderInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+DynamicLoaderCreateInstance
+PluginManager::GetDynamicLoaderCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetDynamicLoaderMutex ());
+ DynamicLoaderInstances &instances = GetDynamicLoaderInstances ();
+
+ DynamicLoaderInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark EmulateInstruction
+
+
+struct EmulateInstructionInstance
+{
+ EmulateInstructionInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ EmulateInstructionCreateInstance create_callback;
+};
+
+typedef std::vector<EmulateInstructionInstance> EmulateInstructionInstances;
+
+static Mutex &
+GetEmulateInstructionMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static EmulateInstructionInstances &
+GetEmulateInstructionInstances ()
+{
+ static EmulateInstructionInstances g_instances;
+ return g_instances;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ EmulateInstructionCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ EmulateInstructionInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetEmulateInstructionMutex ());
+ GetEmulateInstructionInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (EmulateInstructionCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetEmulateInstructionMutex ());
+ EmulateInstructionInstances &instances = GetEmulateInstructionInstances ();
+
+ EmulateInstructionInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+EmulateInstructionCreateInstance
+PluginManager::GetEmulateInstructionCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetEmulateInstructionMutex ());
+ EmulateInstructionInstances &instances = GetEmulateInstructionInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+EmulateInstructionCreateInstance
+PluginManager::GetEmulateInstructionCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetEmulateInstructionMutex ());
+ EmulateInstructionInstances &instances = GetEmulateInstructionInstances ();
+
+ EmulateInstructionInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+#pragma mark OperatingSystem
+
+
+struct OperatingSystemInstance
+{
+ OperatingSystemInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ OperatingSystemCreateInstance create_callback;
+};
+
+typedef std::vector<OperatingSystemInstance> OperatingSystemInstances;
+
+static Mutex &
+GetOperatingSystemMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static OperatingSystemInstances &
+GetOperatingSystemInstances ()
+{
+ static OperatingSystemInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin (const ConstString &name,
+ const char *description,
+ OperatingSystemCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ OperatingSystemInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetOperatingSystemMutex ());
+ GetOperatingSystemInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (OperatingSystemCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetOperatingSystemMutex ());
+ OperatingSystemInstances &instances = GetOperatingSystemInstances ();
+
+ OperatingSystemInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+OperatingSystemCreateInstance
+PluginManager::GetOperatingSystemCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetOperatingSystemMutex ());
+ OperatingSystemInstances &instances = GetOperatingSystemInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+OperatingSystemCreateInstance
+PluginManager::GetOperatingSystemCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetOperatingSystemMutex ());
+ OperatingSystemInstances &instances = GetOperatingSystemInstances ();
+
+ OperatingSystemInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+#pragma mark LanguageRuntime
+
+
+struct LanguageRuntimeInstance
+{
+ LanguageRuntimeInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ LanguageRuntimeCreateInstance create_callback;
+};
+
+typedef std::vector<LanguageRuntimeInstance> LanguageRuntimeInstances;
+
+static Mutex &
+GetLanguageRuntimeMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static LanguageRuntimeInstances &
+GetLanguageRuntimeInstances ()
+{
+ static LanguageRuntimeInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ LanguageRuntimeCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ LanguageRuntimeInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetLanguageRuntimeMutex ());
+ GetLanguageRuntimeInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (LanguageRuntimeCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetLanguageRuntimeMutex ());
+ LanguageRuntimeInstances &instances = GetLanguageRuntimeInstances ();
+
+ LanguageRuntimeInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+LanguageRuntimeCreateInstance
+PluginManager::GetLanguageRuntimeCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetLanguageRuntimeMutex ());
+ LanguageRuntimeInstances &instances = GetLanguageRuntimeInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+LanguageRuntimeCreateInstance
+PluginManager::GetLanguageRuntimeCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetLanguageRuntimeMutex ());
+ LanguageRuntimeInstances &instances = GetLanguageRuntimeInstances ();
+
+ LanguageRuntimeInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark ObjectFile
+
+struct ObjectFileInstance
+{
+ ObjectFileInstance() :
+ name(),
+ description(),
+ create_callback(NULL),
+ create_memory_callback (NULL),
+ get_module_specifications (NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ ObjectFileCreateInstance create_callback;
+ ObjectFileCreateMemoryInstance create_memory_callback;
+ ObjectFileGetModuleSpecifications get_module_specifications;
+};
+
+typedef std::vector<ObjectFileInstance> ObjectFileInstances;
+
+static Mutex &
+GetObjectFileMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static ObjectFileInstances &
+GetObjectFileInstances ()
+{
+ static ObjectFileInstances g_instances;
+ return g_instances;
+}
+
+
+bool
+PluginManager::RegisterPlugin (const ConstString &name,
+ const char *description,
+ ObjectFileCreateInstance create_callback,
+ ObjectFileCreateMemoryInstance create_memory_callback,
+ ObjectFileGetModuleSpecifications get_module_specifications)
+{
+ if (create_callback)
+ {
+ ObjectFileInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ instance.create_memory_callback = create_memory_callback;
+ instance.get_module_specifications = get_module_specifications;
+ Mutex::Locker locker (GetObjectFileMutex ());
+ GetObjectFileInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ObjectFileCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetObjectFileMutex ());
+ ObjectFileInstances &instances = GetObjectFileInstances ();
+
+ ObjectFileInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ObjectFileCreateInstance
+PluginManager::GetObjectFileCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetObjectFileMutex ());
+ ObjectFileInstances &instances = GetObjectFileInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+
+ObjectFileCreateMemoryInstance
+PluginManager::GetObjectFileCreateMemoryCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetObjectFileMutex ());
+ ObjectFileInstances &instances = GetObjectFileInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_memory_callback;
+ return NULL;
+}
+
+ObjectFileGetModuleSpecifications
+PluginManager::GetObjectFileGetModuleSpecificationsCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetObjectFileMutex ());
+ ObjectFileInstances &instances = GetObjectFileInstances ();
+ if (idx < instances.size())
+ return instances[idx].get_module_specifications;
+ return NULL;
+}
+
+ObjectFileCreateInstance
+PluginManager::GetObjectFileCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetObjectFileMutex ());
+ ObjectFileInstances &instances = GetObjectFileInstances ();
+
+ ObjectFileInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+ObjectFileCreateMemoryInstance
+PluginManager::GetObjectFileCreateMemoryCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetObjectFileMutex ());
+ ObjectFileInstances &instances = GetObjectFileInstances ();
+
+ ObjectFileInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_memory_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+#pragma mark ObjectContainer
+
+struct ObjectContainerInstance
+{
+ ObjectContainerInstance() :
+ name(),
+ description(),
+ create_callback (NULL),
+ get_module_specifications (NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ ObjectContainerCreateInstance create_callback;
+ ObjectFileGetModuleSpecifications get_module_specifications;
+
+};
+
+typedef std::vector<ObjectContainerInstance> ObjectContainerInstances;
+
+static Mutex &
+GetObjectContainerMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static ObjectContainerInstances &
+GetObjectContainerInstances ()
+{
+ static ObjectContainerInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin (const ConstString &name,
+ const char *description,
+ ObjectContainerCreateInstance create_callback,
+ ObjectFileGetModuleSpecifications get_module_specifications)
+{
+ if (create_callback)
+ {
+ ObjectContainerInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ instance.get_module_specifications = get_module_specifications;
+ Mutex::Locker locker (GetObjectContainerMutex ());
+ GetObjectContainerInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ObjectContainerCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetObjectContainerMutex ());
+ ObjectContainerInstances &instances = GetObjectContainerInstances ();
+
+ ObjectContainerInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ObjectContainerCreateInstance
+PluginManager::GetObjectContainerCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetObjectContainerMutex ());
+ ObjectContainerInstances &instances = GetObjectContainerInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+ObjectContainerCreateInstance
+PluginManager::GetObjectContainerCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetObjectContainerMutex ());
+ ObjectContainerInstances &instances = GetObjectContainerInstances ();
+
+ ObjectContainerInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+ObjectFileGetModuleSpecifications
+PluginManager::GetObjectContainerGetModuleSpecificationsCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetObjectContainerMutex ());
+ ObjectContainerInstances &instances = GetObjectContainerInstances ();
+ if (idx < instances.size())
+ return instances[idx].get_module_specifications;
+ return NULL;
+}
+
+#pragma mark LogChannel
+
+struct LogInstance
+{
+ LogInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ LogChannelCreateInstance create_callback;
+};
+
+typedef std::vector<LogInstance> LogInstances;
+
+static Mutex &
+GetLogMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static LogInstances &
+GetLogInstances ()
+{
+ static LogInstances g_instances;
+ return g_instances;
+}
+
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ LogChannelCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ LogInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetLogMutex ());
+ GetLogInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (LogChannelCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetLogMutex ());
+ LogInstances &instances = GetLogInstances ();
+
+ LogInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+const char *
+PluginManager::GetLogChannelCreateNameAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetLogMutex ());
+ LogInstances &instances = GetLogInstances ();
+ if (idx < instances.size())
+ return instances[idx].name.GetCString();
+ return NULL;
+}
+
+
+LogChannelCreateInstance
+PluginManager::GetLogChannelCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetLogMutex ());
+ LogInstances &instances = GetLogInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+LogChannelCreateInstance
+PluginManager::GetLogChannelCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetLogMutex ());
+ LogInstances &instances = GetLogInstances ();
+
+ LogInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark Platform
+
+struct PlatformInstance
+{
+ PlatformInstance() :
+ name(),
+ description(),
+ create_callback(NULL),
+ debugger_init_callback (NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ PlatformCreateInstance create_callback;
+ DebuggerInitializeCallback debugger_init_callback;
+};
+
+typedef std::vector<PlatformInstance> PlatformInstances;
+
+static Mutex &
+GetPlatformInstancesMutex ()
+{
+ static Mutex g_platform_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_platform_instances_mutex;
+}
+
+static PlatformInstances &
+GetPlatformInstances ()
+{
+ static PlatformInstances g_platform_instances;
+ return g_platform_instances;
+}
+
+
+bool
+PluginManager::RegisterPlugin (const ConstString &name,
+ const char *description,
+ PlatformCreateInstance create_callback,
+ DebuggerInitializeCallback debugger_init_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+
+ PlatformInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ instance.debugger_init_callback = debugger_init_callback;
+ GetPlatformInstances ().push_back (instance);
+ return true;
+ }
+ return false;
+}
+
+
+const char *
+PluginManager::GetPlatformPluginNameAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+ if (idx < instances.size())
+ return instances[idx].name.GetCString();
+ return NULL;
+}
+
+const char *
+PluginManager::GetPlatformPluginDescriptionAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+ if (idx < instances.size())
+ return instances[idx].description.c_str();
+ return NULL;
+}
+
+bool
+PluginManager::UnregisterPlugin (PlatformCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+
+ PlatformInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+PlatformCreateInstance
+PluginManager::GetPlatformCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+PlatformCreateInstance
+PluginManager::GetPlatformCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+
+ PlatformInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+size_t
+PluginManager::AutoCompletePlatformName (const char *name, StringList &matches)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+ llvm::StringRef name_sref(name);
+
+ PlatformInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ llvm::StringRef plugin_name (pos->name.GetCString());
+ if (plugin_name.startswith(name_sref))
+ matches.AppendString (plugin_name.data());
+ }
+ }
+ return matches.GetSize();
+}
+#pragma mark Process
+
+struct ProcessInstance
+{
+ ProcessInstance() :
+ name(),
+ description(),
+ create_callback(NULL),
+ debugger_init_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ ProcessCreateInstance create_callback;
+ DebuggerInitializeCallback debugger_init_callback;
+};
+
+typedef std::vector<ProcessInstance> ProcessInstances;
+
+static Mutex &
+GetProcessMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static ProcessInstances &
+GetProcessInstances ()
+{
+ static ProcessInstances g_instances;
+ return g_instances;
+}
+
+
+bool
+PluginManager::RegisterPlugin (const ConstString &name,
+ const char *description,
+ ProcessCreateInstance create_callback,
+ DebuggerInitializeCallback debugger_init_callback)
+{
+ if (create_callback)
+ {
+ ProcessInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ instance.debugger_init_callback = debugger_init_callback;
+ Mutex::Locker locker (GetProcessMutex ());
+ GetProcessInstances ().push_back (instance);
+ }
+ return false;
+}
+
+const char *
+PluginManager::GetProcessPluginNameAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetProcessMutex ());
+ ProcessInstances &instances = GetProcessInstances ();
+ if (idx < instances.size())
+ return instances[idx].name.GetCString();
+ return NULL;
+}
+
+const char *
+PluginManager::GetProcessPluginDescriptionAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetProcessMutex ());
+ ProcessInstances &instances = GetProcessInstances ();
+ if (idx < instances.size())
+ return instances[idx].description.c_str();
+ return NULL;
+}
+
+bool
+PluginManager::UnregisterPlugin (ProcessCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetProcessMutex ());
+ ProcessInstances &instances = GetProcessInstances ();
+
+ ProcessInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ProcessCreateInstance
+PluginManager::GetProcessCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetProcessMutex ());
+ ProcessInstances &instances = GetProcessInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+
+ProcessCreateInstance
+PluginManager::GetProcessCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetProcessMutex ());
+ ProcessInstances &instances = GetProcessInstances ();
+
+ ProcessInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark SymbolFile
+
+struct SymbolFileInstance
+{
+ SymbolFileInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ SymbolFileCreateInstance create_callback;
+};
+
+typedef std::vector<SymbolFileInstance> SymbolFileInstances;
+
+static Mutex &
+GetSymbolFileMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static SymbolFileInstances &
+GetSymbolFileInstances ()
+{
+ static SymbolFileInstances g_instances;
+ return g_instances;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ SymbolFileCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ SymbolFileInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetSymbolFileMutex ());
+ GetSymbolFileInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (SymbolFileCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetSymbolFileMutex ());
+ SymbolFileInstances &instances = GetSymbolFileInstances ();
+
+ SymbolFileInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+SymbolFileCreateInstance
+PluginManager::GetSymbolFileCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetSymbolFileMutex ());
+ SymbolFileInstances &instances = GetSymbolFileInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+SymbolFileCreateInstance
+PluginManager::GetSymbolFileCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetSymbolFileMutex ());
+ SymbolFileInstances &instances = GetSymbolFileInstances ();
+
+ SymbolFileInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+#pragma mark SymbolVendor
+
+struct SymbolVendorInstance
+{
+ SymbolVendorInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ SymbolVendorCreateInstance create_callback;
+};
+
+typedef std::vector<SymbolVendorInstance> SymbolVendorInstances;
+
+static Mutex &
+GetSymbolVendorMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static SymbolVendorInstances &
+GetSymbolVendorInstances ()
+{
+ static SymbolVendorInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ SymbolVendorCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ SymbolVendorInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetSymbolVendorMutex ());
+ GetSymbolVendorInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (SymbolVendorCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetSymbolVendorMutex ());
+ SymbolVendorInstances &instances = GetSymbolVendorInstances ();
+
+ SymbolVendorInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+SymbolVendorCreateInstance
+PluginManager::GetSymbolVendorCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetSymbolVendorMutex ());
+ SymbolVendorInstances &instances = GetSymbolVendorInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+
+SymbolVendorCreateInstance
+PluginManager::GetSymbolVendorCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetSymbolVendorMutex ());
+ SymbolVendorInstances &instances = GetSymbolVendorInstances ();
+
+ SymbolVendorInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+#pragma mark UnwindAssembly
+
+struct UnwindAssemblyInstance
+{
+ UnwindAssemblyInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ UnwindAssemblyCreateInstance create_callback;
+};
+
+typedef std::vector<UnwindAssemblyInstance> UnwindAssemblyInstances;
+
+static Mutex &
+GetUnwindAssemblyMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static UnwindAssemblyInstances &
+GetUnwindAssemblyInstances ()
+{
+ static UnwindAssemblyInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ UnwindAssemblyCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ UnwindAssemblyInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetUnwindAssemblyMutex ());
+ GetUnwindAssemblyInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (UnwindAssemblyCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetUnwindAssemblyMutex ());
+ UnwindAssemblyInstances &instances = GetUnwindAssemblyInstances ();
+
+ UnwindAssemblyInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+UnwindAssemblyCreateInstance
+PluginManager::GetUnwindAssemblyCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetUnwindAssemblyMutex ());
+ UnwindAssemblyInstances &instances = GetUnwindAssemblyInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+
+UnwindAssemblyCreateInstance
+PluginManager::GetUnwindAssemblyCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetUnwindAssemblyMutex ());
+ UnwindAssemblyInstances &instances = GetUnwindAssemblyInstances ();
+
+ UnwindAssemblyInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+void
+PluginManager::DebuggerInitialize (Debugger &debugger)
+{
+ // Initialize the DynamicLoader plugins
+ {
+ Mutex::Locker locker (GetDynamicLoaderMutex ());
+ DynamicLoaderInstances &instances = GetDynamicLoaderInstances ();
+
+ DynamicLoaderInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->debugger_init_callback)
+ pos->debugger_init_callback (debugger);
+ }
+ }
+
+ // Initialize the Platform plugins
+ {
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+
+ PlatformInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->debugger_init_callback)
+ pos->debugger_init_callback (debugger);
+ }
+ }
+
+ // Initialize the Process plugins
+ {
+ Mutex::Locker locker (GetProcessMutex());
+ ProcessInstances &instances = GetProcessInstances();
+
+ ProcessInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->debugger_init_callback)
+ pos->debugger_init_callback (debugger);
+ }
+ }
+
+}
+
+// This is the preferred new way to register plugin specific settings. e.g.
+// This will put a plugin's settings under e.g. "plugin.<plugin_type_name>.<plugin_type_desc>.SETTINGNAME".
+static lldb::OptionValuePropertiesSP
+GetDebuggerPropertyForPlugins (Debugger &debugger,
+ const ConstString &plugin_type_name,
+ const ConstString &plugin_type_desc,
+ bool can_create)
+{
+ lldb::OptionValuePropertiesSP parent_properties_sp (debugger.GetValueProperties());
+ if (parent_properties_sp)
+ {
+ static ConstString g_property_name("plugin");
+
+ OptionValuePropertiesSP plugin_properties_sp = parent_properties_sp->GetSubProperty (NULL, g_property_name);
+ if (!plugin_properties_sp && can_create)
+ {
+ plugin_properties_sp.reset (new OptionValueProperties (g_property_name));
+ parent_properties_sp->AppendProperty (g_property_name,
+ ConstString("Settings specify to plugins."),
+ true,
+ plugin_properties_sp);
+ }
+
+ if (plugin_properties_sp)
+ {
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp = plugin_properties_sp->GetSubProperty (NULL, plugin_type_name);
+ if (!plugin_type_properties_sp && can_create)
+ {
+ plugin_type_properties_sp.reset (new OptionValueProperties (plugin_type_name));
+ plugin_properties_sp->AppendProperty (plugin_type_name,
+ plugin_type_desc,
+ true,
+ plugin_type_properties_sp);
+ }
+ return plugin_type_properties_sp;
+ }
+ }
+ return lldb::OptionValuePropertiesSP();
+}
+
+// This is deprecated way to register plugin specific settings. e.g.
+// "<plugin_type_name>.plugin.<plugin_type_desc>.SETTINGNAME"
+// and Platform generic settings would be under "platform.SETTINGNAME".
+static lldb::OptionValuePropertiesSP
+GetDebuggerPropertyForPluginsOldStyle (Debugger &debugger,
+ const ConstString &plugin_type_name,
+ const ConstString &plugin_type_desc,
+ bool can_create)
+{
+ static ConstString g_property_name("plugin");
+ lldb::OptionValuePropertiesSP parent_properties_sp (debugger.GetValueProperties());
+ if (parent_properties_sp)
+ {
+ OptionValuePropertiesSP plugin_properties_sp = parent_properties_sp->GetSubProperty (NULL, plugin_type_name);
+ if (!plugin_properties_sp && can_create)
+ {
+ plugin_properties_sp.reset (new OptionValueProperties (plugin_type_name));
+ parent_properties_sp->AppendProperty (plugin_type_name,
+ plugin_type_desc,
+ true,
+ plugin_properties_sp);
+ }
+
+ if (plugin_properties_sp)
+ {
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp = plugin_properties_sp->GetSubProperty (NULL, g_property_name);
+ if (!plugin_type_properties_sp && can_create)
+ {
+ plugin_type_properties_sp.reset (new OptionValueProperties (g_property_name));
+ plugin_properties_sp->AppendProperty (g_property_name,
+ ConstString("Settings specific to plugins"),
+ true,
+ plugin_type_properties_sp);
+ }
+ return plugin_type_properties_sp;
+ }
+ }
+ return lldb::OptionValuePropertiesSP();
+}
+
+
+lldb::OptionValuePropertiesSP
+PluginManager::GetSettingForDynamicLoaderPlugin (Debugger &debugger, const ConstString &setting_name)
+{
+ lldb::OptionValuePropertiesSP properties_sp;
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger,
+ ConstString("dynamic-loader"),
+ ConstString(), // not creating to so we don't need the description
+ false));
+ if (plugin_type_properties_sp)
+ properties_sp = plugin_type_properties_sp->GetSubProperty (NULL, setting_name);
+ return properties_sp;
+}
+
+bool
+PluginManager::CreateSettingForDynamicLoaderPlugin (Debugger &debugger,
+ const lldb::OptionValuePropertiesSP &properties_sp,
+ const ConstString &description,
+ bool is_global_property)
+{
+ if (properties_sp)
+ {
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger,
+ ConstString("dynamic-loader"),
+ ConstString("Settings for dynamic loader plug-ins"),
+ true));
+ if (plugin_type_properties_sp)
+ {
+ plugin_type_properties_sp->AppendProperty (properties_sp->GetName(),
+ description,
+ is_global_property,
+ properties_sp);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+lldb::OptionValuePropertiesSP
+PluginManager::GetSettingForPlatformPlugin (Debugger &debugger, const ConstString &setting_name)
+{
+ lldb::OptionValuePropertiesSP properties_sp;
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPluginsOldStyle (debugger,
+ ConstString("platform"),
+ ConstString(), // not creating to so we don't need the description
+ false));
+ if (plugin_type_properties_sp)
+ properties_sp = plugin_type_properties_sp->GetSubProperty (NULL, setting_name);
+ return properties_sp;
+}
+
+bool
+PluginManager::CreateSettingForPlatformPlugin (Debugger &debugger,
+ const lldb::OptionValuePropertiesSP &properties_sp,
+ const ConstString &description,
+ bool is_global_property)
+{
+ if (properties_sp)
+ {
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPluginsOldStyle (debugger,
+ ConstString("platform"),
+ ConstString("Settings for platform plug-ins"),
+ true));
+ if (plugin_type_properties_sp)
+ {
+ plugin_type_properties_sp->AppendProperty (properties_sp->GetName(),
+ description,
+ is_global_property,
+ properties_sp);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+lldb::OptionValuePropertiesSP
+PluginManager::GetSettingForProcessPlugin (Debugger &debugger, const ConstString &setting_name)
+{
+ lldb::OptionValuePropertiesSP properties_sp;
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger,
+ ConstString("process"),
+ ConstString(), // not creating to so we don't need the description
+ false));
+ if (plugin_type_properties_sp)
+ properties_sp = plugin_type_properties_sp->GetSubProperty (NULL, setting_name);
+ return properties_sp;
+}
+
+bool
+PluginManager::CreateSettingForProcessPlugin (Debugger &debugger,
+ const lldb::OptionValuePropertiesSP &properties_sp,
+ const ConstString &description,
+ bool is_global_property)
+{
+ if (properties_sp)
+ {
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger,
+ ConstString("process"),
+ ConstString("Settings for process plug-ins"),
+ true));
+ if (plugin_type_properties_sp)
+ {
+ plugin_type_properties_sp->AppendProperty (properties_sp->GetName(),
+ description,
+ is_global_property,
+ properties_sp);
+ return true;
+ }
+ }
+ return false;
+}
+
diff --git a/source/Core/RegisterValue.cpp b/source/Core/RegisterValue.cpp
new file mode 100644
index 0000000..91f5bea
--- /dev/null
+++ b/source/Core/RegisterValue.cpp
@@ -0,0 +1,1272 @@
+//===-- RegisterValue.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/RegisterValue.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+bool
+RegisterValue::Dump (Stream *s,
+ const RegisterInfo *reg_info,
+ bool prefix_with_name,
+ bool prefix_with_alt_name,
+ Format format,
+ uint32_t reg_name_right_align_at) const
+{
+ DataExtractor data;
+ if (GetData (data))
+ {
+ bool name_printed = false;
+ // For simplicity, alignment of the register name printing applies only
+ // in the most common case where:
+ //
+ // prefix_with_name^prefix_with_alt_name is true
+ //
+ StreamString format_string;
+ if (reg_name_right_align_at && (prefix_with_name^prefix_with_alt_name))
+ format_string.Printf("%%%us", reg_name_right_align_at);
+ else
+ format_string.Printf("%%s");
+ const char *fmt = format_string.GetData();
+ if (prefix_with_name)
+ {
+ if (reg_info->name)
+ {
+ s->Printf (fmt, reg_info->name);
+ name_printed = true;
+ }
+ else if (reg_info->alt_name)
+ {
+ s->Printf (fmt, reg_info->alt_name);
+ prefix_with_alt_name = false;
+ name_printed = true;
+ }
+ }
+ if (prefix_with_alt_name)
+ {
+ if (name_printed)
+ s->PutChar ('/');
+ if (reg_info->alt_name)
+ {
+ s->Printf (fmt, reg_info->alt_name);
+ name_printed = true;
+ }
+ else if (!name_printed)
+ {
+ // No alternate name but we were asked to display a name, so show the main name
+ s->Printf (fmt, reg_info->name);
+ name_printed = true;
+ }
+ }
+ if (name_printed)
+ s->PutCString (" = ");
+
+ if (format == eFormatDefault)
+ format = reg_info->format;
+
+ data.Dump (s,
+ 0, // Offset in "data"
+ format, // Format to use when dumping
+ reg_info->byte_size, // item_byte_size
+ 1, // item_count
+ UINT32_MAX, // num_per_line
+ LLDB_INVALID_ADDRESS, // base_addr
+ 0, // item_bit_size
+ 0); // item_bit_offset
+ return true;
+ }
+ return false;
+}
+
+
+bool
+RegisterValue::GetData (DataExtractor &data) const
+{
+ return data.SetData(GetBytes(), GetByteSize(), GetByteOrder()) > 0;
+}
+
+
+uint32_t
+RegisterValue::GetAsMemoryData (const RegisterInfo *reg_info,
+ void *dst,
+ uint32_t dst_len,
+ lldb::ByteOrder dst_byte_order,
+ Error &error) const
+{
+ if (reg_info == NULL)
+ {
+ error.SetErrorString ("invalid register info argument.");
+ return 0;
+ }
+
+ // ReadRegister should have already been called on tgus object prior to
+ // calling this.
+ if (GetType() == eTypeInvalid)
+ {
+ // No value has been read into this object...
+ error.SetErrorStringWithFormat("invalid register value type for register %s", reg_info->name);
+ return 0;
+ }
+
+ if (dst_len > kMaxRegisterByteSize)
+ {
+ error.SetErrorString ("destination is too big");
+ return 0;
+ }
+
+ const uint32_t src_len = reg_info->byte_size;
+
+ // Extract the register data into a data extractor
+ DataExtractor reg_data;
+ if (!GetData(reg_data))
+ {
+ error.SetErrorString ("invalid register value to copy into");
+ return 0;
+ }
+
+ // Prepare a memory buffer that contains some or all of the register value
+ const uint32_t bytes_copied = reg_data.CopyByteOrderedData (0, // src offset
+ src_len, // src length
+ dst, // dst buffer
+ dst_len, // dst length
+ dst_byte_order); // dst byte order
+ if (bytes_copied == 0)
+ error.SetErrorStringWithFormat("failed to copy data for register write of %s", reg_info->name);
+
+ return bytes_copied;
+}
+
+uint32_t
+RegisterValue::SetFromMemoryData (const RegisterInfo *reg_info,
+ const void *src,
+ uint32_t src_len,
+ lldb::ByteOrder src_byte_order,
+ Error &error)
+{
+ if (reg_info == NULL)
+ {
+ error.SetErrorString ("invalid register info argument.");
+ return 0;
+ }
+
+ // Moving from addr into a register
+ //
+ // Case 1: src_len == dst_len
+ //
+ // |AABBCCDD| Address contents
+ // |AABBCCDD| Register contents
+ //
+ // Case 2: src_len > dst_len
+ //
+ // Error! (The register should always be big enough to hold the data)
+ //
+ // Case 3: src_len < dst_len
+ //
+ // |AABB| Address contents
+ // |AABB0000| Register contents [on little-endian hardware]
+ // |0000AABB| Register contents [on big-endian hardware]
+ if (src_len > kMaxRegisterByteSize)
+ {
+ error.SetErrorStringWithFormat ("register buffer is too small to receive %u bytes of data.", src_len);
+ return 0;
+ }
+
+ const uint32_t dst_len = reg_info->byte_size;
+
+ if (src_len > dst_len)
+ {
+ error.SetErrorStringWithFormat("%u bytes is too big to store in register %s (%u bytes)", src_len, reg_info->name, dst_len);
+ return 0;
+ }
+
+ // Use a data extractor to correctly copy and pad the bytes read into the
+ // register value
+ DataExtractor src_data (src, src_len, src_byte_order, 4);
+
+ // Given the register info, set the value type of this RegisterValue object
+ SetType (reg_info);
+ // And make sure we were able to figure out what that register value was
+ RegisterValue::Type value_type = GetType();
+ if (value_type == eTypeInvalid)
+ {
+ // No value has been read into this object...
+ error.SetErrorStringWithFormat("invalid register value type for register %s", reg_info->name);
+ return 0;
+ }
+ else if (value_type == eTypeBytes)
+ {
+ m_data.buffer.byte_order = src_byte_order;
+ // Make sure to set the buffer length of the destination buffer to avoid
+ // problems due to uninitalized variables.
+ m_data.buffer.length = src_len;
+ }
+
+ const uint32_t bytes_copied = src_data.CopyByteOrderedData (0, // src offset
+ src_len, // src length
+ GetBytes(), // dst buffer
+ GetByteSize(), // dst length
+ GetByteOrder()); // dst byte order
+ if (bytes_copied == 0)
+ error.SetErrorStringWithFormat("failed to copy data for register write of %s", reg_info->name);
+
+ return bytes_copied;
+}
+
+bool
+RegisterValue::GetScalarValue (Scalar &scalar) const
+{
+ switch (m_type)
+ {
+ case eTypeInvalid: break;
+ case eTypeBytes:
+ {
+ switch (m_data.buffer.length)
+ {
+ default: break;
+ case 1: scalar = m_data.uint8; return true;
+ case 2: scalar = m_data.uint16; return true;
+ case 4: scalar = m_data.uint32; return true;
+ case 8: scalar = m_data.uint64; return true;
+ }
+ }
+ case eTypeUInt8: scalar = m_data.uint8; return true;
+ case eTypeUInt16: scalar = m_data.uint16; return true;
+ case eTypeUInt32: scalar = m_data.uint32; return true;
+ case eTypeUInt64: scalar = m_data.uint64; return true;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: break;
+#endif
+ case eTypeFloat: scalar = m_data.ieee_float; return true;
+ case eTypeDouble: scalar = m_data.ieee_double; return true;
+ case eTypeLongDouble: scalar = m_data.ieee_long_double; return true;
+ }
+ return false;
+}
+
+void
+RegisterValue::Clear()
+{
+ m_type = eTypeInvalid;
+}
+
+RegisterValue::Type
+RegisterValue::SetType (const RegisterInfo *reg_info)
+{
+ m_type = eTypeInvalid;
+ const uint32_t byte_size = reg_info->byte_size;
+ switch (reg_info->encoding)
+ {
+ case eEncodingInvalid:
+ break;
+
+ case eEncodingUint:
+ case eEncodingSint:
+ if (byte_size == 1)
+ m_type = eTypeUInt8;
+ else if (byte_size <= 2)
+ m_type = eTypeUInt16;
+ else if (byte_size <= 4)
+ m_type = eTypeUInt32;
+ else if (byte_size <= 8)
+ m_type = eTypeUInt64;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ else if (byte_size <= 16)
+ m_type = eTypeUInt128;
+#endif
+ break;
+
+ case eEncodingIEEE754:
+ if (byte_size == sizeof(float))
+ m_type = eTypeFloat;
+ else if (byte_size == sizeof(double))
+ m_type = eTypeDouble;
+ else if (byte_size == sizeof(long double))
+ m_type = eTypeLongDouble;
+ break;
+
+ case eEncodingVector:
+ m_type = eTypeBytes;
+ break;
+ }
+ return m_type;
+}
+
+Error
+RegisterValue::SetValueFromData (const RegisterInfo *reg_info, DataExtractor &src, lldb::offset_t src_offset, bool partial_data_ok)
+{
+ Error error;
+
+ if (src.GetByteSize() == 0)
+ {
+ error.SetErrorString ("empty data.");
+ return error;
+ }
+
+ if (reg_info->byte_size == 0)
+ {
+ error.SetErrorString ("invalid register info.");
+ return error;
+ }
+
+ uint32_t src_len = src.GetByteSize() - src_offset;
+
+ if (!partial_data_ok && (src_len < reg_info->byte_size))
+ {
+ error.SetErrorString ("not enough data.");
+ return error;
+ }
+
+ // Cap the data length if there is more than enough bytes for this register
+ // value
+ if (src_len > reg_info->byte_size)
+ src_len = reg_info->byte_size;
+
+ // Zero out the value in case we get partial data...
+ memset (m_data.buffer.bytes, 0, sizeof (m_data.buffer.bytes));
+
+ switch (SetType (reg_info))
+ {
+ case eTypeInvalid:
+ error.SetErrorString("");
+ break;
+ case eTypeUInt8: SetUInt8 (src.GetMaxU32 (&src_offset, src_len)); break;
+ case eTypeUInt16: SetUInt16 (src.GetMaxU32 (&src_offset, src_len)); break;
+ case eTypeUInt32: SetUInt32 (src.GetMaxU32 (&src_offset, src_len)); break;
+ case eTypeUInt64: SetUInt64 (src.GetMaxU64 (&src_offset, src_len)); break;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ {
+ __uint128_t data1 = src.GetU64 (&src_offset);
+ __uint128_t data2 = src.GetU64 (&src_offset);
+ if (src.GetByteSize() == eByteOrderBig)
+ SetUInt128 (data1 << 64 + data2);
+ else
+ SetUInt128 (data2 << 64 + data1);
+ }
+ break;
+#endif
+ case eTypeFloat: SetFloat (src.GetFloat (&src_offset)); break;
+ case eTypeDouble: SetDouble(src.GetDouble (&src_offset)); break;
+ case eTypeLongDouble: SetFloat (src.GetLongDouble (&src_offset)); break;
+ case eTypeBytes:
+ {
+ m_data.buffer.length = reg_info->byte_size;
+ m_data.buffer.byte_order = src.GetByteOrder();
+ assert (m_data.buffer.length <= kMaxRegisterByteSize);
+ if (m_data.buffer.length > kMaxRegisterByteSize)
+ m_data.buffer.length = kMaxRegisterByteSize;
+ if (src.CopyByteOrderedData (src_offset, // offset within "src" to start extracting data
+ src_len, // src length
+ m_data.buffer.bytes, // dst buffer
+ m_data.buffer.length, // dst length
+ m_data.buffer.byte_order) == 0)// dst byte order
+ {
+ error.SetErrorString ("data copy failed data.");
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+
+#include "llvm/ADT/StringRef.h"
+#include <vector>
+static inline void StripSpaces(llvm::StringRef &Str)
+{
+ while (!Str.empty() && isspace(Str[0]))
+ Str = Str.substr(1);
+ while (!Str.empty() && isspace(Str.back()))
+ Str = Str.substr(0, Str.size()-1);
+}
+static inline void LStrip(llvm::StringRef &Str, char c)
+{
+ if (!Str.empty() && Str.front() == c)
+ Str = Str.substr(1);
+}
+static inline void RStrip(llvm::StringRef &Str, char c)
+{
+ if (!Str.empty() && Str.back() == c)
+ Str = Str.substr(0, Str.size()-1);
+}
+// Helper function for RegisterValue::SetValueFromCString()
+static bool
+ParseVectorEncoding(const RegisterInfo *reg_info, const char *vector_str, const uint32_t byte_size, RegisterValue *reg_value)
+{
+ // Example: vector_str = "{0x2c 0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a 0x2a 0x3e 0x84 0x4f 0x2a 0x3e}".
+ llvm::StringRef Str(vector_str);
+ StripSpaces(Str);
+ LStrip(Str, '{');
+ RStrip(Str, '}');
+ StripSpaces(Str);
+
+ char Sep = ' ';
+
+ // The first split should give us:
+ // ('0x2c', '0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a 0x2a 0x3e 0x84 0x4f 0x2a 0x3e').
+ std::pair<llvm::StringRef, llvm::StringRef> Pair = Str.split(Sep);
+ std::vector<uint8_t> bytes;
+ unsigned byte = 0;
+
+ // Using radix auto-sensing by passing 0 as the radix.
+ // Keep on processing the vector elements as long as the parsing succeeds and the vector size is < byte_size.
+ while (!Pair.first.getAsInteger(0, byte) && bytes.size() < byte_size) {
+ bytes.push_back(byte);
+ Pair = Pair.second.split(Sep);
+ }
+
+ // Check for vector of exact byte_size elements.
+ if (bytes.size() != byte_size)
+ return false;
+
+ reg_value->SetBytes(&(bytes.front()), byte_size, eByteOrderLittle);
+ return true;
+}
+Error
+RegisterValue::SetValueFromCString (const RegisterInfo *reg_info, const char *value_str)
+{
+ Error error;
+ if (reg_info == NULL)
+ {
+ error.SetErrorString ("Invalid register info argument.");
+ return error;
+ }
+
+ if (value_str == NULL || value_str[0] == '\0')
+ {
+ error.SetErrorString ("Invalid c-string value string.");
+ return error;
+ }
+ bool success = false;
+ const uint32_t byte_size = reg_info->byte_size;
+ switch (reg_info->encoding)
+ {
+ case eEncodingInvalid:
+ error.SetErrorString ("Invalid encoding.");
+ break;
+
+ case eEncodingUint:
+ if (byte_size <= sizeof (uint64_t))
+ {
+ uint64_t uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("'%s' is not a valid unsigned integer string value", value_str);
+ else if (!Args::UInt64ValueIsValidForByteSize (uval64, byte_size))
+ error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %u byte unsigned integer value", uval64, byte_size);
+ else
+ {
+ if (!SetUInt (uval64, reg_info->byte_size))
+ error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %u", byte_size);
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %u", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingSint:
+ if (byte_size <= sizeof (long long))
+ {
+ uint64_t sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("'%s' is not a valid signed integer string value", value_str);
+ else if (!Args::SInt64ValueIsValidForByteSize (sval64, byte_size))
+ error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %u byte signed integer value", sval64, byte_size);
+ else
+ {
+ if (!SetUInt (sval64, reg_info->byte_size))
+ error.SetErrorStringWithFormat ("unsupported signed integer byte size: %u", byte_size);
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported signed integer byte size: %u", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingIEEE754:
+ if (byte_size == sizeof (float))
+ {
+ if (::sscanf (value_str, "%f", &m_data.ieee_float) == 1)
+ m_type = eTypeFloat;
+ else
+ error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
+ }
+ else if (byte_size == sizeof (double))
+ {
+ if (::sscanf (value_str, "%lf", &m_data.ieee_double) == 1)
+ m_type = eTypeDouble;
+ else
+ error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
+ }
+ else if (byte_size == sizeof (long double))
+ {
+ if (::sscanf (value_str, "%Lf", &m_data.ieee_long_double) == 1)
+ m_type = eTypeLongDouble;
+ else
+ error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported float byte size: %u", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingVector:
+ if (!ParseVectorEncoding(reg_info, value_str, byte_size, this))
+ error.SetErrorString ("unrecognized vector encoding string value.");
+ break;
+ }
+ if (error.Fail())
+ m_type = eTypeInvalid;
+
+ return error;
+}
+
+
+bool
+RegisterValue::SignExtend (uint32_t sign_bitpos)
+{
+ switch (m_type)
+ {
+ case eTypeInvalid:
+ break;
+
+ case eTypeUInt8:
+ if (sign_bitpos == (8-1))
+ return true;
+ else if (sign_bitpos < (8-1))
+ {
+ uint8_t sign_bit = 1u << sign_bitpos;
+ if (m_data.uint8 & sign_bit)
+ {
+ const uint8_t mask = ~(sign_bit) + 1u;
+ m_data.uint8 |= mask;
+ }
+ return true;
+ }
+ break;
+
+ case eTypeUInt16:
+ if (sign_bitpos == (16-1))
+ return true;
+ else if (sign_bitpos < (16-1))
+ {
+ uint16_t sign_bit = 1u << sign_bitpos;
+ if (m_data.uint16 & sign_bit)
+ {
+ const uint16_t mask = ~(sign_bit) + 1u;
+ m_data.uint16 |= mask;
+ }
+ return true;
+ }
+ break;
+
+ case eTypeUInt32:
+ if (sign_bitpos == (32-1))
+ return true;
+ else if (sign_bitpos < (32-1))
+ {
+ uint32_t sign_bit = 1u << sign_bitpos;
+ if (m_data.uint32 & sign_bit)
+ {
+ const uint32_t mask = ~(sign_bit) + 1u;
+ m_data.uint32 |= mask;
+ }
+ return true;
+ }
+ break;
+
+ case eTypeUInt64:
+ if (sign_bitpos == (64-1))
+ return true;
+ else if (sign_bitpos < (64-1))
+ {
+ uint64_t sign_bit = 1ull << sign_bitpos;
+ if (m_data.uint64 & sign_bit)
+ {
+ const uint64_t mask = ~(sign_bit) + 1ull;
+ m_data.uint64 |= mask;
+ }
+ return true;
+ }
+ break;
+
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ if (sign_bitpos == (128-1))
+ return true;
+ else if (sign_bitpos < (128-1))
+ {
+ __uint128_t sign_bit = (__uint128_t)1u << sign_bitpos;
+ if (m_data.uint128 & sign_bit)
+ {
+ const uint128_t mask = ~(sign_bit) + 1u;
+ m_data.uint128 |= mask;
+ }
+ return true;
+ }
+ break;
+#endif
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ case eTypeBytes:
+ break;
+ }
+ return false;
+}
+
+bool
+RegisterValue::CopyValue (const RegisterValue &rhs)
+{
+ m_type = rhs.m_type;
+ switch (m_type)
+ {
+ case eTypeInvalid:
+ return false;
+ case eTypeUInt8: m_data.uint8 = rhs.m_data.uint8; break;
+ case eTypeUInt16: m_data.uint16 = rhs.m_data.uint16; break;
+ case eTypeUInt32: m_data.uint32 = rhs.m_data.uint32; break;
+ case eTypeUInt64: m_data.uint64 = rhs.m_data.uint64; break;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: m_data.uint128 = rhs.m_data.uint128; break;
+#endif
+ case eTypeFloat: m_data.ieee_float = rhs.m_data.ieee_float; break;
+ case eTypeDouble: m_data.ieee_double = rhs.m_data.ieee_double; break;
+ case eTypeLongDouble: m_data.ieee_long_double = rhs.m_data.ieee_long_double; break;
+ case eTypeBytes:
+ assert (rhs.m_data.buffer.length <= kMaxRegisterByteSize);
+ ::memcpy (m_data.buffer.bytes, rhs.m_data.buffer.bytes, kMaxRegisterByteSize);
+ m_data.buffer.length = rhs.m_data.buffer.length;
+ m_data.buffer.byte_order = rhs.m_data.buffer.byte_order;
+ break;
+ }
+ return true;
+}
+
+uint16_t
+RegisterValue::GetAsUInt16 (uint16_t fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+
+ switch (m_type)
+ {
+ default: break;
+ case eTypeUInt8: return m_data.uint8;
+ case eTypeUInt16: return m_data.uint16;
+ case eTypeBytes:
+ {
+ switch (m_data.buffer.length)
+ {
+ default: break;
+ case 1: return m_data.uint8;
+ case 2: return m_data.uint16;
+ }
+ }
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+uint32_t
+RegisterValue::GetAsUInt32 (uint32_t fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type)
+ {
+ default: break;
+ case eTypeUInt8: return m_data.uint8;
+ case eTypeUInt16: return m_data.uint16;
+ case eTypeUInt32: return m_data.uint32;
+ case eTypeFloat:
+ if (sizeof(float) == sizeof(uint32_t))
+ return m_data.uint32;
+ break;
+ case eTypeDouble:
+ if (sizeof(double) == sizeof(uint32_t))
+ return m_data.uint32;
+ break;
+ case eTypeLongDouble:
+ if (sizeof(long double) == sizeof(uint32_t))
+ return m_data.uint32;
+ break;
+ case eTypeBytes:
+ {
+ switch (m_data.buffer.length)
+ {
+ default: break;
+ case 1: return m_data.uint8;
+ case 2: return m_data.uint16;
+ case 4: return m_data.uint32;
+ }
+ }
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+uint64_t
+RegisterValue::GetAsUInt64 (uint64_t fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type)
+ {
+ default: break;
+ case eTypeUInt8: return m_data.uint8;
+ case eTypeUInt16: return m_data.uint16;
+ case eTypeUInt32: return m_data.uint32;
+ case eTypeUInt64: return m_data.uint64;
+ case eTypeFloat:
+ if (sizeof(float) == sizeof(uint64_t))
+ return m_data.uint64;
+ break;
+ case eTypeDouble:
+ if (sizeof(double) == sizeof(uint64_t))
+ return m_data.uint64;
+ break;
+ case eTypeLongDouble:
+ if (sizeof(long double) == sizeof(uint64_t))
+ return m_data.uint64;
+ break;
+ case eTypeBytes:
+ {
+ switch (m_data.buffer.length)
+ {
+ default: break;
+ case 1: return m_data.uint8;
+ case 2: return m_data.uint16;
+ case 4: return m_data.uint32;
+ case 8: return m_data.uint64;
+ }
+ }
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+#if defined (ENABLE_128_BIT_SUPPORT)
+__uint128_t
+RegisterValue::GetAsUInt128 (__uint128_t fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type)
+ {
+ default: break;
+ case eTypeUInt8: return m_data.uint8;
+ case eTypeUInt16: return m_data.uint16;
+ case eTypeUInt32: return m_data.uint32;
+ case eTypeUInt64: return m_data.uint64;
+ case eTypeUInt128: return m_data.uint128;
+ case eTypeFloat:
+ if (sizeof(float) == sizeof(__uint128_t))
+ return m_data.uint128;
+ break;
+ case eTypeDouble:
+ if (sizeof(double) == sizeof(__uint128_t))
+ return m_data.uint128;
+ break;
+ case eTypeLongDouble:
+ if (sizeof(long double) == sizeof(__uint128_t))
+ return m_data.uint128;
+ break;
+ case eTypeBytes:
+ {
+ switch (m_data.buffer.length)
+ {
+ default:
+ break;
+ case 1: return m_data.uint8;
+ case 2: return m_data.uint16;
+ case 4: return m_data.uint32;
+ case 8: return m_data.uint64;
+ case 16: return m_data.uint128;
+ }
+ }
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+#endif
+float
+RegisterValue::GetAsFloat (float fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type)
+ {
+ default: break;
+ case eTypeUInt32:
+ if (sizeof(float) == sizeof(m_data.uint32))
+ return m_data.ieee_float;
+ break;
+ case eTypeUInt64:
+ if (sizeof(float) == sizeof(m_data.uint64))
+ return m_data.ieee_float;
+ break;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ if (sizeof(float) == sizeof(m_data.uint128))
+ return m_data.ieee_float;
+ break;
+#endif
+ case eTypeFloat: return m_data.ieee_float;
+ case eTypeDouble:
+ if (sizeof(float) == sizeof(double))
+ return m_data.ieee_float;
+ break;
+ case eTypeLongDouble:
+ if (sizeof(float) == sizeof(long double))
+ return m_data.ieee_float;
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+double
+RegisterValue::GetAsDouble (double fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type)
+ {
+ default:
+ break;
+
+ case eTypeUInt32:
+ if (sizeof(double) == sizeof(m_data.uint32))
+ return m_data.ieee_double;
+ break;
+
+ case eTypeUInt64:
+ if (sizeof(double) == sizeof(m_data.uint64))
+ return m_data.ieee_double;
+ break;
+
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ if (sizeof(double) == sizeof(m_data.uint128))
+ return m_data.ieee_double;
+#endif
+ case eTypeFloat: return m_data.ieee_float;
+ case eTypeDouble: return m_data.ieee_double;
+
+ case eTypeLongDouble:
+ if (sizeof(double) == sizeof(long double))
+ return m_data.ieee_double;
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+long double
+RegisterValue::GetAsLongDouble (long double fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type)
+ {
+ default:
+ break;
+
+ case eTypeUInt32:
+ if (sizeof(long double) == sizeof(m_data.uint32))
+ return m_data.ieee_long_double;
+ break;
+
+ case eTypeUInt64:
+ if (sizeof(long double) == sizeof(m_data.uint64))
+ return m_data.ieee_long_double;
+ break;
+
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ if (sizeof(long double) == sizeof(m_data.uint128))
+ return m_data.ieee_long_double;
+#endif
+ case eTypeFloat: return m_data.ieee_float;
+ case eTypeDouble: return m_data.ieee_double;
+ case eTypeLongDouble: return m_data.ieee_long_double;
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+const void *
+RegisterValue::GetBytes () const
+{
+ switch (m_type)
+ {
+ case eTypeInvalid: break;
+ case eTypeUInt8: return &m_data.uint8;
+ case eTypeUInt16: return &m_data.uint16;
+ case eTypeUInt32: return &m_data.uint32;
+ case eTypeUInt64: return &m_data.uint64;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: return &m_data.uint128;
+#endif
+ case eTypeFloat: return &m_data.ieee_float;
+ case eTypeDouble: return &m_data.ieee_double;
+ case eTypeLongDouble: return &m_data.ieee_long_double;
+ case eTypeBytes: return m_data.buffer.bytes;
+ }
+ return NULL;
+}
+
+void *
+RegisterValue::GetBytes ()
+{
+ switch (m_type)
+ {
+ case eTypeInvalid: break;
+ case eTypeUInt8: return &m_data.uint8;
+ case eTypeUInt16: return &m_data.uint16;
+ case eTypeUInt32: return &m_data.uint32;
+ case eTypeUInt64: return &m_data.uint64;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: return &m_data.uint128;
+#endif
+ case eTypeFloat: return &m_data.ieee_float;
+ case eTypeDouble: return &m_data.ieee_double;
+ case eTypeLongDouble: return &m_data.ieee_long_double;
+ case eTypeBytes: return m_data.buffer.bytes;
+ }
+ return NULL;
+}
+
+uint32_t
+RegisterValue::GetByteSize () const
+{
+ switch (m_type)
+ {
+ case eTypeInvalid: break;
+ case eTypeUInt8: return sizeof(m_data.uint8);
+ case eTypeUInt16: return sizeof(m_data.uint16);
+ case eTypeUInt32: return sizeof(m_data.uint32);
+ case eTypeUInt64: return sizeof(m_data.uint64);
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: return sizeof(m_data.uint128);
+#endif
+ case eTypeFloat: return sizeof(m_data.ieee_float);
+ case eTypeDouble: return sizeof(m_data.ieee_double);
+ case eTypeLongDouble: return sizeof(m_data.ieee_long_double);
+ case eTypeBytes: return m_data.buffer.length;
+ }
+ return 0;
+}
+
+
+bool
+RegisterValue::SetUInt (uint64_t uint, uint32_t byte_size)
+{
+ if (byte_size == 0)
+ {
+ SetUInt64 (uint);
+ }
+ else if (byte_size == 1)
+ {
+ SetUInt8 (uint);
+ }
+ else if (byte_size <= 2)
+ {
+ SetUInt16 (uint);
+ }
+ else if (byte_size <= 4)
+ {
+ SetUInt32 (uint);
+ }
+ else if (byte_size <= 8)
+ {
+ SetUInt64 (uint);
+ }
+#if defined (ENABLE_128_BIT_SUPPORT)
+ else if (byte_size <= 16)
+ {
+ SetUInt128 (uint);
+ }
+#endif
+ else
+ return false;
+ return true;
+}
+
+void
+RegisterValue::SetBytes (const void *bytes, size_t length, lldb::ByteOrder byte_order)
+{
+ // If this assertion fires off we need to increase the size of
+ // m_data.buffer.bytes, or make it something that is allocated on
+ // the heap. Since the data buffer is in a union, we can't make it
+ // a collection class like SmallVector...
+ if (bytes && length > 0)
+ {
+ assert (length <= sizeof (m_data.buffer.bytes) && "Storing too many bytes in a RegisterValue.");
+ m_type = eTypeBytes;
+ m_data.buffer.length = length;
+ memcpy (m_data.buffer.bytes, bytes, length);
+ m_data.buffer.byte_order = byte_order;
+ }
+ else
+ {
+ m_type = eTypeInvalid;
+ m_data.buffer.length = 0;
+ }
+}
+
+
+bool
+RegisterValue::operator == (const RegisterValue &rhs) const
+{
+ if (m_type == rhs.m_type)
+ {
+ switch (m_type)
+ {
+ case eTypeInvalid: return true;
+ case eTypeUInt8: return m_data.uint8 == rhs.m_data.uint8;
+ case eTypeUInt16: return m_data.uint16 == rhs.m_data.uint16;
+ case eTypeUInt32: return m_data.uint32 == rhs.m_data.uint32;
+ case eTypeUInt64: return m_data.uint64 == rhs.m_data.uint64;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: return m_data.uint128 == rhs.m_data.uint128;
+#endif
+ case eTypeFloat: return m_data.ieee_float == rhs.m_data.ieee_float;
+ case eTypeDouble: return m_data.ieee_double == rhs.m_data.ieee_double;
+ case eTypeLongDouble: return m_data.ieee_long_double == rhs.m_data.ieee_long_double;
+ case eTypeBytes:
+ if (m_data.buffer.length != rhs.m_data.buffer.length)
+ return false;
+ else
+ {
+ uint8_t length = m_data.buffer.length;
+ if (length > kMaxRegisterByteSize)
+ length = kMaxRegisterByteSize;
+ return memcmp (m_data.buffer.bytes, rhs.m_data.buffer.bytes, length) == 0;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+bool
+RegisterValue::operator != (const RegisterValue &rhs) const
+{
+ if (m_type != rhs.m_type)
+ return true;
+ switch (m_type)
+ {
+ case eTypeInvalid: return false;
+ case eTypeUInt8: return m_data.uint8 != rhs.m_data.uint8;
+ case eTypeUInt16: return m_data.uint16 != rhs.m_data.uint16;
+ case eTypeUInt32: return m_data.uint32 != rhs.m_data.uint32;
+ case eTypeUInt64: return m_data.uint64 != rhs.m_data.uint64;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: return m_data.uint128 != rhs.m_data.uint128;
+#endif
+ case eTypeFloat: return m_data.ieee_float != rhs.m_data.ieee_float;
+ case eTypeDouble: return m_data.ieee_double != rhs.m_data.ieee_double;
+ case eTypeLongDouble: return m_data.ieee_long_double != rhs.m_data.ieee_long_double;
+ case eTypeBytes:
+ if (m_data.buffer.length != rhs.m_data.buffer.length)
+ {
+ return true;
+ }
+ else
+ {
+ uint8_t length = m_data.buffer.length;
+ if (length > kMaxRegisterByteSize)
+ length = kMaxRegisterByteSize;
+ return memcmp (m_data.buffer.bytes, rhs.m_data.buffer.bytes, length) != 0;
+ }
+ break;
+ }
+ return true;
+}
+
+bool
+RegisterValue::ClearBit (uint32_t bit)
+{
+ switch (m_type)
+ {
+ case eTypeInvalid:
+ break;
+
+ case eTypeUInt8:
+ if (bit < 8)
+ {
+ m_data.uint8 &= ~(1u << bit);
+ return true;
+ }
+ break;
+
+ case eTypeUInt16:
+ if (bit < 16)
+ {
+ m_data.uint16 &= ~(1u << bit);
+ return true;
+ }
+ break;
+
+ case eTypeUInt32:
+ if (bit < 32)
+ {
+ m_data.uint32 &= ~(1u << bit);
+ return true;
+ }
+ break;
+
+ case eTypeUInt64:
+ if (bit < 64)
+ {
+ m_data.uint64 &= ~(1ull << (uint64_t)bit);
+ return true;
+ }
+ break;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ if (bit < 64)
+ {
+ m_data.uint128 &= ~((__uint128_t)1ull << (__uint128_t)bit);
+ return true;
+ }
+#endif
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ break;
+
+ case eTypeBytes:
+ if (m_data.buffer.byte_order == eByteOrderBig || m_data.buffer.byte_order == eByteOrderLittle)
+ {
+ uint32_t byte_idx;
+ if (m_data.buffer.byte_order == eByteOrderBig)
+ byte_idx = m_data.buffer.length - (bit / 8) - 1;
+ else
+ byte_idx = bit / 8;
+
+ const uint32_t byte_bit = bit % 8;
+ if (byte_idx < m_data.buffer.length)
+ {
+ m_data.buffer.bytes[byte_idx] &= ~(1u << byte_bit);
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+
+bool
+RegisterValue::SetBit (uint32_t bit)
+{
+ switch (m_type)
+ {
+ case eTypeInvalid:
+ break;
+
+ case eTypeUInt8:
+ if (bit < 8)
+ {
+ m_data.uint8 |= (1u << bit);
+ return true;
+ }
+ break;
+
+ case eTypeUInt16:
+ if (bit < 16)
+ {
+ m_data.uint16 |= (1u << bit);
+ return true;
+ }
+ break;
+
+ case eTypeUInt32:
+ if (bit < 32)
+ {
+ m_data.uint32 |= (1u << bit);
+ return true;
+ }
+ break;
+
+ case eTypeUInt64:
+ if (bit < 64)
+ {
+ m_data.uint64 |= (1ull << (uint64_t)bit);
+ return true;
+ }
+ break;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ if (bit < 64)
+ {
+ m_data.uint128 |= ((__uint128_t)1ull << (__uint128_t)bit);
+ return true;
+ }
+#endif
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ break;
+
+ case eTypeBytes:
+ if (m_data.buffer.byte_order == eByteOrderBig || m_data.buffer.byte_order == eByteOrderLittle)
+ {
+ uint32_t byte_idx;
+ if (m_data.buffer.byte_order == eByteOrderBig)
+ byte_idx = m_data.buffer.length - (bit / 8) - 1;
+ else
+ byte_idx = bit / 8;
+
+ const uint32_t byte_bit = bit % 8;
+ if (byte_idx < m_data.buffer.length)
+ {
+ m_data.buffer.bytes[byte_idx] |= (1u << byte_bit);
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+}
+
diff --git a/source/Core/RegularExpression.cpp b/source/Core/RegularExpression.cpp
new file mode 100644
index 0000000..4ccd774
--- /dev/null
+++ b/source/Core/RegularExpression.cpp
@@ -0,0 +1,279 @@
+//===-- RegularExpression.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/RegularExpression.h"
+#include "llvm/ADT/StringRef.h"
+#include <string.h>
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+RegularExpression::RegularExpression() :
+ m_re(),
+ m_comp_err (1),
+ m_preg(),
+ m_compile_flags(REG_EXTENDED)
+{
+ memset(&m_preg,0,sizeof(m_preg));
+}
+
+//----------------------------------------------------------------------
+// Constructor that compiles "re" using "flags" and stores the
+// resulting compiled regular expression into this object.
+//----------------------------------------------------------------------
+RegularExpression::RegularExpression(const char* re, int flags) :
+ m_re(),
+ m_comp_err (1),
+ m_preg(),
+ m_compile_flags(flags)
+{
+ memset(&m_preg,0,sizeof(m_preg));
+ Compile(re);
+}
+
+//----------------------------------------------------------------------
+// Constructor that compiles "re" using "flags" and stores the
+// resulting compiled regular expression into this object.
+//----------------------------------------------------------------------
+RegularExpression::RegularExpression(const char* re) :
+ m_re(),
+ m_comp_err (1),
+ m_preg(),
+ m_compile_flags(REG_EXTENDED)
+{
+ memset(&m_preg,0,sizeof(m_preg));
+ Compile(re);
+}
+
+RegularExpression::RegularExpression(const RegularExpression &rhs)
+{
+ memset(&m_preg,0,sizeof(m_preg));
+ Compile(rhs.GetText(), rhs.GetCompileFlags());
+}
+
+const RegularExpression &
+RegularExpression::operator= (const RegularExpression &rhs)
+{
+ if (&rhs != this)
+ {
+ Compile (rhs.GetText(), rhs.GetCompileFlags());
+ }
+ return *this;
+}
+//----------------------------------------------------------------------
+// Destructor
+//
+// Any previosuly compiled regular expression contained in this
+// object will be freed.
+//----------------------------------------------------------------------
+RegularExpression::~RegularExpression()
+{
+ Free();
+}
+
+//----------------------------------------------------------------------
+// Compile a regular expression using the supplied regular
+// expression text and flags. The compied regular expression lives
+// in this object so that it can be readily used for regular
+// expression matches. Execute() can be called after the regular
+// expression is compiled. Any previosuly compiled regular
+// expression contained in this object will be freed.
+//
+// RETURNS
+// True of the refular expression compiles successfully, false
+// otherwise.
+//----------------------------------------------------------------------
+bool
+RegularExpression::Compile(const char* re)
+{
+ return Compile (re, m_compile_flags);
+}
+
+bool
+RegularExpression::Compile(const char* re, int flags)
+{
+ Free();
+ m_compile_flags = flags;
+
+ if (re && re[0])
+ {
+ m_re = re;
+ m_comp_err = ::regcomp (&m_preg, re, flags);
+ }
+ else
+ {
+ // No valid regular expression
+ m_comp_err = 1;
+ }
+
+ return m_comp_err == 0;
+}
+
+//----------------------------------------------------------------------
+// Execute a regular expression match using the compiled regular
+// expression that is already in this object against the match
+// string "s". If any parens are used for regular expression
+// matches "match_count" should indicate the number of regmatch_t
+// values that are present in "match_ptr". The regular expression
+// will be executed using the "execute_flags".
+//---------------------------------------------------------------------
+bool
+RegularExpression::Execute(const char* s, Match *match, int execute_flags) const
+{
+ int err = 1;
+ if (s != NULL && m_comp_err == 0)
+ {
+ if (match)
+ {
+ err = ::regexec (&m_preg,
+ s,
+ match->GetSize(),
+ match->GetData(),
+ execute_flags);
+ }
+ else
+ {
+ err = ::regexec (&m_preg,
+ s,
+ 0,
+ NULL,
+ execute_flags);
+ }
+ }
+
+ if (err != 0)
+ {
+ // The regular expression didn't compile, so clear the matches
+ if (match)
+ match->Clear();
+ return false;
+ }
+ return true;
+}
+
+bool
+RegularExpression::Match::GetMatchAtIndex (const char* s, uint32_t idx, std::string& match_str) const
+{
+ if (idx < m_matches.size())
+ {
+ if (m_matches[idx].rm_eo == m_matches[idx].rm_so)
+ {
+ // Matched the empty string...
+ match_str.clear();
+ return true;
+ }
+ else if (m_matches[idx].rm_eo > m_matches[idx].rm_so)
+ {
+ match_str.assign (s + m_matches[idx].rm_so,
+ m_matches[idx].rm_eo - m_matches[idx].rm_so);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+RegularExpression::Match::GetMatchAtIndex (const char* s, uint32_t idx, llvm::StringRef& match_str) const
+{
+ if (idx < m_matches.size())
+ {
+ if (m_matches[idx].rm_eo == m_matches[idx].rm_so)
+ {
+ // Matched the empty string...
+ match_str = llvm::StringRef();
+ return true;
+ }
+ else if (m_matches[idx].rm_eo > m_matches[idx].rm_so)
+ {
+ match_str = llvm::StringRef (s + m_matches[idx].rm_so, m_matches[idx].rm_eo - m_matches[idx].rm_so);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+RegularExpression::Match::GetMatchSpanningIndices (const char* s, uint32_t idx1, uint32_t idx2, llvm::StringRef& match_str) const
+{
+ if (idx1 < m_matches.size() && idx2 < m_matches.size())
+ {
+ if (m_matches[idx1].rm_so == m_matches[idx2].rm_eo)
+ {
+ // Matched the empty string...
+ match_str = llvm::StringRef();
+ return true;
+ }
+ else if (m_matches[idx1].rm_so < m_matches[idx2].rm_eo)
+ {
+ match_str = llvm::StringRef (s + m_matches[idx1].rm_so, m_matches[idx2].rm_eo - m_matches[idx1].rm_so);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+//----------------------------------------------------------------------
+// Returns true if the regular expression compiled and is ready
+// for execution.
+//----------------------------------------------------------------------
+bool
+RegularExpression::IsValid () const
+{
+ return m_comp_err == 0;
+}
+
+//----------------------------------------------------------------------
+// Returns the text that was used to compile the current regular
+// expression.
+//----------------------------------------------------------------------
+const char*
+RegularExpression::GetText () const
+{
+ if (m_re.empty())
+ return NULL;
+ return m_re.c_str();
+}
+
+//----------------------------------------------------------------------
+// Free any contained compiled regular expressions.
+//----------------------------------------------------------------------
+void
+RegularExpression::Free()
+{
+ if (m_comp_err == 0)
+ {
+ m_re.clear();
+ regfree(&m_preg);
+ // Set a compile error since we no longer have a valid regex
+ m_comp_err = 1;
+ }
+}
+
+size_t
+RegularExpression::GetErrorAsCString (char *err_str, size_t err_str_max_len) const
+{
+ if (m_comp_err == 0)
+ {
+ if (err_str && err_str_max_len)
+ *err_str = '\0';
+ return 0;
+ }
+
+ return ::regerror (m_comp_err, &m_preg, err_str, err_str_max_len);
+}
+
+bool
+RegularExpression::operator < (const RegularExpression& rhs) const
+{
+ return (m_re < rhs.m_re);
+}
+
diff --git a/source/Core/Scalar.cpp b/source/Core/Scalar.cpp
new file mode 100644
index 0000000..26f7437
--- /dev/null
+++ b/source/Core/Scalar.cpp
@@ -0,0 +1,2279 @@
+//===-- Scalar.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/Scalar.h"
+
+#include <math.h>
+#include <inttypes.h>
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Host/Endian.h"
+
+#include "Plugins/Process/Utility/InstructionUtils.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Promote to max type currently follows the ANSI C rule for type
+// promotion in expressions.
+//----------------------------------------------------------------------
+static Scalar::Type
+PromoteToMaxType
+(
+ const Scalar& lhs, // The const left hand side object
+ const Scalar& rhs, // The const right hand side object
+ Scalar& temp_value, // A modifiable temp value than can be used to hold either the promoted lhs or rhs object
+ const Scalar* &promoted_lhs_ptr, // Pointer to the resulting possibly promoted value of lhs (at most one of lhs/rhs will get promoted)
+ const Scalar* &promoted_rhs_ptr // Pointer to the resulting possibly promoted value of rhs (at most one of lhs/rhs will get promoted)
+)
+{
+ Scalar result;
+ // Initialize the promoted values for both the right and left hand side values
+ // to be the objects themselves. If no promotion is needed (both right and left
+ // have the same type), then the temp_value will not get used.
+ promoted_lhs_ptr = &lhs;
+ promoted_rhs_ptr = &rhs;
+ // Extract the types of both the right and left hand side values
+ Scalar::Type lhs_type = lhs.GetType();
+ Scalar::Type rhs_type = rhs.GetType();
+
+ if (lhs_type > rhs_type)
+ {
+ // Right hand side need to be promoted
+ temp_value = rhs; // Copy right hand side into the temp value
+ if (temp_value.Promote(lhs_type)) // Promote it
+ promoted_rhs_ptr = &temp_value; // Update the pointer for the promoted right hand side
+ }
+ else if (lhs_type < rhs_type)
+ {
+ // Left hand side need to be promoted
+ temp_value = lhs; // Copy left hand side value into the temp value
+ if (temp_value.Promote(rhs_type)) // Promote it
+ promoted_lhs_ptr = &temp_value; // Update the pointer for the promoted left hand side
+ }
+
+ // Make sure our type promotion worked as exptected
+ if (promoted_lhs_ptr->GetType() == promoted_rhs_ptr->GetType())
+ return promoted_lhs_ptr->GetType(); // Return the resulting max type
+
+ // Return the void type (zero) if we fail to promote either of the values.
+ return Scalar::e_void;
+}
+
+
+//----------------------------------------------------------------------
+// Scalar constructor
+//----------------------------------------------------------------------
+Scalar::Scalar() :
+ m_type(e_void),
+ m_data()
+{
+}
+
+//----------------------------------------------------------------------
+// Scalar copy constructor
+//----------------------------------------------------------------------
+Scalar::Scalar(const Scalar& rhs) :
+ m_type(rhs.m_type),
+ m_data(rhs.m_data) // TODO: verify that for C++ this will correctly copy the union??
+{
+}
+
+//Scalar::Scalar(const RegisterValue& reg) :
+// m_type(e_void),
+// m_data()
+//{
+// switch (reg.info.encoding)
+// {
+// case eEncodingUint: // unsigned integer
+// switch (reg.info.byte_size)
+// {
+// case 1: m_type = e_uint; m_data.uint = reg.value.uint8; break;
+// case 2: m_type = e_uint; m_data.uint = reg.value.uint16; break;
+// case 4: m_type = e_uint; m_data.uint = reg.value.uint32; break;
+// case 8: m_type = e_ulonglong; m_data.ulonglong = reg.value.uint64; break;
+// break;
+// }
+// break;
+//
+// case eEncodingSint: // signed integer
+// switch (reg.info.byte_size)
+// {
+// case 1: m_type = e_sint; m_data.sint = reg.value.sint8; break;
+// case 2: m_type = e_sint; m_data.sint = reg.value.sint16; break;
+// case 4: m_type = e_sint; m_data.sint = reg.value.sint32; break;
+// case 8: m_type = e_slonglong; m_data.slonglong = reg.value.sint64; break;
+// break;
+// }
+// break;
+//
+// case eEncodingIEEE754: // float
+// switch (reg.info.byte_size)
+// {
+// case 4: m_type = e_float; m_data.flt = reg.value.float32; break;
+// case 8: m_type = e_double; m_data.dbl = reg.value.float64; break;
+// break;
+// }
+// break;
+// case eEncodingVector: // vector registers
+// break;
+// }
+//}
+
+bool
+Scalar::GetData (DataExtractor &data, size_t limit_byte_size) const
+{
+ size_t byte_size = GetByteSize();
+ if (byte_size > 0)
+ {
+ if (limit_byte_size < byte_size)
+ {
+ if (lldb::endian::InlHostByteOrder() == eByteOrderLittle)
+ {
+ // On little endian systems if we want fewer bytes from the
+ // current type we just specify fewer bytes since the LSByte
+ // is first...
+ data.SetData((uint8_t*)&m_data, limit_byte_size, lldb::endian::InlHostByteOrder());
+ }
+ else if (lldb::endian::InlHostByteOrder() == eByteOrderBig)
+ {
+ // On big endian systems if we want fewer bytes from the
+ // current type have to advance our initial byte pointer and
+ // trim down the number of bytes since the MSByte is first
+ data.SetData(((uint8_t*)&m_data) + byte_size - limit_byte_size, limit_byte_size, lldb::endian::InlHostByteOrder());
+ }
+ }
+ else
+ {
+ // We want all of the data
+ data.SetData((uint8_t*)&m_data, byte_size, lldb::endian::InlHostByteOrder());
+ }
+ return true;
+ }
+ data.Clear();
+ return false;
+}
+
+size_t
+Scalar::GetByteSize() const
+{
+ switch (m_type)
+ {
+ case e_void:
+ break;
+ case e_sint: return sizeof(m_data.sint);
+ case e_uint: return sizeof(m_data.uint);
+ case e_slong: return sizeof(m_data.slong);
+ case e_ulong: return sizeof(m_data.ulong);
+ case e_slonglong: return sizeof(m_data.slonglong);
+ case e_ulonglong: return sizeof(m_data.ulonglong);
+ case e_float: return sizeof(m_data.flt);
+ case e_double: return sizeof(m_data.dbl);
+ case e_long_double: return sizeof(m_data.ldbl);
+ }
+ return 0;
+}
+
+bool
+Scalar::IsZero() const
+{
+ switch (m_type)
+ {
+ case e_void:
+ break;
+ case e_sint: return m_data.sint == 0;
+ case e_uint: return m_data.uint == 0;
+ case e_slong: return m_data.slong == 0;
+ case e_ulong: return m_data.ulong == 0;
+ case e_slonglong: return m_data.slonglong == 0;
+ case e_ulonglong: return m_data.ulonglong == 0;
+ case e_float: return m_data.flt == 0.0f;
+ case e_double: return m_data.dbl == 0.0;
+ case e_long_double: return m_data.ldbl == 0.0;
+ }
+ return false;
+}
+
+void
+Scalar::GetValue (Stream *s, bool show_type) const
+{
+ if (show_type)
+ s->Printf("(%s) ", GetTypeAsCString());
+
+ switch (m_type)
+ {
+ case e_void:
+ break;
+ case e_sint: s->Printf("%i", m_data.sint); break;
+ case e_uint: s->Printf("0x%8.8x", m_data.uint); break;
+ case e_slong: s->Printf("%li", m_data.slong); break;
+ case e_ulong: s->Printf("0x%8.8lx", m_data.ulong); break;
+ case e_slonglong: s->Printf("%lli", m_data.slonglong); break;
+ case e_ulonglong: s->Printf("0x%16.16llx", m_data.ulonglong); break;
+ case e_float: s->Printf("%f", m_data.flt); break;
+ case e_double: s->Printf("%g", m_data.dbl); break;
+ case e_long_double: s->Printf("%Lg", m_data.ldbl); break;
+ }
+}
+
+const char *
+Scalar::GetTypeAsCString() const
+{
+ switch (m_type)
+ {
+ case e_void: return "void";
+ case e_sint: return "int";
+ case e_uint: return "unsigned int";
+ case e_slong: return "long";
+ case e_ulong: return "unsigned long";
+ case e_slonglong: return "long long";
+ case e_ulonglong: return "unsigned long long";
+ case e_float: return "float";
+ case e_double: return "double";
+ case e_long_double: return "long double";
+ }
+ return "<invalid Scalar type>";
+}
+
+
+
+//----------------------------------------------------------------------
+// Scalar copy constructor
+//----------------------------------------------------------------------
+Scalar&
+Scalar::operator=(const Scalar& rhs)
+{
+ if (this != &rhs)
+ {
+ m_type = rhs.m_type;
+ ::memcpy (&m_data, &rhs.m_data, sizeof(m_data));
+ }
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (const int v)
+{
+ m_type = e_sint;
+ m_data.sint = v;
+ return *this;
+}
+
+
+Scalar&
+Scalar::operator= (unsigned int v)
+{
+ m_type = e_uint;
+ m_data.uint = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (long v)
+{
+ m_type = e_slong;
+ m_data.slong = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (unsigned long v)
+{
+ m_type = e_ulong;
+ m_data.ulong = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (long long v)
+{
+ m_type = e_slonglong;
+ m_data.slonglong = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (unsigned long long v)
+{
+ m_type = e_ulonglong;
+ m_data.ulonglong = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (float v)
+{
+ m_type = e_float;
+ m_data.flt = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (double v)
+{
+ m_type = e_double;
+ m_data.dbl = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (long double v)
+{
+ m_type = e_long_double;
+ m_data.ldbl = v;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Scalar::~Scalar()
+{
+}
+
+bool
+Scalar::Promote(Scalar::Type type)
+{
+ bool success = false;
+ switch (m_type)
+ {
+ case e_void:
+ break;
+
+ case e_sint:
+ switch (type)
+ {
+ case e_void: break;
+ case e_sint: success = true; break;
+ case e_uint: m_data.uint = m_data.sint; success = true; break;
+ case e_slong: m_data.slong = m_data.sint; success = true; break;
+ case e_ulong: m_data.ulong = m_data.sint; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.sint; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.sint; success = true; break;
+ case e_float: m_data.flt = m_data.sint; success = true; break;
+ case e_double: m_data.dbl = m_data.sint; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.sint; success = true; break;
+ }
+ break;
+
+ case e_uint:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: break;
+ case e_uint: success = true; break;
+ case e_slong: m_data.slong = m_data.uint; success = true; break;
+ case e_ulong: m_data.ulong = m_data.uint; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.uint; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.uint; success = true; break;
+ case e_float: m_data.flt = m_data.uint; success = true; break;
+ case e_double: m_data.dbl = m_data.uint; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.uint; success = true; break;
+ }
+ break;
+
+ case e_slong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint: break;
+ case e_slong: success = true; break;
+ case e_ulong: m_data.ulong = m_data.slong; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.slong; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.slong; success = true; break;
+ case e_float: m_data.flt = m_data.slong; success = true; break;
+ case e_double: m_data.dbl = m_data.slong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.slong; success = true; break;
+ }
+ break;
+
+ case e_ulong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint:
+ case e_slong: break;
+ case e_ulong: success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.ulong; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.ulong; success = true; break;
+ case e_float: m_data.flt = m_data.ulong; success = true; break;
+ case e_double: m_data.dbl = m_data.ulong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.ulong; success = true; break;
+ }
+ break;
+
+ case e_slonglong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint:
+ case e_slong:
+ case e_ulong: break;
+ case e_slonglong: success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.slonglong; success = true; break;
+ case e_float: m_data.flt = m_data.slonglong; success = true; break;
+ case e_double: m_data.dbl = m_data.slonglong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.slonglong; success = true; break;
+ }
+ break;
+
+ case e_ulonglong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint:
+ case e_slong:
+ case e_ulong:
+ case e_slonglong: break;
+ case e_ulonglong: success = true; break;
+ case e_float: m_data.flt = m_data.ulonglong; success = true; break;
+ case e_double: m_data.dbl = m_data.ulonglong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.ulonglong; success = true; break;
+ }
+ break;
+
+ case e_float:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint:
+ case e_slong:
+ case e_ulong:
+ case e_slonglong:
+ case e_ulonglong: break;
+ case e_float: success = true; break;
+ case e_double: m_data.dbl = m_data.flt; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.ulonglong; success = true; break;
+ }
+ break;
+
+ case e_double:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint:
+ case e_slong:
+ case e_ulong:
+ case e_slonglong:
+ case e_ulonglong:
+ case e_float: break;
+ case e_double: success = true; break;
+ case e_long_double: m_data.ldbl = m_data.dbl; success = true; break;
+ }
+ break;
+
+ case e_long_double:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint:
+ case e_slong:
+ case e_ulong:
+ case e_slonglong:
+ case e_ulonglong:
+ case e_float:
+ case e_double: break;
+ case e_long_double: success = true; break;
+ }
+ break;
+ }
+
+ if (success)
+ m_type = type;
+ return success;
+}
+
+const char *
+Scalar::GetValueTypeAsCString (Scalar::Type type)
+{
+ switch (type)
+ {
+ case e_void: return "void";
+ case e_sint: return "int";
+ case e_uint: return "unsigned int";
+ case e_slong: return "long";
+ case e_ulong: return "unsigned long";
+ case e_slonglong: return "long long";
+ case e_ulonglong: return "unsigned long long";
+ case e_float: return "float";
+ case e_double: return "double";
+ case e_long_double: return "long double";
+ }
+ return "???";
+}
+
+
+Scalar::Type
+Scalar::GetValueTypeForSignedIntegerWithByteSize (size_t byte_size)
+{
+ if (byte_size <= sizeof(sint_t))
+ return e_sint;
+ if (byte_size <= sizeof(slong_t))
+ return e_slong;
+ if (byte_size <= sizeof(slonglong_t))
+ return e_slonglong;
+ return e_void;
+}
+
+Scalar::Type
+Scalar::GetValueTypeForUnsignedIntegerWithByteSize (size_t byte_size)
+{
+ if (byte_size <= sizeof(uint_t))
+ return e_uint;
+ if (byte_size <= sizeof(ulong_t))
+ return e_ulong;
+ if (byte_size <= sizeof(ulonglong_t))
+ return e_ulonglong;
+ return e_void;
+}
+
+Scalar::Type
+Scalar::GetValueTypeForFloatWithByteSize (size_t byte_size)
+{
+ if (byte_size == sizeof(float_t))
+ return e_float;
+ if (byte_size == sizeof(double_t))
+ return e_double;
+ if (byte_size == sizeof(long_double_t))
+ return e_long_double;
+ return e_void;
+}
+
+bool
+Scalar::Cast(Scalar::Type type)
+{
+ bool success = false;
+ switch (m_type)
+ {
+ case e_void:
+ break;
+
+ case e_sint:
+ switch (type)
+ {
+ case e_void: break;
+ case e_sint: success = true; break;
+ case e_uint: m_data.uint = m_data.sint; success = true; break;
+ case e_slong: m_data.slong = m_data.sint; success = true; break;
+ case e_ulong: m_data.ulong = m_data.sint; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.sint; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.sint; success = true; break;
+ case e_float: m_data.flt = m_data.sint; success = true; break;
+ case e_double: m_data.dbl = m_data.sint; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.sint; success = true; break;
+ }
+ break;
+
+ case e_uint:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = m_data.uint; success = true; break;
+ case e_uint: success = true; break;
+ case e_slong: m_data.slong = m_data.uint; success = true; break;
+ case e_ulong: m_data.ulong = m_data.uint; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.uint; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.uint; success = true; break;
+ case e_float: m_data.flt = m_data.uint; success = true; break;
+ case e_double: m_data.dbl = m_data.uint; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.uint; success = true; break;
+ }
+ break;
+
+ case e_slong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.slong; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.slong; success = true; break;
+ case e_slong: success = true; break;
+ case e_ulong: m_data.ulong = m_data.slong; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.slong; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.slong; success = true; break;
+ case e_float: m_data.flt = m_data.slong; success = true; break;
+ case e_double: m_data.dbl = m_data.slong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.slong; success = true; break;
+ }
+ break;
+
+ case e_ulong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.ulong; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.ulong; success = true; break;
+ case e_slong: m_data.slong = m_data.ulong; success = true; break;
+ case e_ulong: success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.ulong; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.ulong; success = true; break;
+ case e_float: m_data.flt = m_data.ulong; success = true; break;
+ case e_double: m_data.dbl = m_data.ulong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.ulong; success = true; break;
+ }
+ break;
+
+ case e_slonglong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.slonglong; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.slonglong; success = true; break;
+ case e_slong: m_data.slong = m_data.slonglong; success = true; break;
+ case e_ulong: m_data.ulong = m_data.slonglong; success = true; break;
+ case e_slonglong: success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.slonglong; success = true; break;
+ case e_float: m_data.flt = m_data.slonglong; success = true; break;
+ case e_double: m_data.dbl = m_data.slonglong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.slonglong; success = true; break;
+ }
+ break;
+
+ case e_ulonglong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.ulonglong; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.ulonglong; success = true; break;
+ case e_slong: m_data.slong = m_data.ulonglong; success = true; break;
+ case e_ulong: m_data.ulong = m_data.ulonglong; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.ulonglong; success = true; break;
+ case e_ulonglong: success = true; break;
+ case e_float: m_data.flt = m_data.ulonglong; success = true; break;
+ case e_double: m_data.dbl = m_data.ulonglong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.ulonglong; success = true; break;
+ }
+ break;
+
+ case e_float:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.flt; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.flt; success = true; break;
+ case e_slong: m_data.slong = (slong_t)m_data.flt; success = true; break;
+ case e_ulong: m_data.ulong = (ulong_t)m_data.flt; success = true; break;
+ case e_slonglong: m_data.slonglong = (slonglong_t)m_data.flt; success = true; break;
+ case e_ulonglong: m_data.ulonglong = (ulonglong_t)m_data.flt; success = true; break;
+ case e_float: success = true; break;
+ case e_double: m_data.dbl = m_data.flt; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.flt; success = true; break;
+ }
+ break;
+
+ case e_double:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.dbl; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.dbl; success = true; break;
+ case e_slong: m_data.slong = (slong_t)m_data.dbl; success = true; break;
+ case e_ulong: m_data.ulong = (ulong_t)m_data.dbl; success = true; break;
+ case e_slonglong: m_data.slonglong = (slonglong_t)m_data.dbl; success = true; break;
+ case e_ulonglong: m_data.ulonglong = (ulonglong_t)m_data.dbl; success = true; break;
+ case e_float: m_data.flt = (float_t)m_data.dbl; success = true; break;
+ case e_double: success = true; break;
+ case e_long_double: m_data.ldbl = m_data.dbl; success = true; break;
+ }
+ break;
+
+ case e_long_double:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.ldbl; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.ldbl; success = true; break;
+ case e_slong: m_data.slong = (slong_t)m_data.ldbl; success = true; break;
+ case e_ulong: m_data.ulong = (ulong_t)m_data.ldbl; success = true; break;
+ case e_slonglong: m_data.slonglong = (slonglong_t)m_data.ldbl; success = true; break;
+ case e_ulonglong: m_data.ulonglong = (ulonglong_t)m_data.ldbl; success = true; break;
+ case e_float: m_data.flt = (float_t)m_data.ldbl; success = true; break;
+ case e_double: m_data.dbl = (double_t)m_data.ldbl; success = true; break;
+ case e_long_double: success = true; break;
+ }
+ break;
+ }
+
+ if (success)
+ m_type = type;
+ return success;
+}
+
+bool
+Scalar::MakeSigned ()
+{
+ bool success = false;
+
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: success = true; break;
+ case e_uint: m_type = e_sint; success = true; break;
+ case e_slong: success = true; break;
+ case e_ulong: m_type = e_slong; success = true; break;
+ case e_slonglong: success = true; break;
+ case e_ulonglong: m_type = e_slonglong; success = true; break;
+ case e_float: success = true; break;
+ case e_double: success = true; break;
+ case e_long_double: success = true; break;
+ }
+
+ return success;
+}
+
+int
+Scalar::SInt(int fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return m_data.sint;
+ case e_uint: return (int)m_data.uint;
+ case e_slong: return (int)m_data.slong;
+ case e_ulong: return (int)m_data.ulong;
+ case e_slonglong: return (int)m_data.slonglong;
+ case e_ulonglong: return (int)m_data.ulonglong;
+ case e_float: return (int)m_data.flt;
+ case e_double: return (int)m_data.dbl;
+ case e_long_double: return (int)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+unsigned int
+Scalar::UInt(unsigned int fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (unsigned int)m_data.sint;
+ case e_uint: return (unsigned int)m_data.uint;
+ case e_slong: return (unsigned int)m_data.slong;
+ case e_ulong: return (unsigned int)m_data.ulong;
+ case e_slonglong: return (unsigned int)m_data.slonglong;
+ case e_ulonglong: return (unsigned int)m_data.ulonglong;
+ case e_float: return (unsigned int)m_data.flt;
+ case e_double: return (unsigned int)m_data.dbl;
+ case e_long_double: return (unsigned int)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+long
+Scalar::SLong(long fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (long)m_data.sint;
+ case e_uint: return (long)m_data.uint;
+ case e_slong: return (long)m_data.slong;
+ case e_ulong: return (long)m_data.ulong;
+ case e_slonglong: return (long)m_data.slonglong;
+ case e_ulonglong: return (long)m_data.ulonglong;
+ case e_float: return (long)m_data.flt;
+ case e_double: return (long)m_data.dbl;
+ case e_long_double: return (long)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+
+unsigned long
+Scalar::ULong(unsigned long fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (unsigned long)m_data.sint;
+ case e_uint: return (unsigned long)m_data.uint;
+ case e_slong: return (unsigned long)m_data.slong;
+ case e_ulong: return (unsigned long)m_data.ulong;
+ case e_slonglong: return (unsigned long)m_data.slonglong;
+ case e_ulonglong: return (unsigned long)m_data.ulonglong;
+ case e_float: return (unsigned long)m_data.flt;
+ case e_double: return (unsigned long)m_data.dbl;
+ case e_long_double: return (unsigned long)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+uint64_t
+Scalar::GetRawBits64(uint64_t fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void:
+ break;
+
+ case e_sint:
+ case e_uint:
+ return m_data.uint;
+
+ case e_slong:
+ case e_ulong:
+ return m_data.ulong;
+
+ case e_slonglong:
+ case e_ulonglong:
+ return m_data.ulonglong;
+
+ case e_float:
+ if (sizeof(m_data.flt) == sizeof(m_data.uint))
+ return m_data.uint;
+ else if (sizeof(m_data.flt) == sizeof(m_data.ulong))
+ return m_data.ulong;
+ else if (sizeof(m_data.flt) == sizeof(m_data.ulonglong))
+ return m_data.ulonglong;
+ break;
+
+ case e_double:
+ if (sizeof(m_data.dbl) == sizeof(m_data.uint))
+ return m_data.uint;
+ else if (sizeof(m_data.dbl) == sizeof(m_data.ulong))
+ return m_data.ulong;
+ else if (sizeof(m_data.dbl) == sizeof(m_data.ulonglong))
+ return m_data.ulonglong;
+ break;
+
+ case e_long_double:
+ if (sizeof(m_data.ldbl) == sizeof(m_data.uint))
+ return m_data.uint;
+ else if (sizeof(m_data.ldbl) == sizeof(m_data.ulong))
+ return m_data.ulong;
+ else if (sizeof(m_data.ldbl) == sizeof(m_data.ulonglong))
+ return m_data.ulonglong;
+ break;
+ }
+ return fail_value;
+}
+
+
+
+long long
+Scalar::SLongLong(long long fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (long long)m_data.sint;
+ case e_uint: return (long long)m_data.uint;
+ case e_slong: return (long long)m_data.slong;
+ case e_ulong: return (long long)m_data.ulong;
+ case e_slonglong: return (long long)m_data.slonglong;
+ case e_ulonglong: return (long long)m_data.ulonglong;
+ case e_float: return (long long)m_data.flt;
+ case e_double: return (long long)m_data.dbl;
+ case e_long_double: return (long long)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+unsigned long long
+Scalar::ULongLong(unsigned long long fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (unsigned long long)m_data.sint;
+ case e_uint: return (unsigned long long)m_data.uint;
+ case e_slong: return (unsigned long long)m_data.slong;
+ case e_ulong: return (unsigned long long)m_data.ulong;
+ case e_slonglong: return (unsigned long long)m_data.slonglong;
+ case e_ulonglong: return (unsigned long long)m_data.ulonglong;
+ case e_float: return (unsigned long long)m_data.flt;
+ case e_double: return (unsigned long long)m_data.dbl;
+ case e_long_double: return (unsigned long long)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+float
+Scalar::Float(float fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (float)m_data.sint;
+ case e_uint: return (float)m_data.uint;
+ case e_slong: return (float)m_data.slong;
+ case e_ulong: return (float)m_data.ulong;
+ case e_slonglong: return (float)m_data.slonglong;
+ case e_ulonglong: return (float)m_data.ulonglong;
+ case e_float: return (float)m_data.flt;
+ case e_double: return (float)m_data.dbl;
+ case e_long_double: return (float)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+double
+Scalar::Double(double fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (double)m_data.sint;
+ case e_uint: return (double)m_data.uint;
+ case e_slong: return (double)m_data.slong;
+ case e_ulong: return (double)m_data.ulong;
+ case e_slonglong: return (double)m_data.slonglong;
+ case e_ulonglong: return (double)m_data.ulonglong;
+ case e_float: return (double)m_data.flt;
+ case e_double: return (double)m_data.dbl;
+ case e_long_double: return (double)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+long double
+Scalar::LongDouble(long double fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (long double)m_data.sint;
+ case e_uint: return (long double)m_data.uint;
+ case e_slong: return (long double)m_data.slong;
+ case e_ulong: return (long double)m_data.ulong;
+ case e_slonglong: return (long double)m_data.slonglong;
+ case e_ulonglong: return (long double)m_data.ulonglong;
+ case e_float: return (long double)m_data.flt;
+ case e_double: return (long double)m_data.dbl;
+ case e_long_double: return (long double)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+Scalar&
+Scalar::operator+= (const Scalar& rhs)
+{
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((m_type = PromoteToMaxType(*this, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: m_data.sint = a->m_data.sint + b->m_data.sint; break;
+ case e_uint: m_data.uint = a->m_data.uint + b->m_data.uint; break;
+ case e_slong: m_data.slong = a->m_data.slong + b->m_data.slong; break;
+ case e_ulong: m_data.ulong = a->m_data.ulong + b->m_data.ulong; break;
+ case e_slonglong: m_data.slonglong = a->m_data.slonglong + b->m_data.slonglong; break;
+ case e_ulonglong: m_data.ulonglong = a->m_data.ulonglong + b->m_data.ulonglong; break;
+ case e_float: m_data.flt = a->m_data.flt + b->m_data.flt; break;
+ case e_double: m_data.dbl = a->m_data.dbl + b->m_data.dbl; break;
+ case e_long_double: m_data.ldbl = a->m_data.ldbl + b->m_data.ldbl; break;
+ }
+ }
+ return *this;
+}
+
+Scalar&
+Scalar::operator<<= (const Scalar& rhs)
+{
+ switch (m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+
+ case e_sint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.sint <<= rhs.m_data.sint; break;
+ case e_uint: m_data.sint <<= rhs.m_data.uint; break;
+ case e_slong: m_data.sint <<= rhs.m_data.slong; break;
+ case e_ulong: m_data.sint <<= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.sint <<= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.sint <<= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_uint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.uint <<= rhs.m_data.sint; break;
+ case e_uint: m_data.uint <<= rhs.m_data.uint; break;
+ case e_slong: m_data.uint <<= rhs.m_data.slong; break;
+ case e_ulong: m_data.uint <<= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.uint <<= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.uint <<= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_slong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.slong <<= rhs.m_data.sint; break;
+ case e_uint: m_data.slong <<= rhs.m_data.uint; break;
+ case e_slong: m_data.slong <<= rhs.m_data.slong; break;
+ case e_ulong: m_data.slong <<= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.slong <<= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.slong <<= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_ulong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulong <<= rhs.m_data.sint; break;
+ case e_uint: m_data.ulong <<= rhs.m_data.uint; break;
+ case e_slong: m_data.ulong <<= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulong <<= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulong <<= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulong <<= rhs.m_data.ulonglong; break;
+ }
+ break;
+ case e_slonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.slonglong <<= rhs.m_data.sint; break;
+ case e_uint: m_data.slonglong <<= rhs.m_data.uint; break;
+ case e_slong: m_data.slonglong <<= rhs.m_data.slong; break;
+ case e_ulong: m_data.slonglong <<= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.slonglong <<= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.slonglong <<= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_ulonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulonglong <<= rhs.m_data.sint; break;
+ case e_uint: m_data.ulonglong <<= rhs.m_data.uint; break;
+ case e_slong: m_data.ulonglong <<= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulonglong <<= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulonglong <<= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulonglong <<= rhs.m_data.ulonglong; break;
+ }
+ break;
+ }
+ return *this;
+}
+
+bool
+Scalar::ShiftRightLogical(const Scalar& rhs)
+{
+ switch (m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+
+ case e_sint:
+ case e_uint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.uint >>= rhs.m_data.sint; break;
+ case e_uint: m_data.uint >>= rhs.m_data.uint; break;
+ case e_slong: m_data.uint >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.uint >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.uint >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.uint >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_slong:
+ case e_ulong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulong >>= rhs.m_data.sint; break;
+ case e_uint: m_data.ulong >>= rhs.m_data.uint; break;
+ case e_slong: m_data.ulong >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulong >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulong >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulong >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_slonglong:
+ case e_ulonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulonglong >>= rhs.m_data.sint; break;
+ case e_uint: m_data.ulonglong >>= rhs.m_data.uint; break;
+ case e_slong: m_data.ulonglong >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulonglong >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulonglong >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulonglong >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+ }
+ return m_type != e_void;
+}
+
+
+Scalar&
+Scalar::operator>>= (const Scalar& rhs)
+{
+ switch (m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+
+ case e_sint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.sint >>= rhs.m_data.sint; break;
+ case e_uint: m_data.sint >>= rhs.m_data.uint; break;
+ case e_slong: m_data.sint >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.sint >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.sint >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.sint >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_uint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.uint >>= rhs.m_data.sint; break;
+ case e_uint: m_data.uint >>= rhs.m_data.uint; break;
+ case e_slong: m_data.uint >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.uint >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.uint >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.uint >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_slong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.slong >>= rhs.m_data.sint; break;
+ case e_uint: m_data.slong >>= rhs.m_data.uint; break;
+ case e_slong: m_data.slong >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.slong >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.slong >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.slong >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_ulong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulong >>= rhs.m_data.sint; break;
+ case e_uint: m_data.ulong >>= rhs.m_data.uint; break;
+ case e_slong: m_data.ulong >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulong >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulong >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulong >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+ case e_slonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.slonglong >>= rhs.m_data.sint; break;
+ case e_uint: m_data.slonglong >>= rhs.m_data.uint; break;
+ case e_slong: m_data.slonglong >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.slonglong >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.slonglong >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.slonglong >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_ulonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulonglong >>= rhs.m_data.sint; break;
+ case e_uint: m_data.ulonglong >>= rhs.m_data.uint; break;
+ case e_slong: m_data.ulonglong >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulonglong >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulonglong >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulonglong >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+ }
+ return *this;
+}
+
+
+Scalar&
+Scalar::operator&= (const Scalar& rhs)
+{
+ switch (m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+
+ case e_sint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.sint &= rhs.m_data.sint; break;
+ case e_uint: m_data.sint &= rhs.m_data.uint; break;
+ case e_slong: m_data.sint &= rhs.m_data.slong; break;
+ case e_ulong: m_data.sint &= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.sint &= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.sint &= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_uint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.uint &= rhs.m_data.sint; break;
+ case e_uint: m_data.uint &= rhs.m_data.uint; break;
+ case e_slong: m_data.uint &= rhs.m_data.slong; break;
+ case e_ulong: m_data.uint &= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.uint &= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.uint &= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_slong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.slong &= rhs.m_data.sint; break;
+ case e_uint: m_data.slong &= rhs.m_data.uint; break;
+ case e_slong: m_data.slong &= rhs.m_data.slong; break;
+ case e_ulong: m_data.slong &= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.slong &= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.slong &= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_ulong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulong &= rhs.m_data.sint; break;
+ case e_uint: m_data.ulong &= rhs.m_data.uint; break;
+ case e_slong: m_data.ulong &= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulong &= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulong &= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulong &= rhs.m_data.ulonglong; break;
+ }
+ break;
+ case e_slonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.slonglong &= rhs.m_data.sint; break;
+ case e_uint: m_data.slonglong &= rhs.m_data.uint; break;
+ case e_slong: m_data.slonglong &= rhs.m_data.slong; break;
+ case e_ulong: m_data.slonglong &= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.slonglong &= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.slonglong &= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_ulonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulonglong &= rhs.m_data.sint; break;
+ case e_uint: m_data.ulonglong &= rhs.m_data.uint; break;
+ case e_slong: m_data.ulonglong &= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulonglong &= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulonglong &= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulonglong &= rhs.m_data.ulonglong; break;
+ }
+ break;
+ }
+ return *this;
+}
+
+
+
+bool
+Scalar::AbsoluteValue()
+{
+ switch (m_type)
+ {
+ case e_void:
+ break;
+
+ case e_sint:
+ if (m_data.sint < 0)
+ m_data.sint = -m_data.sint;
+ return true;
+
+ case e_slong:
+ if (m_data.slong < 0)
+ m_data.slong = -m_data.slong;
+ return true;
+
+ case e_slonglong:
+ if (m_data.slonglong < 0)
+ m_data.slonglong = -m_data.slonglong;
+ return true;
+
+ case e_uint:
+ case e_ulong:
+ case e_ulonglong: return true;
+ case e_float: m_data.flt = fabsf(m_data.flt); return true;
+ case e_double: m_data.dbl = fabs(m_data.dbl); return true;
+ case e_long_double: m_data.ldbl = fabsl(m_data.ldbl); return true;
+ }
+ return false;
+}
+
+
+bool
+Scalar::UnaryNegate()
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: m_data.sint = -m_data.sint; return true;
+ case e_uint: m_data.uint = -m_data.uint; return true;
+ case e_slong: m_data.slong = -m_data.slong; return true;
+ case e_ulong: m_data.ulong = -m_data.ulong; return true;
+ case e_slonglong: m_data.slonglong = -m_data.slonglong; return true;
+ case e_ulonglong: m_data.ulonglong = -m_data.ulonglong; return true;
+ case e_float: m_data.flt = -m_data.flt; return true;
+ case e_double: m_data.dbl = -m_data.dbl; return true;
+ case e_long_double: m_data.ldbl = -m_data.ldbl; return true;
+ }
+ return false;
+}
+
+bool
+Scalar::OnesComplement()
+{
+ switch (m_type)
+ {
+ case e_sint: m_data.sint = ~m_data.sint; return true;
+ case e_uint: m_data.uint = ~m_data.uint; return true;
+ case e_slong: m_data.slong = ~m_data.slong; return true;
+ case e_ulong: m_data.ulong = ~m_data.ulong; return true;
+ case e_slonglong: m_data.slonglong = ~m_data.slonglong; return true;
+ case e_ulonglong: m_data.ulonglong = ~m_data.ulonglong; return true;
+
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ break;
+ }
+ return false;
+}
+
+
+const Scalar
+lldb_private::operator+ (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: result.m_data.sint = a->m_data.sint + b->m_data.sint; break;
+ case Scalar::e_uint: result.m_data.uint = a->m_data.uint + b->m_data.uint; break;
+ case Scalar::e_slong: result.m_data.slong = a->m_data.slong + b->m_data.slong; break;
+ case Scalar::e_ulong: result.m_data.ulong = a->m_data.ulong + b->m_data.ulong; break;
+ case Scalar::e_slonglong: result.m_data.slonglong = a->m_data.slonglong + b->m_data.slonglong; break;
+ case Scalar::e_ulonglong: result.m_data.ulonglong = a->m_data.ulonglong + b->m_data.ulonglong; break;
+ case Scalar::e_float: result.m_data.flt = a->m_data.flt + b->m_data.flt; break;
+ case Scalar::e_double: result.m_data.dbl = a->m_data.dbl + b->m_data.dbl; break;
+ case Scalar::e_long_double: result.m_data.ldbl = a->m_data.ldbl + b->m_data.ldbl; break;
+ }
+ }
+ return result;
+}
+
+
+const Scalar
+lldb_private::operator- (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: result.m_data.sint = a->m_data.sint - b->m_data.sint; break;
+ case Scalar::e_uint: result.m_data.uint = a->m_data.uint - b->m_data.uint; break;
+ case Scalar::e_slong: result.m_data.slong = a->m_data.slong - b->m_data.slong; break;
+ case Scalar::e_ulong: result.m_data.ulong = a->m_data.ulong - b->m_data.ulong; break;
+ case Scalar::e_slonglong: result.m_data.slonglong = a->m_data.slonglong - b->m_data.slonglong; break;
+ case Scalar::e_ulonglong: result.m_data.ulonglong = a->m_data.ulonglong - b->m_data.ulonglong; break;
+ case Scalar::e_float: result.m_data.flt = a->m_data.flt - b->m_data.flt; break;
+ case Scalar::e_double: result.m_data.dbl = a->m_data.dbl - b->m_data.dbl; break;
+ case Scalar::e_long_double: result.m_data.ldbl = a->m_data.ldbl - b->m_data.ldbl; break;
+ }
+ }
+ return result;
+}
+
+const Scalar
+lldb_private::operator/ (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_void: break;
+
+ case Scalar::e_sint: if (b->m_data.sint != 0) { result.m_data.sint = a->m_data.sint/ b->m_data.sint; return result; } break;
+ case Scalar::e_uint: if (b->m_data.uint != 0) { result.m_data.uint = a->m_data.uint / b->m_data.uint; return result; } break;
+ case Scalar::e_slong: if (b->m_data.slong != 0) { result.m_data.slong = a->m_data.slong / b->m_data.slong; return result; } break;
+ case Scalar::e_ulong: if (b->m_data.ulong != 0) { result.m_data.ulong = a->m_data.ulong / b->m_data.ulong; return result; } break;
+ case Scalar::e_slonglong: if (b->m_data.slonglong != 0) { result.m_data.slonglong = a->m_data.slonglong / b->m_data.slonglong; return result; } break;
+ case Scalar::e_ulonglong: if (b->m_data.ulonglong != 0) { result.m_data.ulonglong = a->m_data.ulonglong / b->m_data.ulonglong; return result; } break;
+ case Scalar::e_float: if (b->m_data.flt != 0.0f) { result.m_data.flt = a->m_data.flt / b->m_data.flt; return result; } break;
+ case Scalar::e_double: if (b->m_data.dbl != 0.0) { result.m_data.dbl = a->m_data.dbl / b->m_data.dbl; return result; } break;
+ case Scalar::e_long_double: if (b->m_data.ldbl != 0.0) { result.m_data.ldbl = a->m_data.ldbl / b->m_data.ldbl; return result; } break;
+ }
+ }
+ // For division only, the only way it should make it here is if a promotion failed,
+ // or if we are trying to do a divide by zero.
+ result.m_type = Scalar::e_void;
+ return result;
+}
+
+const Scalar
+lldb_private::operator* (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: result.m_data.sint = a->m_data.sint * b->m_data.sint; break;
+ case Scalar::e_uint: result.m_data.uint = a->m_data.uint * b->m_data.uint; break;
+ case Scalar::e_slong: result.m_data.slong = a->m_data.slong * b->m_data.slong; break;
+ case Scalar::e_ulong: result.m_data.ulong = a->m_data.ulong * b->m_data.ulong; break;
+ case Scalar::e_slonglong: result.m_data.slonglong = a->m_data.slonglong * b->m_data.slonglong; break;
+ case Scalar::e_ulonglong: result.m_data.ulonglong = a->m_data.ulonglong * b->m_data.ulonglong; break;
+ case Scalar::e_float: result.m_data.flt = a->m_data.flt * b->m_data.flt; break;
+ case Scalar::e_double: result.m_data.dbl = a->m_data.dbl * b->m_data.dbl; break;
+ case Scalar::e_long_double: result.m_data.ldbl = a->m_data.ldbl * b->m_data.ldbl; break;
+ }
+ }
+ return result;
+}
+
+const Scalar
+lldb_private::operator& (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_sint: result.m_data.sint = a->m_data.sint & b->m_data.sint; break;
+ case Scalar::e_uint: result.m_data.uint = a->m_data.uint & b->m_data.uint; break;
+ case Scalar::e_slong: result.m_data.slong = a->m_data.slong & b->m_data.slong; break;
+ case Scalar::e_ulong: result.m_data.ulong = a->m_data.ulong & b->m_data.ulong; break;
+ case Scalar::e_slonglong: result.m_data.slonglong = a->m_data.slonglong & b->m_data.slonglong; break;
+ case Scalar::e_ulonglong: result.m_data.ulonglong = a->m_data.ulonglong & b->m_data.ulonglong; break;
+
+ case Scalar::e_void:
+ case Scalar::e_float:
+ case Scalar::e_double:
+ case Scalar::e_long_double:
+ // No bitwise AND on floats, doubles of long doubles
+ result.m_type = Scalar::e_void;
+ break;
+ }
+ }
+ return result;
+}
+
+const Scalar
+lldb_private::operator| (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_sint: result.m_data.sint = a->m_data.sint | b->m_data.sint; break;
+ case Scalar::e_uint: result.m_data.uint = a->m_data.uint | b->m_data.uint; break;
+ case Scalar::e_slong: result.m_data.slong = a->m_data.slong | b->m_data.slong; break;
+ case Scalar::e_ulong: result.m_data.ulong = a->m_data.ulong | b->m_data.ulong; break;
+ case Scalar::e_slonglong: result.m_data.slonglong = a->m_data.slonglong | b->m_data.slonglong; break;
+ case Scalar::e_ulonglong: result.m_data.ulonglong = a->m_data.ulonglong | b->m_data.ulonglong; break;
+
+ case Scalar::e_void:
+ case Scalar::e_float:
+ case Scalar::e_double:
+ case Scalar::e_long_double:
+ // No bitwise AND on floats, doubles of long doubles
+ result.m_type = Scalar::e_void;
+ break;
+ }
+ }
+ return result;
+}
+
+const Scalar
+lldb_private::operator% (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ default: break;
+ case Scalar::e_sint: if (b->m_data.sint != 0) { result.m_data.sint = a->m_data.sint % b->m_data.sint; return result; } break;
+ case Scalar::e_uint: if (b->m_data.uint != 0) { result.m_data.uint = a->m_data.uint % b->m_data.uint; return result; } break;
+ case Scalar::e_slong: if (b->m_data.slong != 0) { result.m_data.slong = a->m_data.slong % b->m_data.slong; return result; } break;
+ case Scalar::e_ulong: if (b->m_data.ulong != 0) { result.m_data.ulong = a->m_data.ulong % b->m_data.ulong; return result; } break;
+ case Scalar::e_slonglong: if (b->m_data.slonglong != 0) { result.m_data.slonglong = a->m_data.slonglong % b->m_data.slonglong; return result; } break;
+ case Scalar::e_ulonglong: if (b->m_data.ulonglong != 0) { result.m_data.ulonglong = a->m_data.ulonglong % b->m_data.ulonglong; return result; } break;
+ }
+ }
+ result.m_type = Scalar::e_void;
+ return result;
+}
+
+const Scalar
+lldb_private::operator^ (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_sint: result.m_data.sint = a->m_data.sint ^ b->m_data.sint; break;
+ case Scalar::e_uint: result.m_data.uint = a->m_data.uint ^ b->m_data.uint; break;
+ case Scalar::e_slong: result.m_data.slong = a->m_data.slong ^ b->m_data.slong; break;
+ case Scalar::e_ulong: result.m_data.ulong = a->m_data.ulong ^ b->m_data.ulong; break;
+ case Scalar::e_slonglong: result.m_data.slonglong = a->m_data.slonglong ^ b->m_data.slonglong; break;
+ case Scalar::e_ulonglong: result.m_data.ulonglong = a->m_data.ulonglong ^ b->m_data.ulonglong; break;
+
+ case Scalar::e_void:
+ case Scalar::e_float:
+ case Scalar::e_double:
+ case Scalar::e_long_double:
+ // No bitwise AND on floats, doubles of long doubles
+ result.m_type = Scalar::e_void;
+ break;
+ }
+ }
+ return result;
+}
+
+const Scalar
+lldb_private::operator<< (const Scalar& lhs, const Scalar &rhs)
+{
+ Scalar result = lhs;
+ result <<= rhs;
+ return result;
+}
+
+const Scalar
+lldb_private::operator>> (const Scalar& lhs, const Scalar &rhs)
+{
+ Scalar result = lhs;
+ result >>= rhs;
+ return result;
+}
+
+// Return the raw unsigned integer without any casting or conversion
+unsigned int
+Scalar::RawUInt () const
+{
+ return m_data.uint;
+}
+
+// Return the raw unsigned long without any casting or conversion
+unsigned long
+Scalar::RawULong () const
+{
+ return m_data.ulong;
+}
+
+// Return the raw unsigned long long without any casting or conversion
+unsigned long long
+Scalar::RawULongLong () const
+{
+ return m_data.ulonglong;
+}
+
+
+Error
+Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t byte_size)
+{
+ Error error;
+ if (value_str == NULL || value_str[0] == '\0')
+ {
+ error.SetErrorString ("Invalid c-string value string.");
+ return error;
+ }
+ bool success = false;
+ switch (encoding)
+ {
+ case eEncodingInvalid:
+ error.SetErrorString ("Invalid encoding.");
+ break;
+
+ case eEncodingUint:
+ if (byte_size <= sizeof (unsigned long long))
+ {
+ uint64_t uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("'%s' is not a valid unsigned integer string value", value_str);
+ else if (!UIntValueIsValidForSize (uval64, byte_size))
+ error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %zu byte unsigned integer value", uval64, byte_size);
+ else
+ {
+ m_type = Scalar::GetValueTypeForUnsignedIntegerWithByteSize (byte_size);
+ switch (m_type)
+ {
+ case e_uint: m_data.uint = (uint_t)uval64; break;
+ case e_ulong: m_data.ulong = (ulong_t)uval64; break;
+ case e_ulonglong: m_data.ulonglong = (ulonglong_t)uval64; break;
+ default:
+ error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %zu", byte_size);
+ break;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %zu", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingSint:
+ if (byte_size <= sizeof (long long))
+ {
+ uint64_t sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("'%s' is not a valid signed integer string value", value_str);
+ else if (!SIntValueIsValidForSize (sval64, byte_size))
+ error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %zu byte signed integer value", sval64, byte_size);
+ else
+ {
+ m_type = Scalar::GetValueTypeForSignedIntegerWithByteSize (byte_size);
+ switch (m_type)
+ {
+ case e_sint: m_data.sint = (sint_t)sval64; break;
+ case e_slong: m_data.slong = (slong_t)sval64; break;
+ case e_slonglong: m_data.slonglong = (slonglong_t)sval64; break;
+ default:
+ error.SetErrorStringWithFormat ("unsupported signed integer byte size: %zu", byte_size);
+ break;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported signed integer byte size: %zu", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingIEEE754:
+ if (byte_size == sizeof (float))
+ {
+ if (::sscanf (value_str, "%f", &m_data.flt) == 1)
+ m_type = e_float;
+ else
+ error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
+ }
+ else if (byte_size == sizeof (double))
+ {
+ if (::sscanf (value_str, "%lf", &m_data.dbl) == 1)
+ m_type = e_double;
+ else
+ error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
+ }
+ else if (byte_size == sizeof (long double))
+ {
+ if (::sscanf (value_str, "%Lf", &m_data.ldbl) == 1)
+ m_type = e_long_double;
+ else
+ error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported float byte size: %zu", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingVector:
+ error.SetErrorString ("vector encoding unsupported.");
+ break;
+ }
+ if (error.Fail())
+ m_type = e_void;
+
+ return error;
+}
+
+Error
+Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t byte_size)
+{
+ Error error;
+
+ switch (encoding)
+ {
+ case lldb::eEncodingInvalid:
+ error.SetErrorString ("invalid encoding");
+ break;
+ case lldb::eEncodingVector:
+ error.SetErrorString ("vector encoding unsupported");
+ break;
+ case lldb::eEncodingUint:
+ {
+ lldb::offset_t offset;
+
+ switch (byte_size)
+ {
+ case 1: operator=((uint8_t)data.GetU8(&offset)); break;
+ case 2: operator=((uint16_t)data.GetU16(&offset)); break;
+ case 4: operator=((uint32_t)data.GetU32(&offset)); break;
+ case 8: operator=((uint64_t)data.GetU64(&offset)); break;
+ default:
+ error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %zu", byte_size);
+ break;
+ }
+ }
+ break;
+ case lldb::eEncodingSint:
+ {
+ lldb::offset_t offset;
+
+ switch (byte_size)
+ {
+ case 1: operator=((int8_t)data.GetU8(&offset)); break;
+ case 2: operator=((int16_t)data.GetU16(&offset)); break;
+ case 4: operator=((int32_t)data.GetU32(&offset)); break;
+ case 8: operator=((int64_t)data.GetU64(&offset)); break;
+ default:
+ error.SetErrorStringWithFormat ("unsupported signed integer byte size: %zu", byte_size);
+ break;
+ }
+ }
+ break;
+ case lldb::eEncodingIEEE754:
+ {
+ lldb::offset_t offset;
+
+ if (byte_size == sizeof (float))
+ operator=((float)data.GetFloat(&offset));
+ else if (byte_size == sizeof (double))
+ operator=((double)data.GetDouble(&offset));
+ else if (byte_size == sizeof (long double))
+ operator=((long double)data.GetLongDouble(&offset));
+ else
+ error.SetErrorStringWithFormat ("unsupported float byte size: %zu", byte_size);
+ }
+ break;
+ }
+
+ return error;
+}
+
+bool
+Scalar::SignExtend (uint32_t sign_bit_pos)
+{
+ const uint32_t max_bit_pos = GetByteSize() * 8;
+
+ if (sign_bit_pos < max_bit_pos)
+ {
+ switch (m_type)
+ {
+ case Scalar::e_void:
+ case Scalar::e_float:
+ case Scalar::e_double:
+ case Scalar::e_long_double:
+ return false;
+
+ case Scalar::e_sint:
+ case Scalar::e_uint:
+ if (max_bit_pos == sign_bit_pos)
+ return true;
+ else if (sign_bit_pos < (max_bit_pos-1))
+ {
+ unsigned int sign_bit = 1u << sign_bit_pos;
+ if (m_data.uint & sign_bit)
+ {
+ const unsigned int mask = ~(sign_bit) + 1u;
+ m_data.uint |= mask;
+ }
+ return true;
+ }
+ break;
+
+ case Scalar::e_slong:
+ case Scalar::e_ulong:
+ if (max_bit_pos == sign_bit_pos)
+ return true;
+ else if (sign_bit_pos < (max_bit_pos-1))
+ {
+ unsigned long sign_bit = 1ul << sign_bit_pos;
+ if (m_data.ulong & sign_bit)
+ {
+ const unsigned long mask = ~(sign_bit) + 1ul;
+ m_data.ulong |= mask;
+ }
+ return true;
+ }
+ break;
+
+ case Scalar::e_slonglong:
+ case Scalar::e_ulonglong:
+ if (max_bit_pos == sign_bit_pos)
+ return true;
+ else if (sign_bit_pos < (max_bit_pos-1))
+ {
+ unsigned long long sign_bit = 1ull << sign_bit_pos;
+ if (m_data.ulonglong & sign_bit)
+ {
+ const unsigned long long mask = ~(sign_bit) + 1ull;
+ m_data.ulonglong |= mask;
+ }
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+size_t
+Scalar::GetAsMemoryData (void *dst,
+ size_t dst_len,
+ lldb::ByteOrder dst_byte_order,
+ Error &error) const
+{
+ // Get a data extractor that points to the native scalar data
+ DataExtractor data;
+ if (!GetData(data))
+ {
+ error.SetErrorString ("invalid scalar value");
+ return 0;
+ }
+
+ const size_t src_len = data.GetByteSize();
+
+ // Prepare a memory buffer that contains some or all of the register value
+ const size_t bytes_copied = data.CopyByteOrderedData (0, // src offset
+ src_len, // src length
+ dst, // dst buffer
+ dst_len, // dst length
+ dst_byte_order); // dst byte order
+ if (bytes_copied == 0)
+ error.SetErrorString ("failed to copy data");
+
+ return bytes_copied;
+}
+
+bool
+Scalar::ExtractBitfield (uint32_t bit_size,
+ uint32_t bit_offset)
+{
+ if (bit_size == 0)
+ return true;
+
+ uint32_t msbit = bit_offset + bit_size - 1;
+ uint32_t lsbit = bit_offset;
+ switch (m_type)
+ {
+ case Scalar::e_void:
+ break;
+
+ case e_float:
+ if (sizeof(m_data.flt) == sizeof(sint_t))
+ m_data.sint = (sint_t)SignedBits (m_data.sint, msbit, lsbit);
+ else if (sizeof(m_data.flt) == sizeof(ulong_t))
+ m_data.slong = (slong_t)SignedBits (m_data.slong, msbit, lsbit);
+ else if (sizeof(m_data.flt) == sizeof(ulonglong_t))
+ m_data.slonglong = (slonglong_t)SignedBits (m_data.slonglong, msbit, lsbit);
+ else
+ return false;
+ return true;
+
+ case e_double:
+ if (sizeof(m_data.dbl) == sizeof(sint_t))
+ m_data.sint = SignedBits (m_data.sint, msbit, lsbit);
+ else if (sizeof(m_data.dbl) == sizeof(ulong_t))
+ m_data.slong = SignedBits (m_data.slong, msbit, lsbit);
+ else if (sizeof(m_data.dbl) == sizeof(ulonglong_t))
+ m_data.slonglong = SignedBits (m_data.slonglong, msbit, lsbit);
+ else
+ return false;
+ return true;
+
+ case e_long_double:
+ if (sizeof(m_data.ldbl) == sizeof(sint_t))
+ m_data.sint = SignedBits (m_data.sint, msbit, lsbit);
+ else if (sizeof(m_data.ldbl) == sizeof(ulong_t))
+ m_data.slong = SignedBits (m_data.slong, msbit, lsbit);
+ else if (sizeof(m_data.ldbl) == sizeof(ulonglong_t))
+ m_data.slonglong = SignedBits (m_data.slonglong, msbit, lsbit);
+ else
+ return false;
+ return true;
+
+ case Scalar::e_sint:
+ m_data.sint = (sint_t)SignedBits (m_data.sint, msbit, lsbit);
+ return true;
+
+ case Scalar::e_uint:
+ m_data.uint = (uint_t)UnsignedBits (m_data.uint, msbit, lsbit);
+ return true;
+
+ case Scalar::e_slong:
+ m_data.slong = (slong_t)SignedBits (m_data.slong, msbit, lsbit);
+ return true;
+
+ case Scalar::e_ulong:
+ m_data.ulong = (ulong_t)UnsignedBits (m_data.ulong, msbit, lsbit);
+ return true;
+
+ case Scalar::e_slonglong:
+ m_data.slonglong = (slonglong_t)SignedBits (m_data.slonglong, msbit, lsbit);
+ return true;
+
+ case Scalar::e_ulonglong:
+ m_data.ulonglong = (ulonglong_t)UnsignedBits (m_data.ulonglong, msbit, lsbit);
+ return true;
+ }
+ return false;
+}
+
+
+
+
+
+bool
+lldb_private::operator== (const Scalar& lhs, const Scalar& rhs)
+{
+ // If either entry is void then we can just compare the types
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return lhs.m_type == rhs.m_type;
+
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ switch (PromoteToMaxType(lhs, rhs, temp_value, a, b))
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: return a->m_data.sint == b->m_data.sint;
+ case Scalar::e_uint: return a->m_data.uint == b->m_data.uint;
+ case Scalar::e_slong: return a->m_data.slong == b->m_data.slong;
+ case Scalar::e_ulong: return a->m_data.ulong == b->m_data.ulong;
+ case Scalar::e_slonglong: return a->m_data.slonglong == b->m_data.slonglong;
+ case Scalar::e_ulonglong: return a->m_data.ulonglong == b->m_data.ulonglong;
+ case Scalar::e_float: return a->m_data.flt == b->m_data.flt;
+ case Scalar::e_double: return a->m_data.dbl == b->m_data.dbl;
+ case Scalar::e_long_double: return a->m_data.ldbl == b->m_data.ldbl;
+ }
+ return false;
+}
+
+bool
+lldb_private::operator!= (const Scalar& lhs, const Scalar& rhs)
+{
+ // If either entry is void then we can just compare the types
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return lhs.m_type != rhs.m_type;
+
+ Scalar temp_value; // A temp value that might get a copy of either promoted value
+ const Scalar* a;
+ const Scalar* b;
+ switch (PromoteToMaxType(lhs, rhs, temp_value, a, b))
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: return a->m_data.sint != b->m_data.sint;
+ case Scalar::e_uint: return a->m_data.uint != b->m_data.uint;
+ case Scalar::e_slong: return a->m_data.slong != b->m_data.slong;
+ case Scalar::e_ulong: return a->m_data.ulong != b->m_data.ulong;
+ case Scalar::e_slonglong: return a->m_data.slonglong != b->m_data.slonglong;
+ case Scalar::e_ulonglong: return a->m_data.ulonglong != b->m_data.ulonglong;
+ case Scalar::e_float: return a->m_data.flt != b->m_data.flt;
+ case Scalar::e_double: return a->m_data.dbl != b->m_data.dbl;
+ case Scalar::e_long_double: return a->m_data.ldbl != b->m_data.ldbl;
+ }
+ return true;
+}
+
+bool
+lldb_private::operator< (const Scalar& lhs, const Scalar& rhs)
+{
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return false;
+
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ switch (PromoteToMaxType(lhs, rhs, temp_value, a, b))
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: return a->m_data.sint < b->m_data.sint;
+ case Scalar::e_uint: return a->m_data.uint < b->m_data.uint;
+ case Scalar::e_slong: return a->m_data.slong < b->m_data.slong;
+ case Scalar::e_ulong: return a->m_data.ulong < b->m_data.ulong;
+ case Scalar::e_slonglong: return a->m_data.slonglong < b->m_data.slonglong;
+ case Scalar::e_ulonglong: return a->m_data.ulonglong < b->m_data.ulonglong;
+ case Scalar::e_float: return a->m_data.flt < b->m_data.flt;
+ case Scalar::e_double: return a->m_data.dbl < b->m_data.dbl;
+ case Scalar::e_long_double: return a->m_data.ldbl < b->m_data.ldbl;
+ }
+ return false;
+}
+
+bool
+lldb_private::operator<= (const Scalar& lhs, const Scalar& rhs)
+{
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return false;
+
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ switch (PromoteToMaxType(lhs, rhs, temp_value, a, b))
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: return a->m_data.sint <= b->m_data.sint;
+ case Scalar::e_uint: return a->m_data.uint <= b->m_data.uint;
+ case Scalar::e_slong: return a->m_data.slong <= b->m_data.slong;
+ case Scalar::e_ulong: return a->m_data.ulong <= b->m_data.ulong;
+ case Scalar::e_slonglong: return a->m_data.slonglong <= b->m_data.slonglong;
+ case Scalar::e_ulonglong: return a->m_data.ulonglong <= b->m_data.ulonglong;
+ case Scalar::e_float: return a->m_data.flt <= b->m_data.flt;
+ case Scalar::e_double: return a->m_data.dbl <= b->m_data.dbl;
+ case Scalar::e_long_double: return a->m_data.ldbl <= b->m_data.ldbl;
+ }
+ return false;
+}
+
+
+bool
+lldb_private::operator> (const Scalar& lhs, const Scalar& rhs)
+{
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return false;
+
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ switch (PromoteToMaxType(lhs, rhs, temp_value, a, b))
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: return a->m_data.sint > b->m_data.sint;
+ case Scalar::e_uint: return a->m_data.uint > b->m_data.uint;
+ case Scalar::e_slong: return a->m_data.slong > b->m_data.slong;
+ case Scalar::e_ulong: return a->m_data.ulong > b->m_data.ulong;
+ case Scalar::e_slonglong: return a->m_data.slonglong > b->m_data.slonglong;
+ case Scalar::e_ulonglong: return a->m_data.ulonglong > b->m_data.ulonglong;
+ case Scalar::e_float: return a->m_data.flt > b->m_data.flt;
+ case Scalar::e_double: return a->m_data.dbl > b->m_data.dbl;
+ case Scalar::e_long_double: return a->m_data.ldbl > b->m_data.ldbl;
+ }
+ return false;
+}
+
+bool
+lldb_private::operator>= (const Scalar& lhs, const Scalar& rhs)
+{
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return false;
+
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ switch (PromoteToMaxType(lhs, rhs, temp_value, a, b))
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: return a->m_data.sint >= b->m_data.sint;
+ case Scalar::e_uint: return a->m_data.uint >= b->m_data.uint;
+ case Scalar::e_slong: return a->m_data.slong >= b->m_data.slong;
+ case Scalar::e_ulong: return a->m_data.ulong >= b->m_data.ulong;
+ case Scalar::e_slonglong: return a->m_data.slonglong >= b->m_data.slonglong;
+ case Scalar::e_ulonglong: return a->m_data.ulonglong >= b->m_data.ulonglong;
+ case Scalar::e_float: return a->m_data.flt >= b->m_data.flt;
+ case Scalar::e_double: return a->m_data.dbl >= b->m_data.dbl;
+ case Scalar::e_long_double: return a->m_data.ldbl >= b->m_data.ldbl;
+ }
+ return false;
+}
+
+
+
+
diff --git a/source/Core/SearchFilter.cpp b/source/Core/SearchFilter.cpp
new file mode 100644
index 0000000..54937c0
--- /dev/null
+++ b/source/Core/SearchFilter.cpp
@@ -0,0 +1,816 @@
+//===-- SearchFilter.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// SearchFilter constructor
+//----------------------------------------------------------------------
+Searcher::Searcher ()
+{
+
+}
+
+Searcher::~Searcher ()
+{
+
+}
+
+void
+Searcher::GetDescription (Stream *s)
+{
+}
+
+//----------------------------------------------------------------------
+// SearchFilter constructor
+//----------------------------------------------------------------------
+SearchFilter::SearchFilter(const TargetSP &target_sp) :
+ m_target_sp (target_sp)
+{
+}
+
+//----------------------------------------------------------------------
+// SearchFilter copy constructor
+//----------------------------------------------------------------------
+SearchFilter::SearchFilter(const SearchFilter& rhs) :
+ m_target_sp (rhs.m_target_sp)
+{
+}
+
+//----------------------------------------------------------------------
+// SearchFilter assignment operator
+//----------------------------------------------------------------------
+const SearchFilter&
+SearchFilter::operator=(const SearchFilter& rhs)
+{
+ m_target_sp = rhs.m_target_sp;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SearchFilter::~SearchFilter()
+{
+}
+
+bool
+SearchFilter::ModulePasses (const FileSpec &spec)
+{
+ return true;
+}
+
+bool
+SearchFilter::ModulePasses (const ModuleSP &module_sp)
+{
+ return true;
+}
+
+bool
+SearchFilter::AddressPasses (Address &address)
+{
+ return true;
+}
+
+bool
+SearchFilter::CompUnitPasses (FileSpec &fileSpec)
+{
+ return true;
+}
+
+bool
+SearchFilter::CompUnitPasses (CompileUnit &compUnit)
+{
+ return true;
+}
+
+uint32_t
+SearchFilter::GetFilterRequiredItems()
+{
+ return (lldb::SymbolContextItem) 0;
+}
+
+void
+SearchFilter::GetDescription (Stream *s)
+{
+}
+
+void
+SearchFilter::Dump (Stream *s) const
+{
+
+}
+
+//----------------------------------------------------------------------
+// UTILITY Functions to help iterate down through the elements of the
+// SymbolContext.
+//----------------------------------------------------------------------
+
+void
+SearchFilter::Search (Searcher &searcher)
+{
+ SymbolContext empty_sc;
+
+ if (!m_target_sp)
+ return;
+ empty_sc.target_sp = m_target_sp;
+
+ if (searcher.GetDepth() == Searcher::eDepthTarget)
+ searcher.SearchCallback (*this, empty_sc, NULL, false);
+ else
+ DoModuleIteration(empty_sc, searcher);
+}
+
+void
+SearchFilter::SearchInModuleList (Searcher &searcher, ModuleList &modules)
+{
+ SymbolContext empty_sc;
+
+ if (!m_target_sp)
+ return;
+ empty_sc.target_sp = m_target_sp;
+
+ if (searcher.GetDepth() == Searcher::eDepthTarget)
+ searcher.SearchCallback (*this, empty_sc, NULL, false);
+ else
+ {
+ Mutex::Locker modules_locker(modules.GetMutex());
+ const size_t numModules = modules.GetSize();
+
+ for (size_t i = 0; i < numModules; i++)
+ {
+ ModuleSP module_sp(modules.GetModuleAtIndexUnlocked(i));
+ if (ModulePasses(module_sp))
+ {
+ if (DoModuleIteration(module_sp, searcher) == Searcher::eCallbackReturnStop)
+ return;
+ }
+ }
+ }
+}
+
+
+Searcher::CallbackReturn
+SearchFilter::DoModuleIteration (const lldb::ModuleSP& module_sp, Searcher &searcher)
+{
+ SymbolContext matchingContext (m_target_sp, module_sp);
+ return DoModuleIteration(matchingContext, searcher);
+}
+
+Searcher::CallbackReturn
+SearchFilter::DoModuleIteration (const SymbolContext &context, Searcher &searcher)
+{
+ if (searcher.GetDepth () >= Searcher::eDepthModule)
+ {
+ if (context.module_sp)
+ {
+ if (searcher.GetDepth () == Searcher::eDepthModule)
+ {
+ SymbolContext matchingContext(context.module_sp.get());
+ searcher.SearchCallback (*this, matchingContext, NULL, false);
+ }
+ else
+ {
+ return DoCUIteration(context.module_sp, context, searcher);
+ }
+ }
+ else
+ {
+ const ModuleList &target_images = m_target_sp->GetImages();
+ Mutex::Locker modules_locker(target_images.GetMutex());
+
+ size_t n_modules = target_images.GetSize();
+ for (size_t i = 0; i < n_modules; i++)
+ {
+ // If this is the last level supplied, then call the callback directly,
+ // otherwise descend.
+ ModuleSP module_sp(target_images.GetModuleAtIndexUnlocked (i));
+ if (!ModulePasses (module_sp))
+ continue;
+
+ if (searcher.GetDepth () == Searcher::eDepthModule)
+ {
+ SymbolContext matchingContext(m_target_sp, module_sp);
+
+ Searcher::CallbackReturn shouldContinue = searcher.SearchCallback (*this, matchingContext, NULL, false);
+ if (shouldContinue == Searcher::eCallbackReturnStop
+ || shouldContinue == Searcher::eCallbackReturnPop)
+ return shouldContinue;
+ }
+ else
+ {
+ Searcher::CallbackReturn shouldContinue = DoCUIteration(module_sp, context, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return shouldContinue;
+ else if (shouldContinue == Searcher::eCallbackReturnPop)
+ continue;
+ }
+ }
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::CallbackReturn
+SearchFilter::DoCUIteration (const ModuleSP &module_sp, const SymbolContext &context, Searcher &searcher)
+{
+ Searcher::CallbackReturn shouldContinue;
+ if (context.comp_unit == NULL)
+ {
+ const size_t num_comp_units = module_sp->GetNumCompileUnits();
+ for (size_t i = 0; i < num_comp_units; i++)
+ {
+ CompUnitSP cu_sp (module_sp->GetCompileUnitAtIndex (i));
+ if (cu_sp)
+ {
+ if (!CompUnitPasses (*(cu_sp.get())))
+ continue;
+
+ if (searcher.GetDepth () == Searcher::eDepthCompUnit)
+ {
+ SymbolContext matchingContext(m_target_sp, module_sp, cu_sp.get());
+
+ shouldContinue = searcher.SearchCallback (*this, matchingContext, NULL, false);
+
+ if (shouldContinue == Searcher::eCallbackReturnPop)
+ return Searcher::eCallbackReturnContinue;
+ else if (shouldContinue == Searcher::eCallbackReturnStop)
+ return shouldContinue;
+ }
+ else
+ {
+ // FIXME Descend to block.
+ }
+ }
+ }
+ }
+ else
+ {
+ if (CompUnitPasses(*context.comp_unit))
+ {
+ SymbolContext matchingContext (m_target_sp, module_sp, context.comp_unit);
+ return searcher.SearchCallback (*this, matchingContext, NULL, false);
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::CallbackReturn
+SearchFilter::DoFunctionIteration (Function *function, const SymbolContext &context, Searcher &searcher)
+{
+ // FIXME: Implement...
+ return Searcher::eCallbackReturnContinue;
+}
+
+//----------------------------------------------------------------------
+// SearchFilterForNonModuleSpecificSearches:
+// Selects a shared library matching a given file spec, consulting the targets "black list".
+//----------------------------------------------------------------------
+
+ bool
+ SearchFilterForNonModuleSpecificSearches::ModulePasses (const FileSpec &module_spec)
+ {
+ if (m_target_sp->ModuleIsExcludedForNonModuleSpecificSearches (module_spec))
+ return false;
+ else
+ return true;
+ }
+
+ bool
+ SearchFilterForNonModuleSpecificSearches::ModulePasses (const lldb::ModuleSP &module_sp)
+ {
+ if (!module_sp)
+ return true;
+ else if (m_target_sp->ModuleIsExcludedForNonModuleSpecificSearches (module_sp))
+ return false;
+ else
+ return true;
+ }
+
+//----------------------------------------------------------------------
+// SearchFilterByModule:
+// Selects a shared library matching a given file spec
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// SearchFilterByModule constructors
+//----------------------------------------------------------------------
+
+SearchFilterByModule::SearchFilterByModule (const lldb::TargetSP &target_sp, const FileSpec &module) :
+ SearchFilter (target_sp),
+ m_module_spec (module)
+{
+}
+
+
+//----------------------------------------------------------------------
+// SearchFilterByModule copy constructor
+//----------------------------------------------------------------------
+SearchFilterByModule::SearchFilterByModule(const SearchFilterByModule& rhs) :
+ SearchFilter (rhs),
+ m_module_spec (rhs.m_module_spec)
+{
+}
+
+//----------------------------------------------------------------------
+// SearchFilterByModule assignment operator
+//----------------------------------------------------------------------
+const SearchFilterByModule&
+SearchFilterByModule::operator=(const SearchFilterByModule& rhs)
+{
+ m_target_sp = rhs.m_target_sp;
+ m_module_spec = rhs.m_module_spec;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SearchFilterByModule::~SearchFilterByModule()
+{
+}
+
+bool
+SearchFilterByModule::ModulePasses (const ModuleSP &module_sp)
+{
+ if (module_sp && FileSpec::Equal(module_sp->GetFileSpec(), m_module_spec, false))
+ return true;
+ else
+ return false;
+}
+
+bool
+SearchFilterByModule::ModulePasses (const FileSpec &spec)
+{
+ // Do a full match only if "spec" has a directory
+ const bool full_match = spec.GetDirectory();
+ return FileSpec::Equal(spec, m_module_spec, full_match);
+}
+
+bool
+SearchFilterByModule::AddressPasses (Address &address)
+{
+ // FIXME: Not yet implemented
+ return true;
+}
+
+
+bool
+SearchFilterByModule::CompUnitPasses (FileSpec &fileSpec)
+{
+ return true;
+}
+
+bool
+SearchFilterByModule::CompUnitPasses (CompileUnit &compUnit)
+{
+ return true;
+}
+
+void
+SearchFilterByModule::Search (Searcher &searcher)
+{
+ if (!m_target_sp)
+ return;
+
+ if (searcher.GetDepth() == Searcher::eDepthTarget)
+ {
+ SymbolContext empty_sc;
+ empty_sc.target_sp = m_target_sp;
+ searcher.SearchCallback (*this, empty_sc, NULL, false);
+ }
+
+ // If the module file spec is a full path, then we can just find the one
+ // filespec that passes. Otherwise, we need to go through all modules and
+ // find the ones that match the file name.
+
+ const ModuleList &target_modules = m_target_sp->GetImages();
+ Mutex::Locker modules_locker (target_modules.GetMutex());
+
+ const size_t num_modules = target_modules.GetSize ();
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ Module* module = target_modules.GetModulePointerAtIndexUnlocked(i);
+ const bool full_match = m_module_spec.GetDirectory();
+ if (FileSpec::Equal (m_module_spec, module->GetFileSpec(), full_match))
+ {
+ SymbolContext matchingContext(m_target_sp, module->shared_from_this());
+ Searcher::CallbackReturn shouldContinue;
+
+ shouldContinue = DoModuleIteration(matchingContext, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return;
+ }
+ }
+}
+
+void
+SearchFilterByModule::GetDescription (Stream *s)
+{
+ s->PutCString(", module = ");
+ if (s->GetVerbose())
+ {
+ char buffer[2048];
+ m_module_spec.GetPath(buffer, 2047);
+ s->PutCString(buffer);
+ }
+ else
+ {
+ s->PutCString(m_module_spec.GetFilename().AsCString("<unknown>"));
+ }
+}
+
+uint32_t
+SearchFilterByModule::GetFilterRequiredItems()
+{
+ return eSymbolContextModule;
+}
+
+void
+SearchFilterByModule::Dump (Stream *s) const
+{
+
+}
+//----------------------------------------------------------------------
+// SearchFilterByModuleList:
+// Selects a shared library matching a given file spec
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleList constructors
+//----------------------------------------------------------------------
+
+SearchFilterByModuleList::SearchFilterByModuleList (const lldb::TargetSP &target_sp, const FileSpecList &module_list) :
+ SearchFilter (target_sp),
+ m_module_spec_list (module_list)
+{
+}
+
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleList copy constructor
+//----------------------------------------------------------------------
+SearchFilterByModuleList::SearchFilterByModuleList(const SearchFilterByModuleList& rhs) :
+ SearchFilter (rhs),
+ m_module_spec_list (rhs.m_module_spec_list)
+{
+}
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleList assignment operator
+//----------------------------------------------------------------------
+const SearchFilterByModuleList&
+SearchFilterByModuleList::operator=(const SearchFilterByModuleList& rhs)
+{
+ m_target_sp = rhs.m_target_sp;
+ m_module_spec_list = rhs.m_module_spec_list;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SearchFilterByModuleList::~SearchFilterByModuleList()
+{
+}
+
+bool
+SearchFilterByModuleList::ModulePasses (const ModuleSP &module_sp)
+{
+ if (m_module_spec_list.GetSize() == 0)
+ return true;
+
+ if (module_sp && m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) != UINT32_MAX)
+ return true;
+ else
+ return false;
+}
+
+bool
+SearchFilterByModuleList::ModulePasses (const FileSpec &spec)
+{
+ if (m_module_spec_list.GetSize() == 0)
+ return true;
+
+ if (m_module_spec_list.FindFileIndex(0, spec, true) != UINT32_MAX)
+ return true;
+ else
+ return false;
+}
+
+bool
+SearchFilterByModuleList::AddressPasses (Address &address)
+{
+ // FIXME: Not yet implemented
+ return true;
+}
+
+
+bool
+SearchFilterByModuleList::CompUnitPasses (FileSpec &fileSpec)
+{
+ return true;
+}
+
+bool
+SearchFilterByModuleList::CompUnitPasses (CompileUnit &compUnit)
+{
+ return true;
+}
+
+void
+SearchFilterByModuleList::Search (Searcher &searcher)
+{
+ if (!m_target_sp)
+ return;
+
+ if (searcher.GetDepth() == Searcher::eDepthTarget)
+ {
+ SymbolContext empty_sc;
+ empty_sc.target_sp = m_target_sp;
+ searcher.SearchCallback (*this, empty_sc, NULL, false);
+ }
+
+ // If the module file spec is a full path, then we can just find the one
+ // filespec that passes. Otherwise, we need to go through all modules and
+ // find the ones that match the file name.
+
+ const ModuleList &target_modules = m_target_sp->GetImages();
+ Mutex::Locker modules_locker (target_modules.GetMutex());
+
+ const size_t num_modules = target_modules.GetSize ();
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ Module* module = target_modules.GetModulePointerAtIndexUnlocked(i);
+ if (m_module_spec_list.FindFileIndex(0, module->GetFileSpec(), false) != UINT32_MAX)
+ {
+ SymbolContext matchingContext(m_target_sp, module->shared_from_this());
+ Searcher::CallbackReturn shouldContinue;
+
+ shouldContinue = DoModuleIteration(matchingContext, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return;
+ }
+ }
+}
+
+void
+SearchFilterByModuleList::GetDescription (Stream *s)
+{
+ size_t num_modules = m_module_spec_list.GetSize();
+ if (num_modules == 1)
+ {
+ s->Printf (", module = ");
+ if (s->GetVerbose())
+ {
+ char buffer[2048];
+ m_module_spec_list.GetFileSpecAtIndex(0).GetPath(buffer, 2047);
+ s->PutCString(buffer);
+ }
+ else
+ {
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString("<unknown>"));
+ }
+ }
+ else
+ {
+ s->Printf (", modules(%zu) = ", num_modules);
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ if (s->GetVerbose())
+ {
+ char buffer[2048];
+ m_module_spec_list.GetFileSpecAtIndex(i).GetPath(buffer, 2047);
+ s->PutCString(buffer);
+ }
+ else
+ {
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString("<unknown>"));
+ }
+ if (i != num_modules - 1)
+ s->PutCString (", ");
+ }
+ }
+}
+
+uint32_t
+SearchFilterByModuleList::GetFilterRequiredItems()
+{
+ return eSymbolContextModule;
+}
+
+void
+SearchFilterByModuleList::Dump (Stream *s) const
+{
+
+}
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleListAndCU:
+// Selects a shared library matching a given file spec
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleListAndCU constructors
+//----------------------------------------------------------------------
+
+SearchFilterByModuleListAndCU::SearchFilterByModuleListAndCU (const lldb::TargetSP &target_sp,
+ const FileSpecList &module_list,
+ const FileSpecList &cu_list) :
+ SearchFilterByModuleList (target_sp, module_list),
+ m_cu_spec_list (cu_list)
+{
+}
+
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleListAndCU copy constructor
+//----------------------------------------------------------------------
+SearchFilterByModuleListAndCU::SearchFilterByModuleListAndCU(const SearchFilterByModuleListAndCU& rhs) :
+ SearchFilterByModuleList (rhs),
+ m_cu_spec_list (rhs.m_cu_spec_list)
+{
+}
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleListAndCU assignment operator
+//----------------------------------------------------------------------
+const SearchFilterByModuleListAndCU&
+SearchFilterByModuleListAndCU::operator=(const SearchFilterByModuleListAndCU& rhs)
+{
+ if (&rhs != this)
+ {
+ m_target_sp = rhs.m_target_sp;
+ m_module_spec_list = rhs.m_module_spec_list;
+ m_cu_spec_list = rhs.m_cu_spec_list;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SearchFilterByModuleListAndCU::~SearchFilterByModuleListAndCU()
+{
+}
+
+bool
+SearchFilterByModuleListAndCU::AddressPasses (Address &address)
+{
+ return true;
+}
+
+
+bool
+SearchFilterByModuleListAndCU::CompUnitPasses (FileSpec &fileSpec)
+{
+ return m_cu_spec_list.FindFileIndex(0, fileSpec, false) != UINT32_MAX;
+}
+
+bool
+SearchFilterByModuleListAndCU::CompUnitPasses (CompileUnit &compUnit)
+{
+ bool in_cu_list = m_cu_spec_list.FindFileIndex(0, compUnit, false) != UINT32_MAX;
+ if (in_cu_list)
+ {
+ ModuleSP module_sp(compUnit.GetModule());
+ if (module_sp)
+ {
+ bool module_passes = SearchFilterByModuleList::ModulePasses(module_sp);
+ return module_passes;
+ }
+ else
+ return true;
+ }
+ else
+ return false;
+}
+
+void
+SearchFilterByModuleListAndCU::Search (Searcher &searcher)
+{
+ if (!m_target_sp)
+ return;
+
+ if (searcher.GetDepth() == Searcher::eDepthTarget)
+ {
+ SymbolContext empty_sc;
+ empty_sc.target_sp = m_target_sp;
+ searcher.SearchCallback (*this, empty_sc, NULL, false);
+ }
+
+ // If the module file spec is a full path, then we can just find the one
+ // filespec that passes. Otherwise, we need to go through all modules and
+ // find the ones that match the file name.
+
+ ModuleList matching_modules;
+ const ModuleList &target_images = m_target_sp->GetImages();
+ Mutex::Locker modules_locker(target_images.GetMutex());
+
+ const size_t num_modules = target_images.GetSize ();
+ bool no_modules_in_filter = m_module_spec_list.GetSize() == 0;
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ lldb::ModuleSP module_sp = target_images.GetModuleAtIndexUnlocked(i);
+ if (no_modules_in_filter || m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) != UINT32_MAX)
+ {
+ SymbolContext matchingContext(m_target_sp, module_sp);
+ Searcher::CallbackReturn shouldContinue;
+
+ if (searcher.GetDepth() == Searcher::eDepthModule)
+ {
+ shouldContinue = DoModuleIteration(matchingContext, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return;
+ }
+ else
+ {
+ const size_t num_cu = module_sp->GetNumCompileUnits();
+ for (size_t cu_idx = 0; cu_idx < num_cu; cu_idx++)
+ {
+ CompUnitSP cu_sp = module_sp->GetCompileUnitAtIndex(cu_idx);
+ matchingContext.comp_unit = cu_sp.get();
+ if (matchingContext.comp_unit)
+ {
+ if (m_cu_spec_list.FindFileIndex(0, *matchingContext.comp_unit, false) != UINT32_MAX)
+ {
+ shouldContinue = DoCUIteration(module_sp, matchingContext, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+SearchFilterByModuleListAndCU::GetDescription (Stream *s)
+{
+ size_t num_modules = m_module_spec_list.GetSize();
+ if (num_modules == 1)
+ {
+ s->Printf (", module = ");
+ if (s->GetVerbose())
+ {
+ char buffer[2048];
+ m_module_spec_list.GetFileSpecAtIndex(0).GetPath(buffer, 2047);
+ s->PutCString(buffer);
+ }
+ else
+ {
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString("<unknown>"));
+ }
+ }
+ else if (num_modules > 0)
+ {
+ s->Printf (", modules(%zd) = ", num_modules);
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ if (s->GetVerbose())
+ {
+ char buffer[2048];
+ m_module_spec_list.GetFileSpecAtIndex(i).GetPath(buffer, 2047);
+ s->PutCString(buffer);
+ }
+ else
+ {
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString("<unknown>"));
+ }
+ if (i != num_modules - 1)
+ s->PutCString (", ");
+ }
+ }
+}
+
+uint32_t
+SearchFilterByModuleListAndCU::GetFilterRequiredItems()
+{
+ return eSymbolContextModule | eSymbolContextCompUnit;
+}
+
+void
+SearchFilterByModuleListAndCU::Dump (Stream *s) const
+{
+
+}
+
diff --git a/source/Core/Section.cpp b/source/Core/Section.cpp
new file mode 100644
index 0000000..e2a084c
--- /dev/null
+++ b/source/Core/Section.cpp
@@ -0,0 +1,562 @@
+//===-- Section.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/Section.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Section::Section (const ModuleSP &module_sp,
+ ObjectFile *obj_file,
+ user_id_t sect_id,
+ const ConstString &name,
+ SectionType sect_type,
+ addr_t file_addr,
+ addr_t byte_size,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ uint32_t flags) :
+ ModuleChild (module_sp),
+ UserID (sect_id),
+ Flags (flags),
+ m_obj_file (obj_file),
+ m_type (sect_type),
+ m_parent_wp (),
+ m_name (name),
+ m_file_addr (file_addr),
+ m_byte_size (byte_size),
+ m_file_offset (file_offset),
+ m_file_size (file_size),
+ m_children (),
+ m_fake (false),
+ m_encrypted (false),
+ m_thread_specific (false)
+{
+// printf ("Section::Section(%p): module=%p, sect_id = 0x%16.16" PRIx64 ", addr=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), file [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), flags = 0x%8.8x, name = %s\n",
+// this, module_sp.get(), sect_id, file_addr, file_addr + byte_size, file_offset, file_offset + file_size, flags, name.GetCString());
+}
+
+Section::Section (const lldb::SectionSP &parent_section_sp,
+ const ModuleSP &module_sp,
+ ObjectFile *obj_file,
+ user_id_t sect_id,
+ const ConstString &name,
+ SectionType sect_type,
+ addr_t file_addr,
+ addr_t byte_size,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ uint32_t flags) :
+ ModuleChild (module_sp),
+ UserID (sect_id),
+ Flags (flags),
+ m_obj_file (obj_file),
+ m_type (sect_type),
+ m_parent_wp (),
+ m_name (name),
+ m_file_addr (file_addr),
+ m_byte_size (byte_size),
+ m_file_offset (file_offset),
+ m_file_size (file_size),
+ m_children (),
+ m_fake (false),
+ m_encrypted (false),
+ m_thread_specific (false)
+{
+// printf ("Section::Section(%p): module=%p, sect_id = 0x%16.16" PRIx64 ", addr=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), file [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), flags = 0x%8.8x, name = %s.%s\n",
+// this, module_sp.get(), sect_id, file_addr, file_addr + byte_size, file_offset, file_offset + file_size, flags, parent_section_sp->GetName().GetCString(), name.GetCString());
+ if (parent_section_sp)
+ m_parent_wp = parent_section_sp;
+}
+
+Section::~Section()
+{
+// printf ("Section::~Section(%p)\n", this);
+}
+
+addr_t
+Section::GetFileAddress () const
+{
+ SectionSP parent_sp (GetParent ());
+ if (parent_sp)
+ {
+ // This section has a parent which means m_file_addr is an offset into
+ // the parent section, so the file address for this section is the file
+ // address of the parent plus the offset
+ return parent_sp->GetFileAddress() + m_file_addr;
+ }
+ // This section has no parent, so m_file_addr is the file base address
+ return m_file_addr;
+}
+
+bool
+Section::SetFileAddress (lldb::addr_t file_addr)
+{
+ SectionSP parent_sp (GetParent ());
+ if (parent_sp)
+ {
+ if (m_file_addr >= file_addr)
+ return parent_sp->SetFileAddress (m_file_addr - file_addr);
+ return false;
+ }
+ else
+ {
+ // This section has no parent, so m_file_addr is the file base address
+ m_file_addr = file_addr;
+ return true;
+ }
+}
+
+lldb::addr_t
+Section::GetOffset () const
+{
+ // This section has a parent which means m_file_addr is an offset.
+ SectionSP parent_sp (GetParent ());
+ if (parent_sp)
+ return m_file_addr;
+
+ // This section has no parent, so there is no offset to be had
+ return 0;
+}
+
+addr_t
+Section::GetLoadBaseAddress (Target *target) const
+{
+ addr_t load_base_addr = LLDB_INVALID_ADDRESS;
+ SectionSP parent_sp (GetParent ());
+ if (parent_sp)
+ {
+ load_base_addr = parent_sp->GetLoadBaseAddress (target);
+ if (load_base_addr != LLDB_INVALID_ADDRESS)
+ load_base_addr += GetOffset();
+ }
+ else
+ {
+ load_base_addr = target->GetSectionLoadList().GetSectionLoadAddress (const_cast<Section *>(this)->shared_from_this());
+ }
+ return load_base_addr;
+}
+
+bool
+Section::ResolveContainedAddress (addr_t offset, Address &so_addr) const
+{
+ const size_t num_children = m_children.GetSize();
+ if (num_children > 0)
+ {
+ for (size_t i=0; i<num_children; i++)
+ {
+ Section* child_section = m_children.GetSectionAtIndex (i).get();
+
+ addr_t child_offset = child_section->GetOffset();
+ if (child_offset <= offset && offset - child_offset < child_section->GetByteSize())
+ return child_section->ResolveContainedAddress (offset - child_offset, so_addr);
+ }
+ }
+ so_addr.SetOffset(offset);
+ so_addr.SetSection(const_cast<Section *>(this)->shared_from_this());
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ // For debug builds, ensure that there are no orphaned (i.e., moduleless) sections.
+ assert(GetModule().get());
+#endif
+ return true;
+}
+
+bool
+Section::ContainsFileAddress (addr_t vm_addr) const
+{
+ const addr_t file_addr = GetFileAddress();
+ if (file_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (file_addr <= vm_addr)
+ {
+ const addr_t offset = vm_addr - file_addr;
+ return offset < GetByteSize();
+ }
+ }
+ return false;
+}
+
+int
+Section::Compare (const Section& a, const Section& b)
+{
+ if (&a == &b)
+ return 0;
+
+ const ModuleSP a_module_sp = a.GetModule();
+ const ModuleSP b_module_sp = b.GetModule();
+ if (a_module_sp == b_module_sp)
+ {
+ user_id_t a_sect_uid = a.GetID();
+ user_id_t b_sect_uid = b.GetID();
+ if (a_sect_uid < b_sect_uid)
+ return -1;
+ if (a_sect_uid > b_sect_uid)
+ return 1;
+ return 0;
+ }
+ else
+ {
+ // The modules are different, just compare the module pointers
+ if (a_module_sp.get() < b_module_sp.get())
+ return -1;
+ else
+ return 1; // We already know the modules aren't equal
+ }
+}
+
+
+void
+Section::Dump (Stream *s, Target *target, uint32_t depth) const
+{
+// s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ s->Printf("0x%8.8" PRIx64 " %-16s ", GetID(), GetSectionTypeAsCString (m_type));
+ bool resolved = true;
+ addr_t addr = LLDB_INVALID_ADDRESS;
+
+ if (GetByteSize() == 0)
+ s->Printf("%39s", "");
+ else
+ {
+ if (target)
+ addr = GetLoadBaseAddress (target);
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ if (target)
+ resolved = false;
+ addr = GetFileAddress();
+ }
+
+ VMRange range(addr, addr + m_byte_size);
+ range.Dump (s, 0);
+ }
+
+ s->Printf("%c 0x%8.8" PRIx64 " 0x%8.8" PRIx64 " 0x%8.8x ", resolved ? ' ' : '*', m_file_offset, m_file_size, Get());
+
+ DumpName (s);
+
+ s->EOL();
+
+ if (depth > 0)
+ m_children.Dump(s, target, false, depth - 1);
+}
+
+void
+Section::DumpName (Stream *s) const
+{
+ SectionSP parent_sp (GetParent ());
+ if (parent_sp)
+ {
+ parent_sp->DumpName (s);
+ s->PutChar('.');
+ }
+ else
+ {
+ // The top most section prints the module basename
+ const char * name = NULL;
+ ModuleSP module_sp (GetModule());
+ const FileSpec &file_spec = m_obj_file->GetFileSpec();
+
+ if (m_obj_file)
+ name = file_spec.GetFilename().AsCString();
+ if ((!name || !name[0]) && module_sp)
+ name = module_sp->GetFileSpec().GetFilename().AsCString();
+ if (name && name[0])
+ s->Printf("%s.", name);
+ }
+ m_name.Dump(s);
+}
+
+bool
+Section::IsDescendant (const Section *section)
+{
+ if (this == section)
+ return true;
+ SectionSP parent_sp (GetParent ());
+ if (parent_sp)
+ return parent_sp->IsDescendant (section);
+ return false;
+}
+
+bool
+Section::Slide (addr_t slide_amount, bool slide_children)
+{
+ if (m_file_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (slide_amount == 0)
+ return true;
+
+ m_file_addr += slide_amount;
+
+ if (slide_children)
+ m_children.Slide (slide_amount, slide_children);
+
+ return true;
+ }
+ return false;
+}
+
+#pragma mark SectionList
+
+SectionList::SectionList () :
+ m_sections()
+{
+}
+
+
+SectionList::~SectionList ()
+{
+}
+
+SectionList &
+SectionList::operator = (const SectionList& rhs)
+{
+ if (this != &rhs)
+ m_sections = rhs.m_sections;
+ return *this;
+}
+
+size_t
+SectionList::AddSection (const lldb::SectionSP& section_sp)
+{
+ assert (section_sp.get());
+ size_t section_index = m_sections.size();
+ m_sections.push_back(section_sp);
+ return section_index;
+}
+
+// Warning, this can be slow as it's removing items from a std::vector.
+bool
+SectionList::DeleteSection (size_t idx)
+{
+ if (idx < m_sections.size())
+ {
+ m_sections.erase (m_sections.begin() + idx);
+ return true;
+ }
+ return false;
+}
+
+size_t
+SectionList::FindSectionIndex (const Section* sect)
+{
+ iterator sect_iter;
+ iterator begin = m_sections.begin();
+ iterator end = m_sections.end();
+ for (sect_iter = begin; sect_iter != end; ++sect_iter)
+ {
+ if (sect_iter->get() == sect)
+ {
+ // The secton was already in this section list
+ return std::distance (begin, sect_iter);
+ }
+ }
+ return UINT32_MAX;
+}
+
+size_t
+SectionList::AddUniqueSection (const lldb::SectionSP& sect_sp)
+{
+ size_t sect_idx = FindSectionIndex (sect_sp.get());
+ if (sect_idx == UINT32_MAX)
+ {
+ sect_idx = AddSection (sect_sp);
+ }
+ return sect_idx;
+}
+
+bool
+SectionList::ReplaceSection (user_id_t sect_id, const lldb::SectionSP& sect_sp, uint32_t depth)
+{
+ iterator sect_iter, end = m_sections.end();
+ for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter)
+ {
+ if ((*sect_iter)->GetID() == sect_id)
+ {
+ *sect_iter = sect_sp;
+ return true;
+ }
+ else if (depth > 0)
+ {
+ if ((*sect_iter)->GetChildren().ReplaceSection(sect_id, sect_sp, depth - 1))
+ return true;
+ }
+ }
+ return false;
+}
+
+size_t
+SectionList::GetNumSections (uint32_t depth) const
+{
+ size_t count = m_sections.size();
+ if (depth > 0)
+ {
+ const_iterator sect_iter, end = m_sections.end();
+ for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter)
+ {
+ count += (*sect_iter)->GetChildren().GetNumSections(depth - 1);
+ }
+ }
+ return count;
+}
+
+SectionSP
+SectionList::GetSectionAtIndex (size_t idx) const
+{
+ SectionSP sect_sp;
+ if (idx < m_sections.size())
+ sect_sp = m_sections[idx];
+ return sect_sp;
+}
+
+SectionSP
+SectionList::FindSectionByName (const ConstString &section_dstr) const
+{
+ SectionSP sect_sp;
+ // Check if we have a valid section string
+ if (section_dstr && !m_sections.empty())
+ {
+ const_iterator sect_iter;
+ const_iterator end = m_sections.end();
+ for (sect_iter = m_sections.begin(); sect_iter != end && sect_sp.get() == NULL; ++sect_iter)
+ {
+ Section *child_section = sect_iter->get();
+ assert (child_section);
+ if (child_section->GetName() == section_dstr)
+ {
+ sect_sp = *sect_iter;
+ }
+ else
+ {
+ sect_sp = child_section->GetChildren().FindSectionByName(section_dstr);
+ }
+ }
+ }
+ return sect_sp;
+}
+
+SectionSP
+SectionList::FindSectionByID (user_id_t sect_id) const
+{
+ SectionSP sect_sp;
+ if (sect_id)
+ {
+ const_iterator sect_iter;
+ const_iterator end = m_sections.end();
+ for (sect_iter = m_sections.begin(); sect_iter != end && sect_sp.get() == NULL; ++sect_iter)
+ {
+ if ((*sect_iter)->GetID() == sect_id)
+ {
+ sect_sp = *sect_iter;
+ break;
+ }
+ else
+ {
+ sect_sp = (*sect_iter)->GetChildren().FindSectionByID (sect_id);
+ }
+ }
+ }
+ return sect_sp;
+}
+
+
+SectionSP
+SectionList::FindSectionByType (SectionType sect_type, bool check_children, size_t start_idx) const
+{
+ SectionSP sect_sp;
+ size_t num_sections = m_sections.size();
+ for (size_t idx = start_idx; idx < num_sections; ++idx)
+ {
+ if (m_sections[idx]->GetType() == sect_type)
+ {
+ sect_sp = m_sections[idx];
+ break;
+ }
+ else if (check_children)
+ {
+ sect_sp = m_sections[idx]->GetChildren().FindSectionByType (sect_type, check_children, 0);
+ if (sect_sp)
+ break;
+ }
+ }
+ return sect_sp;
+}
+
+SectionSP
+SectionList::FindSectionContainingFileAddress (addr_t vm_addr, uint32_t depth) const
+{
+ SectionSP sect_sp;
+ const_iterator sect_iter;
+ const_iterator end = m_sections.end();
+ for (sect_iter = m_sections.begin(); sect_iter != end && sect_sp.get() == NULL; ++sect_iter)
+ {
+ Section *sect = sect_iter->get();
+ if (sect->ContainsFileAddress (vm_addr))
+ {
+ // The file address is in this section. We need to make sure one of our child
+ // sections doesn't contain this address as well as obeying the depth limit
+ // that was passed in.
+ if (depth > 0)
+ sect_sp = sect->GetChildren().FindSectionContainingFileAddress(vm_addr, depth - 1);
+
+ if (sect_sp.get() == NULL && !sect->IsFake())
+ sect_sp = *sect_iter;
+ }
+ }
+ return sect_sp;
+}
+
+bool
+SectionList::ContainsSection(user_id_t sect_id) const
+{
+ return FindSectionByID (sect_id).get() != NULL;
+}
+
+void
+SectionList::Dump (Stream *s, Target *target, bool show_header, uint32_t depth) const
+{
+ bool target_has_loaded_sections = target && !target->GetSectionLoadList().IsEmpty();
+ if (show_header && !m_sections.empty())
+ {
+ s->Indent();
+ s->Printf( "SectID Type %s Address File Off. File Size Flags Section Name\n", target_has_loaded_sections ? "Load" : "File");
+ s->Indent();
+ s->PutCString("---------- ---------------- --------------------------------------- ---------- ---------- ---------- ----------------------------\n");
+ }
+
+
+ const_iterator sect_iter;
+ const_iterator end = m_sections.end();
+ for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter)
+ {
+ (*sect_iter)->Dump(s, target_has_loaded_sections ? target : NULL, depth);
+ }
+
+ if (show_header && !m_sections.empty())
+ s->IndentLess();
+
+}
+
+size_t
+SectionList::Slide (addr_t slide_amount, bool slide_children)
+{
+ size_t count = 0;
+ const_iterator pos, end = m_sections.end();
+ for (pos = m_sections.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->Slide(slide_amount, slide_children))
+ ++count;
+ }
+ return count;
+}
diff --git a/source/Core/SourceManager.cpp b/source/Core/SourceManager.cpp
new file mode 100644
index 0000000..9f28934
--- /dev/null
+++ b/source/Core/SourceManager.cpp
@@ -0,0 +1,651 @@
+//===-- SourceManager.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/lldb-python.h"
+
+#include "lldb/Core/SourceManager.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static inline bool is_newline_char(char ch)
+{
+ return ch == '\n' || ch == '\r';
+}
+
+
+//----------------------------------------------------------------------
+// SourceManager constructor
+//----------------------------------------------------------------------
+SourceManager::SourceManager(const TargetSP &target_sp) :
+ m_last_file_sp (),
+ m_last_line (0),
+ m_last_count (0),
+ m_default_set(false),
+ m_target_wp (target_sp),
+ m_debugger_wp(target_sp->GetDebugger().shared_from_this())
+{
+}
+
+SourceManager::SourceManager(const DebuggerSP &debugger_sp) :
+ m_last_file_sp (),
+ m_last_line (0),
+ m_last_count (0),
+ m_default_set(false),
+ m_target_wp (),
+ m_debugger_wp (debugger_sp)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SourceManager::~SourceManager()
+{
+}
+
+SourceManager::FileSP
+SourceManager::GetFile (const FileSpec &file_spec)
+{
+ bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec);
+
+ DebuggerSP debugger_sp (m_debugger_wp.lock());
+ FileSP file_sp;
+ if (same_as_previous)
+ file_sp = m_last_file_sp;
+ else if (debugger_sp)
+ file_sp = debugger_sp->GetSourceFileCache().FindSourceFile (file_spec);
+
+ TargetSP target_sp (m_target_wp.lock());
+
+ // It the target source path map has been updated, get this file again so we
+ // can successfully remap the source file
+ if (target_sp && file_sp && file_sp->GetSourceMapModificationID() != target_sp->GetSourcePathMap().GetModificationID())
+ file_sp.reset();
+
+ // If file_sp is no good or it points to a non-existent file, reset it.
+ if (!file_sp || !file_sp->GetFileSpec().Exists())
+ {
+ file_sp.reset (new File (file_spec, target_sp.get()));
+
+ if (debugger_sp)
+ debugger_sp->GetSourceFileCache().AddSourceFile(file_sp);
+ }
+ return file_sp;
+}
+
+size_t
+SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile (uint32_t start_line,
+ uint32_t count,
+ uint32_t curr_line,
+ const char* current_line_cstr,
+ Stream *s,
+ const SymbolContextList *bp_locs)
+{
+ if (count == 0)
+ return 0;
+ size_t return_value = 0;
+ if (start_line == 0)
+ {
+ if (m_last_line != 0 && m_last_line != UINT32_MAX)
+ start_line = m_last_line + m_last_count;
+ else
+ start_line = 1;
+ }
+
+ if (!m_default_set)
+ {
+ FileSpec tmp_spec;
+ uint32_t tmp_line;
+ GetDefaultFileAndLine(tmp_spec, tmp_line);
+ }
+
+ m_last_line = start_line;
+ m_last_count = count;
+
+ if (m_last_file_sp.get())
+ {
+ const uint32_t end_line = start_line + count - 1;
+ for (uint32_t line = start_line; line <= end_line; ++line)
+ {
+ if (!m_last_file_sp->LineIsValid (line))
+ {
+ m_last_line = UINT32_MAX;
+ break;
+ }
+
+ char prefix[32] = "";
+ if (bp_locs)
+ {
+ uint32_t bp_count = bp_locs->NumLineEntriesWithLine (line);
+
+ if (bp_count > 0)
+ ::snprintf (prefix, sizeof (prefix), "[%u] ", bp_count);
+ else
+ ::snprintf (prefix, sizeof (prefix), " ");
+ }
+
+ return_value += s->Printf("%s%2.2s %-4u\t",
+ prefix,
+ line == curr_line ? current_line_cstr : "",
+ line);
+ size_t this_line_size = m_last_file_sp->DisplaySourceLines (line, 0, 0, s);
+ if (this_line_size == 0)
+ {
+ m_last_line = UINT32_MAX;
+ break;
+ }
+ else
+ return_value += this_line_size;
+ }
+ }
+ return return_value;
+}
+
+size_t
+SourceManager::DisplaySourceLinesWithLineNumbers
+(
+ const FileSpec &file_spec,
+ uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ const char* current_line_cstr,
+ Stream *s,
+ const SymbolContextList *bp_locs
+)
+{
+ FileSP file_sp (GetFile (file_spec));
+
+ uint32_t start_line;
+ uint32_t count = context_before + context_after + 1;
+ if (line > context_before)
+ start_line = line - context_before;
+ else
+ start_line = 1;
+
+ if (m_last_file_sp.get() != file_sp.get())
+ {
+ if (line == 0)
+ m_last_line = 0;
+ m_last_file_sp = file_sp;
+ }
+ return DisplaySourceLinesWithLineNumbersUsingLastFile (start_line, count, line, current_line_cstr, s, bp_locs);
+}
+
+size_t
+SourceManager::DisplayMoreWithLineNumbers (Stream *s,
+ uint32_t count,
+ bool reverse,
+ const SymbolContextList *bp_locs)
+{
+ // If we get called before anybody has set a default file and line, then try to figure it out here.
+ const bool have_default_file_line = m_last_file_sp && m_last_line > 0;
+ if (!m_default_set)
+ {
+ FileSpec tmp_spec;
+ uint32_t tmp_line;
+ GetDefaultFileAndLine(tmp_spec, tmp_line);
+ }
+
+ if (m_last_file_sp)
+ {
+ if (m_last_line == UINT32_MAX)
+ return 0;
+
+ if (reverse && m_last_line == 1)
+ return 0;
+
+ if (count > 0)
+ m_last_count = count;
+ else if (m_last_count == 0)
+ m_last_count = 10;
+
+ if (m_last_line > 0)
+ {
+ if (reverse)
+ {
+ // If this is the first time we've done a reverse, then back up one more time so we end
+ // up showing the chunk before the last one we've shown:
+ if (m_last_line > m_last_count)
+ m_last_line -= m_last_count;
+ else
+ m_last_line = 1;
+ }
+ else if (have_default_file_line)
+ m_last_line += m_last_count;
+ }
+ else
+ m_last_line = 1;
+
+ return DisplaySourceLinesWithLineNumbersUsingLastFile (m_last_line, m_last_count, UINT32_MAX, "", s, bp_locs);
+ }
+ return 0;
+}
+
+bool
+SourceManager::SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line)
+{
+ FileSP old_file_sp = m_last_file_sp;
+ m_last_file_sp = GetFile (file_spec);
+
+ m_default_set = true;
+ if (m_last_file_sp)
+ {
+ m_last_line = line;
+ return true;
+ }
+ else
+ {
+ m_last_file_sp = old_file_sp;
+ return false;
+ }
+}
+
+bool
+SourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line)
+{
+ if (m_last_file_sp)
+ {
+ file_spec = m_last_file_sp->GetFileSpec();
+ line = m_last_line;
+ return true;
+ }
+ else if (!m_default_set)
+ {
+ TargetSP target_sp (m_target_wp.lock());
+
+ if (target_sp)
+ {
+ // If nobody has set the default file and line then try here. If there's no executable, then we
+ // will try again later when there is one. Otherwise, if we can't find it we won't look again,
+ // somebody will have to set it (for instance when we stop somewhere...)
+ Module *executable_ptr = target_sp->GetExecutableModulePointer();
+ if (executable_ptr)
+ {
+ SymbolContextList sc_list;
+ ConstString main_name("main");
+ bool symbols_okay = false; // Force it to be a debug symbol.
+ bool inlines_okay = true;
+ bool append = false;
+ size_t num_matches = executable_ptr->FindFunctions (main_name,
+ NULL,
+ lldb::eFunctionNameTypeBase,
+ inlines_okay,
+ symbols_okay,
+ append,
+ sc_list);
+ for (size_t idx = 0; idx < num_matches; idx++)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(idx, sc);
+ if (sc.function)
+ {
+ lldb_private::LineEntry line_entry;
+ if (sc.function->GetAddressRange().GetBaseAddress().CalculateSymbolContextLineEntry (line_entry))
+ {
+ SetDefaultFileAndLine (line_entry.file,
+ line_entry.line);
+ file_spec = m_last_file_sp->GetFileSpec();
+ line = m_last_line;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void
+SourceManager::FindLinesMatchingRegex (FileSpec &file_spec,
+ RegularExpression& regex,
+ uint32_t start_line,
+ uint32_t end_line,
+ std::vector<uint32_t> &match_lines)
+{
+ match_lines.clear();
+ FileSP file_sp = GetFile (file_spec);
+ if (!file_sp)
+ return;
+ return file_sp->FindLinesMatchingRegex (regex, start_line, end_line, match_lines);
+}
+
+SourceManager::File::File(const FileSpec &file_spec, Target *target) :
+ m_file_spec_orig (file_spec),
+ m_file_spec(file_spec),
+ m_mod_time (file_spec.GetModificationTime()),
+ m_source_map_mod_id (0),
+ m_data_sp(),
+ m_offsets()
+{
+ if (!m_mod_time.IsValid())
+ {
+ if (target)
+ {
+ m_source_map_mod_id = target->GetSourcePathMap().GetModificationID();
+
+ if (!file_spec.GetDirectory() && file_spec.GetFilename())
+ {
+ // If this is just a file name, lets see if we can find it in the target:
+ bool check_inlines = false;
+ SymbolContextList sc_list;
+ size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (file_spec.GetFilename().AsCString(),
+ 0,
+ check_inlines,
+ lldb::eSymbolContextModule | lldb::eSymbolContextCompUnit,
+ sc_list);
+ bool got_multiple = false;
+ if (num_matches != 0)
+ {
+ if (num_matches > 1)
+ {
+ SymbolContext sc;
+ FileSpec *test_cu_spec = NULL;
+
+ for (unsigned i = 0; i < num_matches; i++)
+ {
+ sc_list.GetContextAtIndex(i, sc);
+ if (sc.comp_unit)
+ {
+ if (test_cu_spec)
+ {
+ if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
+ got_multiple = true;
+ break;
+ }
+ else
+ test_cu_spec = sc.comp_unit;
+ }
+ }
+ }
+ if (!got_multiple)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (0, sc);
+ m_file_spec = sc.comp_unit;
+ m_mod_time = m_file_spec.GetModificationTime();
+ }
+ }
+ }
+ // Try remapping if m_file_spec does not correspond to an existing file.
+ if (!m_file_spec.Exists())
+ {
+ FileSpec new_file_spec;
+ // Check target specific source remappings first, then fall back to
+ // modules objects can have individual path remappings that were detected
+ // when the debug info for a module was found.
+ // then
+ if (target->GetSourcePathMap().FindFile (m_file_spec, new_file_spec) ||
+ target->GetImages().FindSourceFile (m_file_spec, new_file_spec))
+ {
+ m_file_spec = new_file_spec;
+ m_mod_time = m_file_spec.GetModificationTime();
+ }
+ }
+ }
+ }
+
+ if (m_mod_time.IsValid())
+ m_data_sp = m_file_spec.ReadFileContents ();
+}
+
+SourceManager::File::~File()
+{
+}
+
+uint32_t
+SourceManager::File::GetLineOffset (uint32_t line)
+{
+ if (line == 0)
+ return UINT32_MAX;
+
+ if (line == 1)
+ return 0;
+
+ if (CalculateLineOffsets (line))
+ {
+ if (line < m_offsets.size())
+ return m_offsets[line - 1]; // yes we want "line - 1" in the index
+ }
+ return UINT32_MAX;
+}
+
+bool
+SourceManager::File::LineIsValid (uint32_t line)
+{
+ if (line == 0)
+ return false;
+
+ if (CalculateLineOffsets (line))
+ return line < m_offsets.size();
+ return false;
+}
+
+size_t
+SourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s)
+{
+ // TODO: use host API to sign up for file modifications to anything in our
+ // source cache and only update when we determine a file has been updated.
+ // For now we check each time we want to display info for the file.
+ TimeValue curr_mod_time (m_file_spec.GetModificationTime());
+
+ if (curr_mod_time.IsValid() && m_mod_time != curr_mod_time)
+ {
+ m_mod_time = curr_mod_time;
+ m_data_sp = m_file_spec.ReadFileContents ();
+ m_offsets.clear();
+ }
+
+ // Sanity check m_data_sp before proceeding.
+ if (!m_data_sp)
+ return 0;
+
+ const uint32_t start_line = line <= context_before ? 1 : line - context_before;
+ const uint32_t start_line_offset = GetLineOffset (start_line);
+ if (start_line_offset != UINT32_MAX)
+ {
+ const uint32_t end_line = line + context_after;
+ uint32_t end_line_offset = GetLineOffset (end_line + 1);
+ if (end_line_offset == UINT32_MAX)
+ end_line_offset = m_data_sp->GetByteSize();
+
+ assert (start_line_offset <= end_line_offset);
+ size_t bytes_written = 0;
+ if (start_line_offset < end_line_offset)
+ {
+ size_t count = end_line_offset - start_line_offset;
+ const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
+ bytes_written = s->Write(cstr, count);
+ if (!is_newline_char(cstr[count-1]))
+ bytes_written += s->EOL();
+ }
+ return bytes_written;
+ }
+ return 0;
+}
+
+void
+SourceManager::File::FindLinesMatchingRegex (RegularExpression& regex, uint32_t start_line, uint32_t end_line, std::vector<uint32_t> &match_lines)
+{
+ TimeValue curr_mod_time (m_file_spec.GetModificationTime());
+ if (m_mod_time != curr_mod_time)
+ {
+ m_mod_time = curr_mod_time;
+ m_data_sp = m_file_spec.ReadFileContents ();
+ m_offsets.clear();
+ }
+
+ match_lines.clear();
+
+ if (!LineIsValid(start_line) || (end_line != UINT32_MAX && !LineIsValid(end_line)))
+ return;
+ if (start_line > end_line)
+ return;
+
+ for (uint32_t line_no = start_line; line_no < end_line; line_no++)
+ {
+ std::string buffer;
+ if (!GetLine (line_no, buffer))
+ break;
+ if (regex.Execute(buffer.c_str()))
+ {
+ match_lines.push_back(line_no);
+ }
+ }
+}
+
+bool
+SourceManager::File::FileSpecMatches (const FileSpec &file_spec)
+{
+ return FileSpec::Equal (m_file_spec, file_spec, false);
+}
+
+bool
+lldb_private::operator== (const SourceManager::File &lhs, const SourceManager::File &rhs)
+{
+ if (lhs.m_file_spec == rhs.m_file_spec)
+ {
+ if (lhs.m_mod_time.IsValid())
+ {
+ if (rhs.m_mod_time.IsValid())
+ return lhs.m_mod_time == rhs.m_mod_time;
+ else
+ return false;
+ }
+ else if (rhs.m_mod_time.IsValid())
+ return false;
+ else
+ return true;
+ }
+ else
+ return false;
+}
+
+bool
+SourceManager::File::CalculateLineOffsets (uint32_t line)
+{
+ line = UINT32_MAX; // TODO: take this line out when we support partial indexing
+ if (line == UINT32_MAX)
+ {
+ // Already done?
+ if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX)
+ return true;
+
+ if (m_offsets.empty())
+ {
+ if (m_data_sp.get() == NULL)
+ return false;
+
+ const char *start = (char *)m_data_sp->GetBytes();
+ if (start)
+ {
+ const char *end = start + m_data_sp->GetByteSize();
+
+ // Calculate all line offsets from scratch
+
+ // Push a 1 at index zero to indicate the file has been completely indexed.
+ m_offsets.push_back(UINT32_MAX);
+ register const char *s;
+ for (s = start; s < end; ++s)
+ {
+ register char curr_ch = *s;
+ if (is_newline_char (curr_ch))
+ {
+ if (s + 1 < end)
+ {
+ register char next_ch = s[1];
+ if (is_newline_char (next_ch))
+ {
+ if (curr_ch != next_ch)
+ ++s;
+ }
+ }
+ m_offsets.push_back(s + 1 - start);
+ }
+ }
+ if (!m_offsets.empty())
+ {
+ if (m_offsets.back() < end - start)
+ m_offsets.push_back(end - start);
+ }
+ return true;
+ }
+ }
+ else
+ {
+ // Some lines have been populated, start where we last left off
+ assert("Not implemented yet" == NULL);
+ }
+
+ }
+ else
+ {
+ // Calculate all line offsets up to "line"
+ assert("Not implemented yet" == NULL);
+ }
+ return false;
+}
+
+bool
+SourceManager::File::GetLine (uint32_t line_no, std::string &buffer)
+{
+ if (!LineIsValid(line_no))
+ return false;
+
+ size_t start_offset = GetLineOffset (line_no);
+ size_t end_offset = GetLineOffset (line_no + 1);
+ if (end_offset == UINT32_MAX)
+ {
+ end_offset = m_data_sp->GetByteSize();
+ }
+ buffer.assign((char *) m_data_sp->GetBytes() + start_offset, end_offset - start_offset);
+
+ return true;
+}
+
+void
+SourceManager::SourceFileCache::AddSourceFile (const FileSP &file_sp)
+{
+ FileSpec file_spec;
+ FileCache::iterator pos = m_file_cache.find(file_spec);
+ if (pos == m_file_cache.end())
+ m_file_cache[file_spec] = file_sp;
+ else
+ {
+ if (file_sp != pos->second)
+ m_file_cache[file_spec] = file_sp;
+ }
+}
+
+SourceManager::FileSP
+SourceManager::SourceFileCache::FindSourceFile (const FileSpec &file_spec) const
+{
+ FileSP file_sp;
+ FileCache::const_iterator pos = m_file_cache.find(file_spec);
+ if (pos != m_file_cache.end())
+ file_sp = pos->second;
+ return file_sp;
+}
+
diff --git a/source/Core/State.cpp b/source/Core/State.cpp
new file mode 100644
index 0000000..7d9ccda
--- /dev/null
+++ b/source/Core/State.cpp
@@ -0,0 +1,115 @@
+//===-- State.cpp -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/State.h"
+#include <stdio.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *
+lldb_private::StateAsCString (StateType state)
+{
+ switch (state)
+ {
+ case eStateInvalid: return "invalid";
+ case eStateUnloaded: return "unloaded";
+ case eStateConnected: return "connected";
+ case eStateAttaching: return "attaching";
+ case eStateLaunching: return "launching";
+ case eStateStopped: return "stopped";
+ case eStateRunning: return "running";
+ case eStateStepping: return "stepping";
+ case eStateCrashed: return "crashed";
+ case eStateDetached: return "detached";
+ case eStateExited: return "exited";
+ case eStateSuspended: return "suspended";
+ }
+ static char unknown_state_string[64];
+ snprintf(unknown_state_string, sizeof (unknown_state_string), "StateType = %i", state);
+ return unknown_state_string;
+}
+
+const char *
+lldb_private::GetPermissionsAsCString (uint32_t permissions)
+{
+ switch (permissions)
+ {
+ case 0: return "---";
+ case ePermissionsWritable: return "-w-";
+ case ePermissionsReadable: return "r--";
+ case ePermissionsExecutable: return "--x";
+ case ePermissionsReadable |
+ ePermissionsWritable: return "rw-";
+ case ePermissionsReadable |
+ ePermissionsExecutable: return "r-x";
+ case ePermissionsWritable |
+ ePermissionsExecutable: return "-wx";
+ case ePermissionsReadable |
+ ePermissionsWritable |
+ ePermissionsExecutable: return "rwx";
+ default:
+ break;
+ }
+ return "???";
+}
+
+bool
+lldb_private::StateIsRunningState (StateType state)
+{
+ switch (state)
+ {
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ return true;
+
+ case eStateConnected:
+ case eStateDetached:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ break;
+ }
+ return false;
+}
+
+bool
+lldb_private::StateIsStoppedState (StateType state, bool must_exist)
+{
+ switch (state)
+ {
+ case eStateInvalid:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ break;
+
+ case eStateUnloaded:
+ case eStateExited:
+ return !must_exist;
+
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ return true;
+ }
+ return false;
+}
diff --git a/source/Core/Stream.cpp b/source/Core/Stream.cpp
new file mode 100644
index 0000000..49c15d6
--- /dev/null
+++ b/source/Core/Stream.cpp
@@ -0,0 +1,786 @@
+//===-- Stream.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/Stream.h"
+#include "lldb/Host/Endian.h"
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <inttypes.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+Stream::Stream (uint32_t flags, uint32_t addr_size, ByteOrder byte_order) :
+ m_flags (flags),
+ m_addr_size (addr_size),
+ m_byte_order (byte_order),
+ m_indent_level(0)
+{
+}
+
+Stream::Stream () :
+ m_flags (0),
+ m_addr_size (4),
+ m_byte_order (lldb::endian::InlHostByteOrder()),
+ m_indent_level(0)
+{
+}
+
+//------------------------------------------------------------------
+// Destructor
+//------------------------------------------------------------------
+Stream::~Stream ()
+{
+}
+
+ByteOrder
+Stream::SetByteOrder (ByteOrder byte_order)
+{
+ ByteOrder old_byte_order = m_byte_order;
+ m_byte_order = byte_order;
+ return old_byte_order;
+}
+
+//------------------------------------------------------------------
+// Put an offset "uval" out to the stream using the printf format
+// in "format".
+//------------------------------------------------------------------
+void
+Stream::Offset (uint32_t uval, const char *format)
+{
+ Printf (format, uval);
+}
+
+//------------------------------------------------------------------
+// Put an SLEB128 "uval" out to the stream using the printf format
+// in "format".
+//------------------------------------------------------------------
+size_t
+Stream::PutSLEB128 (int64_t sval)
+{
+ size_t bytes_written = 0;
+ if (m_flags.Test(eBinary))
+ {
+ bool more = true;
+ while (more)
+ {
+ uint8_t byte = sval & 0x7fu;
+ sval >>= 7;
+ /* sign bit of byte is 2nd high order bit (0x40) */
+ if ((sval == 0 && !(byte & 0x40)) ||
+ (sval == -1 && (byte & 0x40)) )
+ more = false;
+ else
+ // more bytes to come
+ byte |= 0x80u;
+ bytes_written += Write(&byte, 1);
+ }
+ }
+ else
+ {
+ bytes_written = Printf ("0x%" PRIi64, sval);
+ }
+
+ return bytes_written;
+
+}
+
+//------------------------------------------------------------------
+// Put an ULEB128 "uval" out to the stream using the printf format
+// in "format".
+//------------------------------------------------------------------
+size_t
+Stream::PutULEB128 (uint64_t uval)
+{
+ size_t bytes_written = 0;
+ if (m_flags.Test(eBinary))
+ {
+ do
+ {
+
+ uint8_t byte = uval & 0x7fu;
+ uval >>= 7;
+ if (uval != 0)
+ {
+ // more bytes to come
+ byte |= 0x80u;
+ }
+ bytes_written += Write(&byte, 1);
+ } while (uval != 0);
+ }
+ else
+ {
+ bytes_written = Printf ("0x%" PRIx64, uval);
+ }
+ return bytes_written;
+}
+
+//------------------------------------------------------------------
+// Print a raw NULL terminated C string to the stream.
+//------------------------------------------------------------------
+size_t
+Stream::PutCString (const char *cstr)
+{
+ size_t cstr_len = strlen(cstr);
+ // when in binary mode, emit the NULL terminator
+ if (m_flags.Test(eBinary))
+ ++cstr_len;
+ return Write (cstr, cstr_len);
+}
+
+//------------------------------------------------------------------
+// Print a double quoted NULL terminated C string to the stream
+// using the printf format in "format".
+//------------------------------------------------------------------
+void
+Stream::QuotedCString (const char *cstr, const char *format)
+{
+ Printf (format, cstr);
+}
+
+//------------------------------------------------------------------
+// Put an address "addr" out to the stream with optional prefix
+// and suffix strings.
+//------------------------------------------------------------------
+void
+Stream::Address (uint64_t addr, uint32_t addr_size, const char *prefix, const char *suffix)
+{
+ if (prefix == NULL)
+ prefix = "";
+ if (suffix == NULL)
+ suffix = "";
+// int addr_width = m_addr_size << 1;
+// Printf ("%s0x%0*" PRIx64 "%s", prefix, addr_width, addr, suffix);
+ Printf ("%s0x%0*" PRIx64 "%s", prefix, addr_size * 2, (uint64_t)addr, suffix);
+}
+
+//------------------------------------------------------------------
+// Put an address range out to the stream with optional prefix
+// and suffix strings.
+//------------------------------------------------------------------
+void
+Stream::AddressRange(uint64_t lo_addr, uint64_t hi_addr, uint32_t addr_size, const char *prefix, const char *suffix)
+{
+ if (prefix && prefix[0])
+ PutCString (prefix);
+ Address (lo_addr, addr_size, "[");
+ Address (hi_addr, addr_size, "-", ")");
+ if (suffix && suffix[0])
+ PutCString (suffix);
+}
+
+
+size_t
+Stream::PutChar (char ch)
+{
+ return Write (&ch, 1);
+}
+
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t
+Stream::Printf (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ size_t result = PrintfVarArg(format, args);
+ va_end (args);
+ return result;
+}
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t
+Stream::PrintfVarArg (const char *format, va_list args)
+{
+ char str[1024];
+ va_list args_copy;
+
+ va_copy (args_copy, args);
+
+ size_t bytes_written = 0;
+ // Try and format our string into a fixed buffer first and see if it fits
+ size_t length = ::vsnprintf (str, sizeof(str), format, args);
+ if (length < sizeof(str))
+ {
+ // Include the NULL termination byte for binary output
+ if (m_flags.Test(eBinary))
+ length += 1;
+ // The formatted string fit into our stack based buffer, so we can just
+ // append that to our packet
+ bytes_written = Write (str, length);
+ }
+ else
+ {
+ // Our stack buffer wasn't big enough to contain the entire formatted
+ // string, so lets let vasprintf create the string for us!
+ char *str_ptr = NULL;
+ length = ::vasprintf (&str_ptr, format, args_copy);
+ if (str_ptr)
+ {
+ // Include the NULL termination byte for binary output
+ if (m_flags.Test(eBinary))
+ length += 1;
+ bytes_written = Write (str_ptr, length);
+ ::free (str_ptr);
+ }
+ }
+ va_end (args_copy);
+ return bytes_written;
+}
+
+//------------------------------------------------------------------
+// Print and End of Line character to the stream
+//------------------------------------------------------------------
+size_t
+Stream::EOL()
+{
+ return PutChar ('\n');
+}
+
+//------------------------------------------------------------------
+// Indent the current line using the current indentation level and
+// print an optional string following the idenatation spaces.
+//------------------------------------------------------------------
+size_t
+Stream::Indent(const char *s)
+{
+ return Printf ("%*.*s%s", m_indent_level, m_indent_level, "", s ? s : "");
+}
+
+//------------------------------------------------------------------
+// Stream a character "ch" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (char ch)
+{
+ PutChar (ch);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream the NULL terminated C string out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (const char *s)
+{
+ Printf ("%s", s);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream the pointer value out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (void *p)
+{
+ Printf ("0x%.*tx", (int)sizeof(void*) * 2, (ptrdiff_t)p);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint8_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (uint8_t uval)
+{
+ PutHex8(uval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint16_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (uint16_t uval)
+{
+ PutHex16(uval, m_byte_order);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint32_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (uint32_t uval)
+{
+ PutHex32(uval, m_byte_order);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint64_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (uint64_t uval)
+{
+ PutHex64(uval, m_byte_order);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int8_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (int8_t sval)
+{
+ Printf ("%i", (int)sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int16_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (int16_t sval)
+{
+ Printf ("%i", (int)sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int32_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (int32_t sval)
+{
+ Printf ("%i", (int)sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int64_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (int64_t sval)
+{
+ Printf ("%" PRIi64, sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Get the current indentation level
+//------------------------------------------------------------------
+int
+Stream::GetIndentLevel() const
+{
+ return m_indent_level;
+}
+
+//------------------------------------------------------------------
+// Set the current indentation level
+//------------------------------------------------------------------
+void
+Stream::SetIndentLevel(int indent_level)
+{
+ m_indent_level = indent_level;
+}
+
+//------------------------------------------------------------------
+// Increment the current indentation level
+//------------------------------------------------------------------
+void
+Stream::IndentMore(int amount)
+{
+ m_indent_level += amount;
+}
+
+//------------------------------------------------------------------
+// Decrement the current indentation level
+//------------------------------------------------------------------
+void
+Stream::IndentLess (int amount)
+{
+ if (m_indent_level >= amount)
+ m_indent_level -= amount;
+ else
+ m_indent_level = 0;
+}
+
+//------------------------------------------------------------------
+// Get the address size in bytes
+//------------------------------------------------------------------
+uint32_t
+Stream::GetAddressByteSize() const
+{
+ return m_addr_size;
+}
+
+//------------------------------------------------------------------
+// Set the address size in bytes
+//------------------------------------------------------------------
+void
+Stream::SetAddressByteSize(uint32_t addr_size)
+{
+ m_addr_size = addr_size;
+}
+
+//------------------------------------------------------------------
+// Returns true if the verbose flag bit is set in this stream.
+//------------------------------------------------------------------
+bool
+Stream::GetVerbose() const
+{
+ return m_flags.Test(eVerbose);
+}
+
+//------------------------------------------------------------------
+// Returns true if the debug flag bit is set in this stream.
+//------------------------------------------------------------------
+bool
+Stream::GetDebug() const
+{
+ return m_flags.Test(eDebug);
+}
+
+//------------------------------------------------------------------
+// The flags get accessor
+//------------------------------------------------------------------
+Flags&
+Stream::GetFlags()
+{
+ return m_flags;
+}
+
+//------------------------------------------------------------------
+// The flags const get accessor
+//------------------------------------------------------------------
+const Flags&
+Stream::GetFlags() const
+{
+ return m_flags;
+}
+
+//------------------------------------------------------------------
+// The byte order get accessor
+//------------------------------------------------------------------
+
+lldb::ByteOrder
+Stream::GetByteOrder() const
+{
+ return m_byte_order;
+}
+
+size_t
+Stream::PrintfAsRawHex8 (const char *format, ...)
+{
+ va_list args;
+ va_list args_copy;
+ va_start (args, format);
+ va_copy (args, args_copy); // Copy this so we
+
+ char str[1024];
+ size_t bytes_written = 0;
+ // Try and format our string into a fixed buffer first and see if it fits
+ size_t length = ::vsnprintf (str, sizeof(str), format, args);
+ if (length < sizeof(str))
+ {
+ // The formatted string fit into our stack based buffer, so we can just
+ // append that to our packet
+ for (size_t i=0; i<length; ++i)
+ bytes_written += _PutHex8 (str[i], false);
+ }
+ else
+ {
+ // Our stack buffer wasn't big enough to contain the entire formatted
+ // string, so lets let vasprintf create the string for us!
+ char *str_ptr = NULL;
+ length = ::vasprintf (&str_ptr, format, args_copy);
+ if (str_ptr)
+ {
+ for (size_t i=0; i<length; ++i)
+ bytes_written += _PutHex8 (str_ptr[i], false);
+ ::free (str_ptr);
+ }
+ }
+ va_end (args);
+ va_end (args_copy);
+
+ return bytes_written;
+}
+
+size_t
+Stream::PutNHex8 (size_t n, uint8_t uvalue)
+{
+ size_t bytes_written = 0;
+ for (size_t i=0; i<n; ++i)
+ bytes_written += _PutHex8 (uvalue, m_flags.Test(eAddPrefix));
+ return bytes_written;
+}
+
+size_t
+Stream::_PutHex8 (uint8_t uvalue, bool add_prefix)
+{
+ size_t bytes_written = 0;
+ if (m_flags.Test(eBinary))
+ {
+ bytes_written = Write (&uvalue, 1);
+ }
+ else
+ {
+ if (add_prefix)
+ PutCString("0x");
+
+ static char g_hex_to_ascii_hex_char[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+ char nibble_chars[2];
+ nibble_chars[0] = g_hex_to_ascii_hex_char[(uvalue >> 4) & 0xf];
+ nibble_chars[1] = g_hex_to_ascii_hex_char[(uvalue >> 0) & 0xf];
+ bytes_written = Write (nibble_chars, sizeof(nibble_chars));
+ }
+ return bytes_written;
+}
+
+size_t
+Stream::PutHex8 (uint8_t uvalue)
+{
+ return _PutHex8 (uvalue, m_flags.Test(eAddPrefix));
+}
+
+size_t
+Stream::PutHex16 (uint16_t uvalue, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ bool add_prefix = m_flags.Test(eAddPrefix);
+ size_t bytes_written = 0;
+ if (byte_order == eByteOrderLittle)
+ {
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
+ bytes_written += _PutHex8 ((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ }
+ else
+ {
+ for (size_t byte = sizeof(uvalue)-1; byte < sizeof(uvalue); --byte, add_prefix = false)
+ bytes_written += _PutHex8 ((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ }
+ return bytes_written;
+}
+
+size_t
+Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ bool add_prefix = m_flags.Test(eAddPrefix);
+ size_t bytes_written = 0;
+ if (byte_order == eByteOrderLittle)
+ {
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
+ bytes_written += _PutHex8 ((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ }
+ else
+ {
+ for (size_t byte = sizeof(uvalue)-1; byte < sizeof(uvalue); --byte, add_prefix = false)
+ bytes_written += _PutHex8 ((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ }
+ return bytes_written;
+}
+
+size_t
+Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ bool add_prefix = m_flags.Test(eAddPrefix);
+ size_t bytes_written = 0;
+ if (byte_order == eByteOrderLittle)
+ {
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
+ bytes_written += _PutHex8 ((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ }
+ else
+ {
+ for (size_t byte = sizeof(uvalue)-1; byte < sizeof(uvalue); --byte, add_prefix = false)
+ bytes_written += _PutHex8 ((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ }
+ return bytes_written;
+}
+
+size_t
+Stream::PutMaxHex64
+(
+ uint64_t uvalue,
+ size_t byte_size,
+ lldb::ByteOrder byte_order
+)
+{
+ switch (byte_size)
+ {
+ case 1: return PutHex8 ((uint8_t)uvalue);
+ case 2: return PutHex16 ((uint16_t)uvalue);
+ case 4: return PutHex32 ((uint32_t)uvalue);
+ case 8: return PutHex64 (uvalue);
+ }
+ return 0;
+}
+
+size_t
+Stream::PutPointer (void *ptr)
+{
+ return PutRawBytes (&ptr, sizeof(ptr), lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder());
+}
+
+size_t
+Stream::PutFloat(float f, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes (&f, sizeof(f), lldb::endian::InlHostByteOrder(), byte_order);
+}
+
+size_t
+Stream::PutDouble(double d, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes (&d, sizeof(d), lldb::endian::InlHostByteOrder(), byte_order);
+}
+
+size_t
+Stream::PutLongDouble(long double ld, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes (&ld, sizeof(ld), lldb::endian::InlHostByteOrder(), byte_order);
+}
+
+size_t
+Stream::PutRawBytes (const void *s, size_t src_len, ByteOrder src_byte_order, ByteOrder dst_byte_order)
+{
+ if (src_byte_order == eByteOrderInvalid)
+ src_byte_order = m_byte_order;
+
+ if (dst_byte_order == eByteOrderInvalid)
+ dst_byte_order = m_byte_order;
+
+ size_t bytes_written = 0;
+ const uint8_t *src = (const uint8_t *)s;
+ bool binary_was_set = m_flags.Test (eBinary);
+ if (!binary_was_set)
+ m_flags.Set (eBinary);
+ if (src_byte_order == dst_byte_order)
+ {
+ for (size_t i = 0; i < src_len; ++i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ else
+ {
+ for (size_t i = src_len-1; i < src_len; --i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ if (!binary_was_set)
+ m_flags.Clear (eBinary);
+
+ return bytes_written;
+}
+
+size_t
+Stream::PutBytesAsRawHex8 (const void *s, size_t src_len, ByteOrder src_byte_order, ByteOrder dst_byte_order)
+{
+ if (src_byte_order == eByteOrderInvalid)
+ src_byte_order = m_byte_order;
+
+ if (dst_byte_order == eByteOrderInvalid)
+ dst_byte_order = m_byte_order;
+
+ size_t bytes_written = 0;
+ const uint8_t *src = (const uint8_t *)s;
+ bool binary_is_set = m_flags.Test(eBinary);
+ m_flags.Clear(eBinary);
+ if (src_byte_order == dst_byte_order)
+ {
+ for (size_t i = 0; i < src_len; ++i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ else
+ {
+ for (size_t i = src_len-1; i < src_len; --i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+
+ return bytes_written;
+}
+
+size_t
+Stream::PutCStringAsRawHex8 (const char *s)
+{
+ size_t bytes_written = 0;
+ bool binary_is_set = m_flags.Test(eBinary);
+ m_flags.Clear(eBinary);
+ do
+ {
+ bytes_written += _PutHex8 (*s, false);
+ ++s;
+ } while (*s);
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+ return bytes_written;
+}
+
+void
+Stream::UnitTest(Stream *s)
+{
+ s->PutHex8(0x12);
+
+ s->PutChar(' ');
+ s->PutHex16(0x3456, lldb::endian::InlHostByteOrder());
+ s->PutChar(' ');
+ s->PutHex16(0x3456, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex16(0x3456, eByteOrderLittle);
+
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, lldb::endian::InlHostByteOrder());
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderLittle);
+
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, lldb::endian::InlHostByteOrder());
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, eByteOrderLittle);
+
+ const char *hola = "Hello World!!!";
+ s->PutChar(' ');
+ s->PutCString (hola);
+
+ s->PutChar(' ');
+ s->Write (hola, 5);
+
+ s->PutChar(' ');
+ s->PutCStringAsRawHex8 (hola);
+
+ s->PutChar(' ');
+ s->PutCStringAsRawHex8 ("01234");
+
+ s->PutChar(' ');
+ s->Printf ("pid=%i", 12733);
+
+ s->PutChar(' ');
+ s->PrintfAsRawHex8 ("pid=%i", 12733);
+ s->PutChar('\n');
+}
+
diff --git a/source/Core/StreamAsynchronousIO.cpp b/source/Core/StreamAsynchronousIO.cpp
new file mode 100644
index 0000000..b9e5cdf
--- /dev/null
+++ b/source/Core/StreamAsynchronousIO.cpp
@@ -0,0 +1,52 @@
+//===-- StreamBroadcast.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/StreamAsynchronousIO.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+StreamAsynchronousIO::StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type) :
+ Stream (0, 4, eByteOrderBig),
+ m_broadcaster (broadcaster),
+ m_broadcast_event_type (broadcast_event_type),
+ m_accumulated_data ()
+{
+}
+
+StreamAsynchronousIO::~StreamAsynchronousIO ()
+{
+}
+
+void
+StreamAsynchronousIO::Flush ()
+{
+ if (m_accumulated_data.GetSize() > 0)
+ {
+ std::unique_ptr<EventDataBytes> data_bytes_ap (new EventDataBytes);
+ // Let's swap the bytes to avoid LARGE string copies.
+ data_bytes_ap->SwapBytes (m_accumulated_data.GetString());
+ EventSP new_event_sp (new Event (m_broadcast_event_type, data_bytes_ap.release()));
+ m_broadcaster.BroadcastEvent (new_event_sp);
+ m_accumulated_data.Clear();
+ }
+}
+
+size_t
+StreamAsynchronousIO::Write (const void *s, size_t length)
+{
+ m_accumulated_data.Write (s, length);
+ return length;
+}
diff --git a/source/Core/StreamCallback.cpp b/source/Core/StreamCallback.cpp
new file mode 100644
index 0000000..d144b16
--- /dev/null
+++ b/source/Core/StreamCallback.cpp
@@ -0,0 +1,64 @@
+//===-- StreamCallback.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/StreamCallback.h"
+#include "lldb/Host/Host.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+StreamCallback::StreamCallback (lldb::LogOutputCallback callback, void *baton) :
+ Stream (0, 4, eByteOrderBig),
+ m_callback (callback),
+ m_baton (baton),
+ m_accumulated_data (),
+ m_collection_mutex ()
+{
+}
+
+StreamCallback::~StreamCallback ()
+{
+}
+
+StreamString &
+StreamCallback::FindStreamForThread(lldb::tid_t cur_tid)
+{
+ Mutex::Locker locker(m_collection_mutex);
+ collection::iterator iter = m_accumulated_data.find (cur_tid);
+ if (iter == m_accumulated_data.end())
+ {
+ std::pair<collection::iterator, bool> ret;
+ ret = m_accumulated_data.insert(std::pair<lldb::tid_t,StreamString>(cur_tid, StreamString()));
+ iter = ret.first;
+ }
+ return (*iter).second;
+}
+
+void
+StreamCallback::Flush ()
+{
+ lldb::tid_t cur_tid = Host::GetCurrentThreadID();
+ StreamString &out_stream = FindStreamForThread(cur_tid);
+ m_callback (out_stream.GetData(), m_baton);
+ out_stream.Clear();
+}
+
+size_t
+StreamCallback::Write (const void *s, size_t length)
+{
+ lldb::tid_t cur_tid = Host::GetCurrentThreadID();
+ FindStreamForThread(cur_tid).Write (s, length);
+ return length;
+}
diff --git a/source/Core/StreamFile.cpp b/source/Core/StreamFile.cpp
new file mode 100644
index 0000000..9a4eb79
--- /dev/null
+++ b/source/Core/StreamFile.cpp
@@ -0,0 +1,72 @@
+//===-- StreamFile.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/StreamFile.h"
+
+// C Includes
+#include <stdio.h>
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// StreamFile constructor
+//----------------------------------------------------------------------
+StreamFile::StreamFile () :
+ Stream (),
+ m_file ()
+{
+}
+
+StreamFile::StreamFile (uint32_t flags, uint32_t addr_size, ByteOrder byte_order) :
+ Stream (flags, addr_size, byte_order),
+ m_file ()
+{
+}
+
+StreamFile::StreamFile (int fd, bool transfer_ownership) :
+ Stream (),
+ m_file (fd, transfer_ownership)
+{
+}
+
+StreamFile::StreamFile (FILE *fh, bool transfer_ownership) :
+ Stream (),
+ m_file (fh, transfer_ownership)
+{
+}
+
+StreamFile::StreamFile (const char *path) :
+ Stream (),
+ m_file (path, File::eOpenOptionWrite | File::eOpenOptionCanCreate, File::ePermissionsDefault)
+{
+}
+
+
+StreamFile::~StreamFile()
+{
+}
+
+void
+StreamFile::Flush ()
+{
+ m_file.Flush();
+}
+
+size_t
+StreamFile::Write (const void *s, size_t length)
+{
+ m_file.Write (s, length);
+ return length;
+}
diff --git a/source/Core/StreamString.cpp b/source/Core/StreamString.cpp
new file mode 100644
index 0000000..8d7d039
--- /dev/null
+++ b/source/Core/StreamString.cpp
@@ -0,0 +1,100 @@
+//===-- StreamString.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/StreamString.h"
+#include <stdio.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+StreamString::StreamString () :
+ Stream (0, 4, eByteOrderBig)
+{
+}
+
+StreamString::StreamString(uint32_t flags, uint32_t addr_size, ByteOrder byte_order) :
+ Stream (flags, addr_size, byte_order),
+ m_packet ()
+{
+}
+
+StreamString::~StreamString()
+{
+}
+
+void
+StreamString::Flush ()
+{
+ // Nothing to do when flushing a buffer based stream...
+}
+
+size_t
+StreamString::Write (const void *s, size_t length)
+{
+ m_packet.append ((char *)s, length);
+ return length;
+}
+
+void
+StreamString::Clear()
+{
+ m_packet.clear();
+}
+
+bool
+StreamString::Empty() const
+{
+ return GetSize() == 0;
+}
+
+const char *
+StreamString::GetData () const
+{
+ return m_packet.c_str();
+}
+
+size_t
+StreamString::GetSize () const
+{
+ return m_packet.size();
+}
+
+std::string &
+StreamString::GetString()
+{
+ return m_packet;
+}
+
+const std::string &
+StreamString::GetString() const
+{
+ return m_packet;
+}
+
+void
+StreamString::FillLastLineToColumn (uint32_t column, char fill_char)
+{
+ const size_t length = m_packet.size();
+ size_t last_line_begin_pos = m_packet.find_last_of("\r\n");
+ if (last_line_begin_pos == std::string::npos)
+ {
+ last_line_begin_pos = 0;
+ }
+ else
+ {
+ ++last_line_begin_pos;
+ }
+
+ const size_t line_columns = length - last_line_begin_pos;
+ if (column > line_columns)
+ {
+ m_packet.append(column - line_columns, fill_char);
+ }
+}
+
diff --git a/source/Core/StringList.cpp b/source/Core/StringList.cpp
new file mode 100644
index 0000000..9949751
--- /dev/null
+++ b/source/Core/StringList.cpp
@@ -0,0 +1,290 @@
+//===-- StringList.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/StringList.h"
+
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+
+#include <string>
+
+using namespace lldb_private;
+
+StringList::StringList () :
+ m_strings ()
+{
+}
+
+StringList::StringList (const char *str) :
+ m_strings ()
+{
+ if (str)
+ m_strings.push_back (str);
+}
+
+StringList::StringList (const char **strv, int strc) :
+ m_strings ()
+{
+ for (int i = 0; i < strc; ++i)
+ {
+ if (strv[i])
+ m_strings.push_back (strv[i]);
+ }
+}
+
+StringList::~StringList ()
+{
+}
+
+void
+StringList::AppendString (const char *str)
+{
+ if (str)
+ m_strings.push_back (str);
+}
+
+void
+StringList::AppendString (const std::string &s)
+{
+ m_strings.push_back (s);
+}
+
+void
+StringList::AppendString (const char *str, size_t str_len)
+{
+ if (str)
+ m_strings.push_back (std::string (str, str_len));
+}
+
+void
+StringList::AppendList (const char **strv, int strc)
+{
+ for (int i = 0; i < strc; ++i)
+ {
+ if (strv[i])
+ m_strings.push_back (strv[i]);
+ }
+}
+
+void
+StringList::AppendList (StringList strings)
+{
+ size_t len = strings.GetSize();
+
+ for (size_t i = 0; i < len; ++i)
+ m_strings.push_back (strings.GetStringAtIndex(i));
+}
+
+bool
+StringList::ReadFileLines (FileSpec &input_file)
+{
+ return input_file.ReadFileLines (m_strings);
+}
+
+size_t
+StringList::GetSize () const
+{
+ return m_strings.size();
+}
+
+const char *
+StringList::GetStringAtIndex (size_t idx) const
+{
+ if (idx < m_strings.size())
+ return m_strings[idx].c_str();
+ return NULL;
+}
+
+void
+StringList::Join (const char *separator, Stream &strm)
+{
+ size_t size = GetSize();
+
+ if (size == 0)
+ return;
+
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ if (i > 0)
+ strm.PutCString(separator);
+ strm.PutCString(GetStringAtIndex(i));
+ }
+}
+
+void
+StringList::Clear ()
+{
+ m_strings.clear();
+}
+
+void
+StringList::LongestCommonPrefix (std::string &common_prefix)
+{
+ //arg_sstr_collection::iterator pos, end = m_args.end();
+ size_t pos = 0;
+ size_t end = m_strings.size();
+
+ if (pos == end)
+ common_prefix.clear();
+ else
+ common_prefix = m_strings[pos];
+
+ for (++pos; pos != end; ++pos)
+ {
+ size_t new_size = strlen (m_strings[pos].c_str());
+
+ // First trim common_prefix if it is longer than the current element:
+ if (common_prefix.size() > new_size)
+ common_prefix.erase (new_size);
+
+ // Then trim it at the first disparity:
+
+ for (size_t i = 0; i < common_prefix.size(); i++)
+ {
+ if (m_strings[pos][i] != common_prefix[i])
+ {
+ common_prefix.erase(i);
+ break;
+ }
+ }
+
+ // If we've emptied the common prefix, we're done.
+ if (common_prefix.empty())
+ break;
+ }
+}
+
+void
+StringList::InsertStringAtIndex (size_t idx, const char *str)
+{
+ if (str)
+ {
+ if (idx < m_strings.size())
+ m_strings.insert (m_strings.begin() + idx, str);
+ else
+ m_strings.push_back (str);
+ }
+}
+
+void
+StringList::DeleteStringAtIndex (size_t idx)
+{
+ if (idx < m_strings.size())
+ m_strings.erase (m_strings.begin() + idx);
+}
+
+size_t
+StringList::SplitIntoLines (const char *lines, size_t len)
+{
+ const size_t orig_size = m_strings.size();
+
+ if (len == 0)
+ return 0;
+
+ const char *k_newline_chars = "\r\n";
+ const char *p = lines;
+ const char *end = lines + len;
+ while (p < end)
+ {
+ size_t count = strcspn (p, k_newline_chars);
+ if (count == 0)
+ {
+ if (p[count] == '\r' || p[count] == '\n')
+ m_strings.push_back(std::string());
+ else
+ break;
+ }
+ else
+ {
+ if (p + count > end)
+ count = end - p;
+ m_strings.push_back(std::string(p, count));
+ }
+ if (p[count] == '\r' && p[count+1] == '\n')
+ count++; // Skip an extra newline char for the DOS newline
+ count++; // Skip the newline character
+ p += count;
+ }
+ return m_strings.size() - orig_size;
+}
+
+void
+StringList::RemoveBlankLines ()
+{
+ if (GetSize() == 0)
+ return;
+
+ size_t idx = 0;
+ while (idx < m_strings.size())
+ {
+ if (m_strings[idx].empty())
+ DeleteStringAtIndex(idx);
+ else
+ idx++;
+ }
+}
+
+std::string
+StringList::CopyList(const char* item_preamble,
+ const char* items_sep)
+{
+ StreamString strm;
+ for (size_t i = 0; i < GetSize(); i++)
+ {
+ if (i && items_sep && items_sep[0])
+ strm << items_sep;
+ if (item_preamble)
+ strm << item_preamble;
+ strm << GetStringAtIndex(i);
+ }
+ return std::string(strm.GetData());
+}
+
+StringList&
+StringList::operator << (const char* str)
+{
+ AppendString(str);
+ return *this;
+}
+
+StringList&
+StringList::operator << (StringList strings)
+{
+ AppendList(strings);
+ return *this;
+}
+
+size_t
+StringList::AutoComplete (const char *s, StringList &matches, size_t &exact_idx) const
+{
+ matches.Clear();
+ exact_idx = SIZE_MAX;
+ if (s && s[0])
+ {
+ const size_t s_len = strlen (s);
+ const size_t num_strings = m_strings.size();
+
+ for (size_t i=0; i<num_strings; ++i)
+ {
+ if (m_strings[i].find(s) == 0)
+ {
+ if (exact_idx == SIZE_MAX && m_strings[i].size() == s_len)
+ exact_idx = matches.GetSize();
+ matches.AppendString (m_strings[i]);
+ }
+ }
+ }
+ else
+ {
+ // No string, so it matches everything
+ matches = *this;
+ }
+ return matches.GetSize();
+}
+
diff --git a/source/Core/Timer.cpp b/source/Core/Timer.cpp
new file mode 100644
index 0000000..b1416bd
--- /dev/null
+++ b/source/Core/Timer.cpp
@@ -0,0 +1,250 @@
+//===-- Timer.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/Timer.h"
+
+#include <map>
+#include <vector>
+#include <algorithm>
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/Mutex.h"
+
+#include <stdio.h>
+
+using namespace lldb_private;
+
+#define TIMER_INDENT_AMOUNT 2
+static bool g_quiet = true;
+uint32_t Timer::g_depth = 0;
+uint32_t Timer::g_display_depth = 0;
+FILE * Timer::g_file = NULL;
+typedef std::vector<Timer *> TimerStack;
+typedef std::map<const char *, uint64_t> TimerCategoryMap;
+static pthread_key_t g_key;
+
+static Mutex &
+GetCategoryMutex()
+{
+ static Mutex g_category_mutex(Mutex::eMutexTypeNormal);
+ return g_category_mutex;
+}
+
+static TimerCategoryMap &
+GetCategoryMap()
+{
+ static TimerCategoryMap g_category_map;
+ return g_category_map;
+}
+
+
+static TimerStack *
+GetTimerStackForCurrentThread ()
+{
+ void *timer_stack = ::pthread_getspecific (g_key);
+ if (timer_stack == NULL)
+ {
+ ::pthread_setspecific (g_key, new TimerStack);
+ timer_stack = ::pthread_getspecific (g_key);
+ }
+ return (TimerStack *)timer_stack;
+}
+
+void
+ThreadSpecificCleanup (void *p)
+{
+ delete (TimerStack *)p;
+}
+
+void
+Timer::SetQuiet (bool value)
+{
+ g_quiet = value;
+}
+
+void
+Timer::Initialize ()
+{
+ Timer::g_file = stdout;
+ ::pthread_key_create (&g_key, ThreadSpecificCleanup);
+
+}
+
+Timer::Timer (const char *category, const char *format, ...) :
+ m_category (category),
+ m_total_start (),
+ m_timer_start (),
+ m_total_ticks (0),
+ m_timer_ticks (0)
+{
+ if (g_depth++ < g_display_depth)
+ {
+ if (g_quiet == false)
+ {
+ // Indent
+ ::fprintf (g_file, "%*s", g_depth * TIMER_INDENT_AMOUNT, "");
+ // Print formatted string
+ va_list args;
+ va_start (args, format);
+ ::vfprintf (g_file, format, args);
+ va_end (args);
+
+ // Newline
+ ::fprintf (g_file, "\n");
+ }
+ TimeValue start_time(TimeValue::Now());
+ m_total_start = start_time;
+ m_timer_start = start_time;
+ TimerStack *stack = GetTimerStackForCurrentThread ();
+ if (stack)
+ {
+ if (stack->empty() == false)
+ stack->back()->ChildStarted (start_time);
+ stack->push_back(this);
+ }
+ }
+}
+
+
+Timer::~Timer()
+{
+ if (m_total_start.IsValid())
+ {
+ TimeValue stop_time = TimeValue::Now();
+ if (m_total_start.IsValid())
+ {
+ m_total_ticks += (stop_time - m_total_start);
+ m_total_start.Clear();
+ }
+ if (m_timer_start.IsValid())
+ {
+ m_timer_ticks += (stop_time - m_timer_start);
+ m_timer_start.Clear();
+ }
+
+ TimerStack *stack = GetTimerStackForCurrentThread ();
+ if (stack)
+ {
+ assert (stack->back() == this);
+ stack->pop_back();
+ if (stack->empty() == false)
+ stack->back()->ChildStopped(stop_time);
+ }
+
+ const uint64_t total_nsec_uint = GetTotalElapsedNanoSeconds();
+ const uint64_t timer_nsec_uint = GetTimerElapsedNanoSeconds();
+ const double total_nsec = total_nsec_uint;
+ const double timer_nsec = timer_nsec_uint;
+
+ if (g_quiet == false)
+ {
+
+ ::fprintf (g_file,
+ "%*s%.9f sec (%.9f sec)\n",
+ (g_depth - 1) *TIMER_INDENT_AMOUNT, "",
+ total_nsec / 1000000000.0,
+ timer_nsec / 1000000000.0);
+ }
+
+ // Keep total results for each category so we can dump results.
+ Mutex::Locker locker (GetCategoryMutex());
+ TimerCategoryMap &category_map = GetCategoryMap();
+ category_map[m_category] += timer_nsec_uint;
+ }
+ if (g_depth > 0)
+ --g_depth;
+}
+
+uint64_t
+Timer::GetTotalElapsedNanoSeconds()
+{
+ uint64_t total_ticks = m_total_ticks;
+
+ // If we are currently running, we need to add the current
+ // elapsed time of the running timer...
+ if (m_total_start.IsValid())
+ total_ticks += (TimeValue::Now() - m_total_start);
+
+ return total_ticks;
+}
+
+uint64_t
+Timer::GetTimerElapsedNanoSeconds()
+{
+ uint64_t timer_ticks = m_timer_ticks;
+
+ // If we are currently running, we need to add the current
+ // elapsed time of the running timer...
+ if (m_timer_start.IsValid())
+ timer_ticks += (TimeValue::Now() - m_timer_start);
+
+ return timer_ticks;
+}
+
+void
+Timer::ChildStarted (const TimeValue& start_time)
+{
+ if (m_timer_start.IsValid())
+ {
+ m_timer_ticks += (start_time - m_timer_start);
+ m_timer_start.Clear();
+ }
+}
+
+void
+Timer::ChildStopped (const TimeValue& stop_time)
+{
+ if (!m_timer_start.IsValid())
+ m_timer_start = stop_time;
+}
+
+void
+Timer::SetDisplayDepth (uint32_t depth)
+{
+ g_display_depth = depth;
+}
+
+
+/* binary function predicate:
+ * - returns whether a person is less than another person
+ */
+static bool
+CategoryMapIteratorSortCriterion (const TimerCategoryMap::const_iterator& lhs, const TimerCategoryMap::const_iterator& rhs)
+{
+ return lhs->second > rhs->second;
+}
+
+
+void
+Timer::ResetCategoryTimes ()
+{
+ Mutex::Locker locker (GetCategoryMutex());
+ TimerCategoryMap &category_map = GetCategoryMap();
+ category_map.clear();
+}
+
+void
+Timer::DumpCategoryTimes (Stream *s)
+{
+ Mutex::Locker locker (GetCategoryMutex());
+ TimerCategoryMap &category_map = GetCategoryMap();
+ std::vector<TimerCategoryMap::const_iterator> sorted_iterators;
+ TimerCategoryMap::const_iterator pos, end = category_map.end();
+ for (pos = category_map.begin(); pos != end; ++pos)
+ {
+ sorted_iterators.push_back (pos);
+ }
+ std::sort (sorted_iterators.begin(), sorted_iterators.end(), CategoryMapIteratorSortCriterion);
+
+ const size_t count = sorted_iterators.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ const double timer_nsec = sorted_iterators[i]->second;
+ s->Printf("%.9f sec for %s\n", timer_nsec / 1000000000.0, sorted_iterators[i]->first);
+ }
+}
diff --git a/source/Core/UUID.cpp b/source/Core/UUID.cpp
new file mode 100644
index 0000000..c1b3eb1
--- /dev/null
+++ b/source/Core/UUID.cpp
@@ -0,0 +1,279 @@
+//===-- UUID.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/UUID.h"
+// C Includes
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+
+namespace lldb_private {
+
+UUID::UUID() : m_num_uuid_bytes(16)
+{
+ ::memset (m_uuid, 0, sizeof(m_uuid));
+}
+
+UUID::UUID(const UUID& rhs)
+{
+ m_num_uuid_bytes = rhs.m_num_uuid_bytes;
+ ::memcpy (m_uuid, rhs.m_uuid, sizeof (m_uuid));
+}
+
+UUID::UUID (const void *uuid_bytes, uint32_t num_uuid_bytes)
+{
+ SetBytes (uuid_bytes, num_uuid_bytes);
+}
+
+const UUID&
+UUID::operator=(const UUID& rhs)
+{
+ if (this != &rhs)
+ {
+ m_num_uuid_bytes = rhs.m_num_uuid_bytes;
+ ::memcpy (m_uuid, rhs.m_uuid, sizeof (m_uuid));
+ }
+ return *this;
+}
+
+UUID::~UUID()
+{
+}
+
+void
+UUID::Clear()
+{
+ m_num_uuid_bytes = 16;
+ ::memset (m_uuid, 0, sizeof(m_uuid));
+}
+
+const void *
+UUID::GetBytes() const
+{
+ return m_uuid;
+}
+
+std::string
+UUID::GetAsString (const char *separator) const
+{
+ std::string result;
+ char buf[256];
+ if (!separator)
+ separator = "-";
+ const uint8_t *u = (const uint8_t *)GetBytes();
+ if (sizeof (buf) > (size_t)snprintf (buf,
+ sizeof (buf),
+ "%2.2X%2.2X%2.2X%2.2X%s%2.2X%2.2X%s%2.2X%2.2X%s%2.2X%2.2X%s%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",
+ u[0],u[1],u[2],u[3],separator,
+ u[4],u[5],separator,
+ u[6],u[7],separator,
+ u[8],u[9],separator,
+ u[10],u[11],u[12],u[13],u[14],u[15]))
+ {
+ result.append (buf);
+ if (m_num_uuid_bytes == 20)
+ {
+ if (sizeof (buf) > (size_t)snprintf (buf, sizeof (buf), "%s%2.2X%2.2X%2.2X%2.2X", separator,u[16],u[17],u[18],u[19]))
+ result.append (buf);
+ }
+ }
+ return result;
+}
+
+void
+UUID::Dump (Stream *s) const
+{
+ const uint8_t *u = (const uint8_t *)GetBytes();
+ s->Printf ("%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",
+ u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7],u[8],u[9],u[10],u[11],u[12],u[13],u[14],u[15]);
+ if (m_num_uuid_bytes == 20)
+ {
+ s->Printf ("-%2.2X%2.2X%2.2X%2.2X", u[16],u[17],u[18],u[19]);
+ }
+}
+
+bool
+UUID::SetBytes (const void *uuid_bytes, uint32_t num_uuid_bytes)
+{
+ if (uuid_bytes)
+ {
+ switch (num_uuid_bytes)
+ {
+ case 20:
+ m_num_uuid_bytes = 20;
+ break;
+ case 16:
+ m_num_uuid_bytes = 16;
+ m_uuid[16] = m_uuid[17] = m_uuid[18] = m_uuid[19] = 0;
+ break;
+ default:
+ // Unsupported UUID byte size
+ m_num_uuid_bytes = 0;
+ break;
+ }
+
+ if (m_num_uuid_bytes > 0)
+ {
+ ::memcpy (m_uuid, uuid_bytes, m_num_uuid_bytes);
+ return true;
+ }
+ }
+ ::memset (m_uuid, 0, sizeof(m_uuid));
+ return false;
+}
+
+size_t
+UUID::GetByteSize()
+{
+ return m_num_uuid_bytes;
+}
+
+bool
+UUID::IsValid () const
+{
+ return m_uuid[0] ||
+ m_uuid[1] ||
+ m_uuid[2] ||
+ m_uuid[3] ||
+ m_uuid[4] ||
+ m_uuid[5] ||
+ m_uuid[6] ||
+ m_uuid[7] ||
+ m_uuid[8] ||
+ m_uuid[9] ||
+ m_uuid[10] ||
+ m_uuid[11] ||
+ m_uuid[12] ||
+ m_uuid[13] ||
+ m_uuid[14] ||
+ m_uuid[15] ||
+ m_uuid[16] ||
+ m_uuid[17] ||
+ m_uuid[18] ||
+ m_uuid[19];
+}
+
+static inline int
+xdigit_to_int (char ch)
+{
+ ch = tolower(ch);
+ if (ch >= 'a' && ch <= 'f')
+ return 10 + ch - 'a';
+ return ch - '0';
+}
+
+size_t
+UUID::DecodeUUIDBytesFromCString (const char *p, ValueType &uuid_bytes, const char **end, uint32_t num_uuid_bytes)
+{
+ size_t uuid_byte_idx = 0;
+ if (p)
+ {
+ while (*p)
+ {
+ if (isxdigit(p[0]) && isxdigit(p[1]))
+ {
+ int hi_nibble = xdigit_to_int(p[0]);
+ int lo_nibble = xdigit_to_int(p[1]);
+ // Translate the two hex nibble characters into a byte
+ uuid_bytes[uuid_byte_idx] = (hi_nibble << 4) + lo_nibble;
+
+ // Skip both hex digits
+ p += 2;
+
+ // Increment the byte that we are decoding within the UUID value
+ // and break out if we are done
+ if (++uuid_byte_idx == num_uuid_bytes)
+ break;
+ }
+ else if (*p == '-')
+ {
+ // Skip dashes
+ p++;
+ }
+ else
+ {
+ // UUID values can only consist of hex characters and '-' chars
+ break;
+ }
+ }
+ }
+ if (end)
+ *end = p;
+ // Clear trailing bytes to 0.
+ for (uint32_t i = uuid_byte_idx; i < sizeof(ValueType); i++)
+ uuid_bytes[i] = 0;
+ return uuid_byte_idx;
+}
+size_t
+UUID::SetFromCString (const char *cstr, uint32_t num_uuid_bytes)
+{
+ if (cstr == NULL)
+ return 0;
+
+ const char *p = cstr;
+
+ // Skip leading whitespace characters
+ while (isspace(*p))
+ ++p;
+
+ const size_t uuid_byte_idx = UUID::DecodeUUIDBytesFromCString (p, m_uuid, &p, num_uuid_bytes);
+
+ // If we successfully decoded a UUID, return the amount of characters that
+ // were consumed
+ if (uuid_byte_idx == num_uuid_bytes)
+ return p - cstr;
+
+ // Else return zero to indicate we were not able to parse a UUID value
+ return 0;
+}
+
+}
+
+bool
+lldb_private::operator == (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) == 0;
+}
+
+bool
+lldb_private::operator != (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) != 0;
+}
+
+bool
+lldb_private::operator < (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) < 0;
+}
+
+bool
+lldb_private::operator <= (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) <= 0;
+}
+
+bool
+lldb_private::operator > (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) > 0;
+}
+
+bool
+lldb_private::operator >= (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) >= 0;
+}
diff --git a/source/Core/UserID.cpp b/source/Core/UserID.cpp
new file mode 100644
index 0000000..f3d6e5b
--- /dev/null
+++ b/source/Core/UserID.cpp
@@ -0,0 +1,23 @@
+//===-- UserID.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/UserID.h"
+#include "lldb/Core/Stream.h"
+
+#include <inttypes.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+Stream&
+lldb_private::operator << (Stream& strm, const UserID& uid)
+{
+ strm.Printf("{0x%8.8" PRIx64 "}", uid.GetID());
+ return strm;
+}
diff --git a/source/Core/UserSettingsController.cpp b/source/Core/UserSettingsController.cpp
new file mode 100644
index 0000000..63a5dd9
--- /dev/null
+++ b/source/Core/UserSettingsController.cpp
@@ -0,0 +1,111 @@
+//====-- UserSettingsController.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/lldb-python.h"
+
+#include <string.h>
+#include <algorithm>
+
+#include "lldb/Core/UserSettingsController.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValueString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+lldb::OptionValueSP
+Properties::GetPropertyValue (const ExecutionContext *exe_ctx,
+ const char *path,
+ bool will_modify,
+ Error &error) const
+{
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ return properties_sp->GetSubValue(exe_ctx, path, will_modify, error);
+ return lldb::OptionValueSP();
+}
+
+Error
+Properties::SetPropertyValue (const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ const char *path,
+ const char *value)
+{
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ return properties_sp->SetSubValue(exe_ctx, op, path, value);
+ Error error;
+ error.SetErrorString ("no properties");
+ return error;
+}
+
+void
+Properties::DumpAllPropertyValues (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
+{
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ return properties_sp->DumpValue (exe_ctx, strm, dump_mask);
+}
+
+void
+Properties::DumpAllDescriptions (CommandInterpreter &interpreter,
+ Stream &strm) const
+{
+ strm.PutCString("Top level variables:\n\n");
+
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ return properties_sp->DumpAllDescriptions (interpreter, strm);
+}
+
+
+
+Error
+Properties::DumpPropertyValue (const ExecutionContext *exe_ctx, Stream &strm, const char *property_path, uint32_t dump_mask)
+{
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ {
+ return properties_sp->DumpPropertyValue (exe_ctx,
+ strm,
+ property_path,
+ dump_mask);
+ }
+ Error error;
+ error.SetErrorString("empty property list");
+ return error;
+}
+
+size_t
+Properties::Apropos (const char *keyword, std::vector<const Property *> &matching_properties) const
+{
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ {
+ properties_sp->Apropos (keyword, matching_properties);
+ }
+ return matching_properties.size();
+}
+
+
+lldb::OptionValuePropertiesSP
+Properties::GetSubProperty (const ExecutionContext *exe_ctx,
+ const ConstString &name)
+{
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ return properties_sp->GetSubProperty (exe_ctx, name);
+ return lldb::OptionValuePropertiesSP();
+}
+
diff --git a/source/Core/VMRange.cpp b/source/Core/VMRange.cpp
new file mode 100644
index 0000000..902489e
--- /dev/null
+++ b/source/Core/VMRange.cpp
@@ -0,0 +1,112 @@
+//===-- VMRange.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/lldb-private.h"
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/VMRange.h"
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool
+VMRange::ContainsValue(const VMRange::collection& coll, lldb::addr_t value)
+{
+ ValueInRangeUnaryPredicate in_range_predicate(value);
+ VMRange::const_iterator pos;
+ VMRange::const_iterator end = coll.end();
+ pos = std::find_if( coll.begin(), end, in_range_predicate );
+ if (pos != end)
+ return true;
+ return false;
+}
+
+bool
+VMRange::ContainsRange(const VMRange::collection& coll, const VMRange& range)
+{
+ RangeInRangeUnaryPredicate in_range_predicate(range);
+ VMRange::const_iterator pos;
+ VMRange::const_iterator end = coll.end();
+ pos = std::find_if( coll.begin(), end, in_range_predicate );
+ if (pos != end)
+ return true;
+ return false;
+}
+
+size_t
+VMRange::FindRangeIndexThatContainsValue (const VMRange::collection& coll, lldb::addr_t value)
+{
+ ValueInRangeUnaryPredicate in_range_predicate(value);
+ VMRange::const_iterator begin = coll.begin();
+ VMRange::const_iterator end = coll.end();
+ VMRange::const_iterator pos = std::find_if (begin, end, in_range_predicate);
+ if (pos != end)
+ return std::distance (begin, pos);
+ return UINT32_MAX;
+}
+
+void
+VMRange::Dump(Stream *s, lldb::addr_t offset, uint32_t addr_width) const
+{
+ s->AddressRange(offset + GetBaseAddress(), offset + GetEndAddress(), addr_width);
+}
+
+bool
+lldb_private::operator== (const VMRange& lhs, const VMRange& rhs)
+{
+ return lhs.GetBaseAddress() == rhs.GetBaseAddress() && lhs.GetEndAddress() == rhs.GetEndAddress();
+}
+
+bool
+lldb_private::operator!= (const VMRange& lhs, const VMRange& rhs)
+{
+ return lhs.GetBaseAddress() != rhs.GetBaseAddress() || lhs.GetEndAddress() != rhs.GetEndAddress();
+}
+
+bool
+lldb_private::operator< (const VMRange& lhs, const VMRange& rhs)
+{
+ if (lhs.GetBaseAddress() < rhs.GetBaseAddress())
+ return true;
+ else if (lhs.GetBaseAddress() > rhs.GetBaseAddress())
+ return false;
+ return lhs.GetEndAddress() < rhs.GetEndAddress();
+}
+
+bool
+lldb_private::operator<= (const VMRange& lhs, const VMRange& rhs)
+{
+ if (lhs.GetBaseAddress() < rhs.GetBaseAddress())
+ return true;
+ else if (lhs.GetBaseAddress() > rhs.GetBaseAddress())
+ return false;
+ return lhs.GetEndAddress() <= rhs.GetEndAddress();
+}
+
+bool
+lldb_private::operator> (const VMRange& lhs, const VMRange& rhs)
+{
+ if (lhs.GetBaseAddress() > rhs.GetBaseAddress())
+ return true;
+ else if (lhs.GetBaseAddress() < rhs.GetBaseAddress())
+ return false;
+ return lhs.GetEndAddress() > rhs.GetEndAddress();
+}
+
+bool
+lldb_private::operator>= (const VMRange& lhs, const VMRange& rhs)
+{
+ if (lhs.GetBaseAddress() > rhs.GetBaseAddress())
+ return true;
+ else if (lhs.GetBaseAddress() < rhs.GetBaseAddress())
+ return false;
+ return lhs.GetEndAddress() >= rhs.GetEndAddress();
+}
+
diff --git a/source/Core/Value.cpp b/source/Core/Value.cpp
new file mode 100644
index 0000000..3fe75d3
--- /dev/null
+++ b/source/Core/Value.cpp
@@ -0,0 +1,761 @@
+//===-- Value.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/Value.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Value::Value() :
+ m_value (),
+ m_vector (),
+ m_clang_type (),
+ m_context (NULL),
+ m_value_type (eValueTypeScalar),
+ m_context_type (eContextTypeInvalid),
+ m_data_buffer ()
+{
+}
+
+Value::Value(const Scalar& scalar) :
+ m_value (scalar),
+ m_vector (),
+ m_clang_type (),
+ m_context (NULL),
+ m_value_type (eValueTypeScalar),
+ m_context_type (eContextTypeInvalid),
+ m_data_buffer ()
+{
+}
+
+
+Value::Value(const uint8_t *bytes, int len) :
+ m_value (),
+ m_vector (),
+ m_clang_type (),
+ m_context (NULL),
+ m_value_type (eValueTypeHostAddress),
+ m_context_type (eContextTypeInvalid),
+ m_data_buffer ()
+{
+ m_data_buffer.CopyData(bytes, len);
+ m_value = (uintptr_t)m_data_buffer.GetBytes();
+}
+
+Value::Value(const Value &v) :
+ m_value (v.m_value),
+ m_vector (v.m_vector),
+ m_clang_type (v.m_clang_type),
+ m_context (v.m_context),
+ m_value_type (v.m_value_type),
+ m_context_type (v.m_context_type),
+ m_data_buffer ()
+{
+ if ((uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS) == (uintptr_t)v.m_data_buffer.GetBytes())
+ {
+ m_data_buffer.CopyData(v.m_data_buffer.GetBytes(),
+ v.m_data_buffer.GetByteSize());
+
+ m_value = (uintptr_t)m_data_buffer.GetBytes();
+ }
+}
+
+Value &
+Value::operator=(const Value &rhs)
+{
+ if (this != &rhs)
+ {
+ m_value = rhs.m_value;
+ m_vector = rhs.m_vector;
+ m_clang_type = rhs.m_clang_type;
+ m_context = rhs.m_context;
+ m_value_type = rhs.m_value_type;
+ m_context_type = rhs.m_context_type;
+ if ((uintptr_t)rhs.m_value.ULongLong(LLDB_INVALID_ADDRESS) == (uintptr_t)rhs.m_data_buffer.GetBytes())
+ {
+ m_data_buffer.CopyData(rhs.m_data_buffer.GetBytes(),
+ rhs.m_data_buffer.GetByteSize());
+
+ m_value = (uintptr_t)m_data_buffer.GetBytes();
+ }
+ }
+ return *this;
+}
+
+void
+Value::Dump (Stream* strm)
+{
+ m_value.GetValue (strm, true);
+ strm->Printf(", value_type = %s, context = %p, context_type = %s",
+ Value::GetValueTypeAsCString(m_value_type),
+ m_context,
+ Value::GetContextTypeAsCString(m_context_type));
+}
+
+Value::ValueType
+Value::GetValueType() const
+{
+ return m_value_type;
+}
+
+AddressType
+Value::GetValueAddressType () const
+{
+ switch (m_value_type)
+ {
+ default:
+ case eValueTypeScalar:
+ break;
+ case eValueTypeLoadAddress: return eAddressTypeLoad;
+ case eValueTypeFileAddress: return eAddressTypeFile;
+ case eValueTypeHostAddress: return eAddressTypeHost;
+ }
+ return eAddressTypeInvalid;
+}
+
+RegisterInfo *
+Value::GetRegisterInfo() const
+{
+ if (m_context_type == eContextTypeRegisterInfo)
+ return static_cast<RegisterInfo *> (m_context);
+ return NULL;
+}
+
+Type *
+Value::GetType()
+{
+ if (m_context_type == eContextTypeLLDBType)
+ return static_cast<Type *> (m_context);
+ return NULL;
+}
+
+void
+Value::ResizeData(size_t len)
+{
+ m_value_type = eValueTypeHostAddress;
+ m_data_buffer.SetByteSize(len);
+ m_value = (uintptr_t)m_data_buffer.GetBytes();
+}
+
+bool
+Value::ValueOf(ExecutionContext *exe_ctx)
+{
+ switch (m_context_type)
+ {
+ case eContextTypeInvalid:
+ case eContextTypeRegisterInfo: // RegisterInfo *
+ case eContextTypeLLDBType: // Type *
+ break;
+
+ case eContextTypeVariable: // Variable *
+ ResolveValue(exe_ctx);
+ return true;
+ }
+ return false;
+}
+
+uint64_t
+Value::GetValueByteSize (Error *error_ptr)
+{
+ uint64_t byte_size = 0;
+
+ switch (m_context_type)
+ {
+ case eContextTypeRegisterInfo: // RegisterInfo *
+ if (GetRegisterInfo())
+ byte_size = GetRegisterInfo()->byte_size;
+ break;
+
+ case eContextTypeInvalid:
+ case eContextTypeLLDBType: // Type *
+ case eContextTypeVariable: // Variable *
+ {
+ const ClangASTType &ast_type = GetClangType();
+ if (ast_type.IsValid())
+ byte_size = ast_type.GetByteSize();
+ }
+ break;
+ }
+
+ if (error_ptr)
+ {
+ if (byte_size == 0)
+ {
+ if (error_ptr->Success())
+ error_ptr->SetErrorString("Unable to determine byte size.");
+ }
+ else
+ {
+ error_ptr->Clear();
+ }
+ }
+ return byte_size;
+}
+
+const ClangASTType &
+Value::GetClangType ()
+{
+ if (!m_clang_type.IsValid())
+ {
+ switch (m_context_type)
+ {
+ case eContextTypeInvalid:
+ break;
+
+ case eContextTypeRegisterInfo:
+ break; // TODO: Eventually convert into a clang type?
+
+ case eContextTypeLLDBType:
+ {
+ Type *lldb_type = GetType();
+ if (lldb_type)
+ m_clang_type = lldb_type->GetClangForwardType();
+ }
+ break;
+
+ case eContextTypeVariable:
+ {
+ Variable *variable = GetVariable();
+ if (variable)
+ {
+ Type *variable_type = variable->GetType();
+ if (variable_type)
+ m_clang_type = variable_type->GetClangForwardType();
+ }
+ }
+ break;
+ }
+ }
+
+ return m_clang_type;
+}
+
+void
+Value::SetClangType (const ClangASTType &clang_type)
+{
+ m_clang_type = clang_type;
+}
+
+lldb::Format
+Value::GetValueDefaultFormat ()
+{
+ switch (m_context_type)
+ {
+ case eContextTypeRegisterInfo:
+ if (GetRegisterInfo())
+ return GetRegisterInfo()->format;
+ break;
+
+ case eContextTypeInvalid:
+ case eContextTypeLLDBType:
+ case eContextTypeVariable:
+ {
+ const ClangASTType &ast_type = GetClangType();
+ if (ast_type.IsValid())
+ return ast_type.GetFormat();
+ }
+ break;
+
+ }
+
+ // Return a good default in case we can't figure anything out
+ return eFormatHex;
+}
+
+bool
+Value::GetData (DataExtractor &data)
+{
+ switch (m_value_type)
+ {
+ default:
+ break;
+
+ case eValueTypeScalar:
+ if (m_value.GetData (data))
+ return true;
+ break;
+
+ case eValueTypeLoadAddress:
+ case eValueTypeFileAddress:
+ case eValueTypeHostAddress:
+ if (m_data_buffer.GetByteSize())
+ {
+ data.SetData(m_data_buffer.GetBytes(), m_data_buffer.GetByteSize(), data.GetByteOrder());
+ return true;
+ }
+ break;
+ }
+
+ return false;
+
+}
+
+Error
+Value::GetValueAsData (ExecutionContext *exe_ctx,
+ DataExtractor &data,
+ uint32_t data_offset,
+ Module *module)
+{
+ data.Clear();
+
+ Error error;
+ lldb::addr_t address = LLDB_INVALID_ADDRESS;
+ AddressType address_type = eAddressTypeFile;
+ Address file_so_addr;
+ const ClangASTType &ast_type = GetClangType();
+ switch (m_value_type)
+ {
+ case eValueTypeVector:
+ if (ast_type.IsValid())
+ data.SetAddressByteSize (ast_type.GetPointerByteSize());
+ else
+ data.SetAddressByteSize(sizeof(void *));
+ data.SetData(m_vector.bytes, m_vector.length, m_vector.byte_order);
+ break;
+
+ case eValueTypeScalar:
+ data.SetByteOrder (lldb::endian::InlHostByteOrder());
+ if (ast_type.IsValid())
+ data.SetAddressByteSize (ast_type.GetPointerByteSize());
+ else
+ data.SetAddressByteSize(sizeof(void *));
+ if (m_value.GetData (data))
+ return error; // Success;
+ error.SetErrorStringWithFormat("extracting data from value failed");
+ break;
+
+ case eValueTypeLoadAddress:
+ if (exe_ctx == NULL)
+ {
+ error.SetErrorString ("can't read load address (no execution context)");
+ }
+ else
+ {
+ Process *process = exe_ctx->GetProcessPtr();
+ if (process == NULL || !process->IsAlive())
+ {
+ Target *target = exe_ctx->GetTargetPtr();
+ if (target)
+ {
+ // Allow expressions to run and evaluate things when the target
+ // has memory sections loaded. This allows you to use "target modules load"
+ // to load your executable and any shared libraries, then execute
+ // commands where you can look at types in data sections.
+ const SectionLoadList &target_sections = target->GetSectionLoadList();
+ if (!target_sections.IsEmpty())
+ {
+ address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ if (target_sections.ResolveLoadAddress(address, file_so_addr))
+ {
+ address_type = eAddressTypeLoad;
+ data.SetByteOrder(target->GetArchitecture().GetByteOrder());
+ data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
+ }
+ else
+ address = LLDB_INVALID_ADDRESS;
+ }
+// else
+// {
+// ModuleSP exe_module_sp (target->GetExecutableModule());
+// if (exe_module_sp)
+// {
+// address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+// if (address != LLDB_INVALID_ADDRESS)
+// {
+// if (exe_module_sp->ResolveFileAddress(address, file_so_addr))
+// {
+// data.SetByteOrder(target->GetArchitecture().GetByteOrder());
+// data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
+// address_type = eAddressTypeFile;
+// }
+// else
+// {
+// address = LLDB_INVALID_ADDRESS;
+// }
+// }
+// }
+// }
+ }
+ else
+ {
+ error.SetErrorString ("can't read load address (invalid process)");
+ }
+ }
+ else
+ {
+ address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ address_type = eAddressTypeLoad;
+ data.SetByteOrder(process->GetTarget().GetArchitecture().GetByteOrder());
+ data.SetAddressByteSize(process->GetTarget().GetArchitecture().GetAddressByteSize());
+ }
+ }
+ break;
+
+ case eValueTypeFileAddress:
+ if (exe_ctx == NULL)
+ {
+ error.SetErrorString ("can't read file address (no execution context)");
+ }
+ else if (exe_ctx->GetTargetPtr() == NULL)
+ {
+ error.SetErrorString ("can't read file address (invalid target)");
+ }
+ else
+ {
+ address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ if (address == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorString ("invalid file address");
+ }
+ else
+ {
+ if (module == NULL)
+ {
+ // The only thing we can currently lock down to a module so that
+ // we can resolve a file address, is a variable.
+ Variable *variable = GetVariable();
+ if (variable)
+ {
+ SymbolContext var_sc;
+ variable->CalculateSymbolContext(&var_sc);
+ module = var_sc.module_sp.get();
+ }
+ }
+
+ if (module)
+ {
+ bool resolved = false;
+ ObjectFile *objfile = module->GetObjectFile();
+ if (objfile)
+ {
+ Address so_addr(address, objfile->GetSectionList());
+ addr_t load_address = so_addr.GetLoadAddress (exe_ctx->GetTargetPtr());
+ bool process_launched_and_stopped = exe_ctx->GetProcessPtr()
+ ? StateIsStoppedState(exe_ctx->GetProcessPtr()->GetState(), true /* must_exist */)
+ : false;
+ // Don't use the load address if the process has exited.
+ if (load_address != LLDB_INVALID_ADDRESS && process_launched_and_stopped)
+ {
+ resolved = true;
+ address = load_address;
+ address_type = eAddressTypeLoad;
+ data.SetByteOrder(exe_ctx->GetTargetRef().GetArchitecture().GetByteOrder());
+ data.SetAddressByteSize(exe_ctx->GetTargetRef().GetArchitecture().GetAddressByteSize());
+ }
+ else
+ {
+ if (so_addr.IsSectionOffset())
+ {
+ resolved = true;
+ file_so_addr = so_addr;
+ data.SetByteOrder(objfile->GetByteOrder());
+ data.SetAddressByteSize(objfile->GetAddressByteSize());
+ }
+ }
+ }
+ if (!resolved)
+ {
+ Variable *variable = GetVariable();
+
+ if (module)
+ {
+ if (variable)
+ error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64 " for variable '%s' in %s",
+ address,
+ variable->GetName().AsCString(""),
+ module->GetFileSpec().GetPath().c_str());
+ else
+ error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64 " in %s",
+ address,
+ module->GetFileSpec().GetPath().c_str());
+ }
+ else
+ {
+ if (variable)
+ error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64 " for variable '%s'",
+ address,
+ variable->GetName().AsCString(""));
+ else
+ error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64, address);
+ }
+ }
+ }
+ else
+ {
+ // Can't convert a file address to anything valid without more
+ // context (which Module it came from)
+ error.SetErrorString ("can't read memory from file address without more context");
+ }
+ }
+ }
+ break;
+
+ case eValueTypeHostAddress:
+ address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ address_type = eAddressTypeHost;
+ if (exe_ctx)
+ {
+ Target *target = exe_ctx->GetTargetPtr();
+ if (target)
+ {
+ data.SetByteOrder(target->GetArchitecture().GetByteOrder());
+ data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
+ break;
+ }
+ }
+ // fallback to host settings
+ data.SetByteOrder(lldb::endian::InlHostByteOrder());
+ data.SetAddressByteSize(sizeof(void *));
+ break;
+ }
+
+ // Bail if we encountered any errors
+ if (error.Fail())
+ return error;
+
+ if (address == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorStringWithFormat ("invalid %s address", address_type == eAddressTypeHost ? "host" : "load");
+ return error;
+ }
+
+ // If we got here, we need to read the value from memory
+ size_t byte_size = GetValueByteSize (&error);
+
+ // Bail if we encountered any errors getting the byte size
+ if (error.Fail())
+ return error;
+
+ // Make sure we have enough room within "data", and if we don't make
+ // something large enough that does
+ if (!data.ValidOffsetForDataOfSize (data_offset, byte_size))
+ {
+ DataBufferSP data_sp(new DataBufferHeap (data_offset + byte_size, '\0'));
+ data.SetData(data_sp);
+ }
+
+ uint8_t* dst = const_cast<uint8_t*>(data.PeekData (data_offset, byte_size));
+ if (dst != NULL)
+ {
+ if (address_type == eAddressTypeHost)
+ {
+ // The address is an address in this process, so just copy it
+ memcpy (dst, (uint8_t*)NULL + address, byte_size);
+ }
+ else if ((address_type == eAddressTypeLoad) || (address_type == eAddressTypeFile))
+ {
+ if (file_so_addr.IsValid())
+ {
+ // We have a file address that we were able to translate into a
+ // section offset address so we might be able to read this from
+ // the object files if we don't have a live process. Lets always
+ // try and read from the process if we have one though since we
+ // want to read the actual value by setting "prefer_file_cache"
+ // to false.
+ const bool prefer_file_cache = false;
+ if (exe_ctx->GetTargetRef().ReadMemory(file_so_addr, prefer_file_cache, dst, byte_size, error) != byte_size)
+ {
+ error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed", (uint64_t)address);
+ }
+ }
+ else
+ {
+ // The execution context might have a NULL process, but it
+ // might have a valid process in the exe_ctx->target, so use
+ // the ExecutionContext::GetProcess accessor to ensure we
+ // get the process if there is one.
+ Process *process = exe_ctx->GetProcessPtr();
+
+ if (process)
+ {
+ const size_t bytes_read = process->ReadMemory(address, dst, byte_size, error);
+ if (bytes_read != byte_size)
+ error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed (%u of %u bytes read)",
+ (uint64_t)address,
+ (uint32_t)bytes_read,
+ (uint32_t)byte_size);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed (invalid process)", (uint64_t)address);
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported AddressType value (%i)", address_type);
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("out of memory");
+ }
+
+ return error;
+}
+
+Scalar &
+Value::ResolveValue(ExecutionContext *exe_ctx)
+{
+ const ClangASTType &clang_type = GetClangType();
+ if (clang_type.IsValid())
+ {
+ switch (m_value_type)
+ {
+ case eValueTypeScalar: // raw scalar value
+ break;
+
+ default:
+ case eValueTypeFileAddress:
+ case eValueTypeLoadAddress: // load address value
+ case eValueTypeHostAddress: // host address value (for memory in the process that is using liblldb)
+ {
+ DataExtractor data;
+ lldb::addr_t addr = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ Error error (GetValueAsData (exe_ctx, data, 0, NULL));
+ if (error.Success())
+ {
+ Scalar scalar;
+ if (clang_type.GetValueAsScalar (data, 0, data.GetByteSize(), scalar))
+ {
+ m_value = scalar;
+ m_value_type = eValueTypeScalar;
+ }
+ else
+ {
+ if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes())
+ {
+ m_value.Clear();
+ m_value_type = eValueTypeScalar;
+ }
+ }
+ }
+ else
+ {
+ if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes())
+ {
+ m_value.Clear();
+ m_value_type = eValueTypeScalar;
+ }
+ }
+ }
+ break;
+ }
+ }
+ return m_value;
+}
+
+Variable *
+Value::GetVariable()
+{
+ if (m_context_type == eContextTypeVariable)
+ return static_cast<Variable *> (m_context);
+ return NULL;
+}
+
+void
+Value::Clear()
+{
+ m_value.Clear();
+ m_vector.Clear();
+ m_clang_type.Clear();
+ m_value_type = eValueTypeScalar;
+ m_context = NULL;
+ m_context_type = eContextTypeInvalid;
+ m_data_buffer.Clear();
+}
+
+
+const char *
+Value::GetValueTypeAsCString (ValueType value_type)
+{
+ switch (value_type)
+ {
+ case eValueTypeScalar: return "scalar";
+ case eValueTypeVector: return "vector";
+ case eValueTypeFileAddress: return "file address";
+ case eValueTypeLoadAddress: return "load address";
+ case eValueTypeHostAddress: return "host address";
+ };
+ return "???";
+}
+
+const char *
+Value::GetContextTypeAsCString (ContextType context_type)
+{
+ switch (context_type)
+ {
+ case eContextTypeInvalid: return "invalid";
+ case eContextTypeRegisterInfo: return "RegisterInfo *";
+ case eContextTypeLLDBType: return "Type *";
+ case eContextTypeVariable: return "Variable *";
+ };
+ return "???";
+}
+
+ValueList::ValueList (const ValueList &rhs)
+{
+ m_values = rhs.m_values;
+}
+
+const ValueList &
+ValueList::operator= (const ValueList &rhs)
+{
+ m_values = rhs.m_values;
+ return *this;
+}
+
+void
+ValueList::PushValue (const Value &value)
+{
+ m_values.push_back (value);
+}
+
+size_t
+ValueList::GetSize()
+{
+ return m_values.size();
+}
+
+Value *
+ValueList::GetValueAtIndex (size_t idx)
+{
+ if (idx < GetSize())
+ {
+ return &(m_values[idx]);
+ }
+ else
+ return NULL;
+}
+
+void
+ValueList::Clear ()
+{
+ m_values.clear();
+}
+
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp
new file mode 100644
index 0000000..a30cc13
--- /dev/null
+++ b/source/Core/ValueObject.cpp
@@ -0,0 +1,4199 @@
+//===-- ValueObject.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/lldb-python.h"
+
+#include "lldb/Core/ValueObject.h"
+
+// C Includes
+#include <stdlib.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "llvm/Support/raw_ostream.h"
+#include "clang/AST/Type.h"
+
+// Project includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObjectCast.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectDynamicValue.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Core/ValueObjectSyntheticFilter.h"
+
+#include "lldb/DataFormatters/DataVisualization.h"
+
+#include "lldb/Host/Endian.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Type.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_utility;
+
+static user_id_t g_value_obj_uid = 0;
+
+//----------------------------------------------------------------------
+// ValueObject constructor
+//----------------------------------------------------------------------
+ValueObject::ValueObject (ValueObject &parent) :
+ UserID (++g_value_obj_uid), // Unique identifier for every value object
+ m_parent (&parent),
+ m_root (NULL),
+ m_update_point (parent.GetUpdatePoint ()),
+ m_name (),
+ m_data (),
+ m_value (),
+ m_error (),
+ m_value_str (),
+ m_old_value_str (),
+ m_location_str (),
+ m_summary_str (),
+ m_object_desc_str (),
+ m_manager(parent.GetManager()),
+ m_children (),
+ m_synthetic_children (),
+ m_dynamic_value (NULL),
+ m_synthetic_value(NULL),
+ m_deref_valobj(NULL),
+ m_format (eFormatDefault),
+ m_last_format (eFormatDefault),
+ m_last_format_mgr_revision(0),
+ m_type_summary_sp(),
+ m_type_format_sp(),
+ m_synthetic_children_sp(),
+ m_user_id_of_forced_summary(),
+ m_address_type_of_ptr_or_ref_children(eAddressTypeInvalid),
+ m_value_is_valid (false),
+ m_value_did_change (false),
+ m_children_count_valid (false),
+ m_old_value_valid (false),
+ m_is_deref_of_parent (false),
+ m_is_array_item_for_pointer(false),
+ m_is_bitfield_for_scalar(false),
+ m_is_child_at_offset(false),
+ m_is_getting_summary(false),
+ m_did_calculate_complete_objc_class_type(false)
+{
+ m_manager->ManageObject(this);
+}
+
+//----------------------------------------------------------------------
+// ValueObject constructor
+//----------------------------------------------------------------------
+ValueObject::ValueObject (ExecutionContextScope *exe_scope,
+ AddressType child_ptr_or_ref_addr_type) :
+ UserID (++g_value_obj_uid), // Unique identifier for every value object
+ m_parent (NULL),
+ m_root (NULL),
+ m_update_point (exe_scope),
+ m_name (),
+ m_data (),
+ m_value (),
+ m_error (),
+ m_value_str (),
+ m_old_value_str (),
+ m_location_str (),
+ m_summary_str (),
+ m_object_desc_str (),
+ m_manager(),
+ m_children (),
+ m_synthetic_children (),
+ m_dynamic_value (NULL),
+ m_synthetic_value(NULL),
+ m_deref_valobj(NULL),
+ m_format (eFormatDefault),
+ m_last_format (eFormatDefault),
+ m_last_format_mgr_revision(0),
+ m_type_summary_sp(),
+ m_type_format_sp(),
+ m_synthetic_children_sp(),
+ m_user_id_of_forced_summary(),
+ m_address_type_of_ptr_or_ref_children(child_ptr_or_ref_addr_type),
+ m_value_is_valid (false),
+ m_value_did_change (false),
+ m_children_count_valid (false),
+ m_old_value_valid (false),
+ m_is_deref_of_parent (false),
+ m_is_array_item_for_pointer(false),
+ m_is_bitfield_for_scalar(false),
+ m_is_child_at_offset(false),
+ m_is_getting_summary(false),
+ m_did_calculate_complete_objc_class_type(false)
+{
+ m_manager = new ValueObjectManager();
+ m_manager->ManageObject (this);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ValueObject::~ValueObject ()
+{
+}
+
+bool
+ValueObject::UpdateValueIfNeeded (bool update_format)
+{
+
+ bool did_change_formats = false;
+
+ if (update_format)
+ did_change_formats = UpdateFormatsIfNeeded();
+
+ // If this is a constant value, then our success is predicated on whether
+ // we have an error or not
+ if (GetIsConstant())
+ {
+ // if you were asked to update your formatters, but did not get a chance to do it
+ // clear your own values (this serves the purpose of faking a stop-id for frozen
+ // objects (which are regarded as constant, but could have changes behind their backs
+ // because of the frozen-pointer depth limit)
+ // TODO: decouple summary from value and then remove this code and only force-clear the summary
+ if (update_format && !did_change_formats)
+ ClearUserVisibleData(eClearUserVisibleDataItemsSummary);
+ return m_error.Success();
+ }
+
+ bool first_update = m_update_point.IsFirstEvaluation();
+
+ if (m_update_point.NeedsUpdating())
+ {
+ m_update_point.SetUpdated();
+
+ // Save the old value using swap to avoid a string copy which
+ // also will clear our m_value_str
+ if (m_value_str.empty())
+ {
+ m_old_value_valid = false;
+ }
+ else
+ {
+ m_old_value_valid = true;
+ m_old_value_str.swap (m_value_str);
+ ClearUserVisibleData(eClearUserVisibleDataItemsValue);
+ }
+
+ ClearUserVisibleData();
+
+ if (IsInScope())
+ {
+ const bool value_was_valid = GetValueIsValid();
+ SetValueDidChange (false);
+
+ m_error.Clear();
+
+ // Call the pure virtual function to update the value
+ bool success = UpdateValue ();
+
+ SetValueIsValid (success);
+
+ if (first_update)
+ SetValueDidChange (false);
+ else if (!m_value_did_change && success == false)
+ {
+ // The value wasn't gotten successfully, so we mark this
+ // as changed if the value used to be valid and now isn't
+ SetValueDidChange (value_was_valid);
+ }
+ }
+ else
+ {
+ m_error.SetErrorString("out of scope");
+ }
+ }
+ return m_error.Success();
+}
+
+bool
+ValueObject::UpdateFormatsIfNeeded()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+ if (log)
+ log->Printf("[%s %p] checking for FormatManager revisions. ValueObject rev: %d - Global rev: %d",
+ GetName().GetCString(),
+ this,
+ m_last_format_mgr_revision,
+ DataVisualization::GetCurrentRevision());
+
+ bool any_change = false;
+
+ if ( (m_last_format_mgr_revision != DataVisualization::GetCurrentRevision()))
+ {
+ SetValueFormat(DataVisualization::ValueFormats::GetFormat (*this, eNoDynamicValues));
+ SetSummaryFormat(DataVisualization::GetSummaryFormat (*this, GetDynamicValueType()));
+#ifndef LLDB_DISABLE_PYTHON
+ SetSyntheticChildren(DataVisualization::GetSyntheticChildren (*this, GetDynamicValueType()));
+#endif
+
+ m_last_format_mgr_revision = DataVisualization::GetCurrentRevision();
+
+ any_change = true;
+ }
+
+ return any_change;
+
+}
+
+void
+ValueObject::SetNeedsUpdate ()
+{
+ m_update_point.SetNeedsUpdate();
+ // We have to clear the value string here so ConstResult children will notice if their values are
+ // changed by hand (i.e. with SetValueAsCString).
+ ClearUserVisibleData(eClearUserVisibleDataItemsValue);
+}
+
+void
+ValueObject::ClearDynamicTypeInformation ()
+{
+ m_did_calculate_complete_objc_class_type = false;
+ m_last_format_mgr_revision = 0;
+ m_override_type = ClangASTType();
+ SetValueFormat(lldb::TypeFormatImplSP());
+ SetSummaryFormat(lldb::TypeSummaryImplSP());
+ SetSyntheticChildren(lldb::SyntheticChildrenSP());
+}
+
+ClangASTType
+ValueObject::MaybeCalculateCompleteType ()
+{
+ ClangASTType clang_type(GetClangTypeImpl());
+
+ if (m_did_calculate_complete_objc_class_type)
+ {
+ if (m_override_type.IsValid())
+ return m_override_type;
+ else
+ return clang_type;
+ }
+
+ ClangASTType class_type;
+ bool is_pointer_type = false;
+
+ if (clang_type.IsObjCObjectPointerType(&class_type))
+ {
+ is_pointer_type = true;
+ }
+ else if (clang_type.IsObjCObjectOrInterfaceType())
+ {
+ class_type = clang_type;
+ }
+ else
+ {
+ return clang_type;
+ }
+
+ m_did_calculate_complete_objc_class_type = true;
+
+ if (class_type)
+ {
+ ConstString class_name (class_type.GetConstTypeName());
+
+ if (class_name)
+ {
+ ProcessSP process_sp(GetUpdatePoint().GetExecutionContextRef().GetProcessSP());
+
+ if (process_sp)
+ {
+ ObjCLanguageRuntime *objc_language_runtime(process_sp->GetObjCLanguageRuntime());
+
+ if (objc_language_runtime)
+ {
+ TypeSP complete_objc_class_type_sp = objc_language_runtime->LookupInCompleteClassCache(class_name);
+
+ if (complete_objc_class_type_sp)
+ {
+ ClangASTType complete_class(complete_objc_class_type_sp->GetClangFullType());
+
+ if (complete_class.GetCompleteType())
+ {
+ if (is_pointer_type)
+ {
+ m_override_type = complete_class.GetPointerType();
+ }
+ else
+ {
+ m_override_type = complete_class;
+ }
+
+ if (m_override_type.IsValid())
+ return m_override_type;
+ }
+ }
+ }
+ }
+ }
+ }
+ return clang_type;
+}
+
+ClangASTType
+ValueObject::GetClangType ()
+{
+ return MaybeCalculateCompleteType();
+}
+
+DataExtractor &
+ValueObject::GetDataExtractor ()
+{
+ UpdateValueIfNeeded(false);
+ return m_data;
+}
+
+const Error &
+ValueObject::GetError()
+{
+ UpdateValueIfNeeded(false);
+ return m_error;
+}
+
+const ConstString &
+ValueObject::GetName() const
+{
+ return m_name;
+}
+
+const char *
+ValueObject::GetLocationAsCString ()
+{
+ return GetLocationAsCStringImpl(m_value,
+ m_data);
+}
+
+const char *
+ValueObject::GetLocationAsCStringImpl (const Value& value,
+ const DataExtractor& data)
+{
+ if (UpdateValueIfNeeded(false))
+ {
+ if (m_location_str.empty())
+ {
+ StreamString sstr;
+
+ Value::ValueType value_type = value.GetValueType();
+
+ switch (value_type)
+ {
+ case Value::eValueTypeScalar:
+ case Value::eValueTypeVector:
+ if (value.GetContextType() == Value::eContextTypeRegisterInfo)
+ {
+ RegisterInfo *reg_info = value.GetRegisterInfo();
+ if (reg_info)
+ {
+ if (reg_info->name)
+ m_location_str = reg_info->name;
+ else if (reg_info->alt_name)
+ m_location_str = reg_info->alt_name;
+ if (m_location_str.empty())
+ m_location_str = (reg_info->encoding == lldb::eEncodingVector) ? "vector" : "scalar";
+ }
+ }
+ if (m_location_str.empty())
+ m_location_str = (value_type == Value::eValueTypeVector) ? "vector" : "scalar";
+ break;
+
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeHostAddress:
+ {
+ uint32_t addr_nibble_size = data.GetAddressByteSize() * 2;
+ sstr.Printf("0x%*.*llx", addr_nibble_size, addr_nibble_size, value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS));
+ m_location_str.swap(sstr.GetString());
+ }
+ break;
+ }
+ }
+ }
+ return m_location_str.c_str();
+}
+
+Value &
+ValueObject::GetValue()
+{
+ return m_value;
+}
+
+const Value &
+ValueObject::GetValue() const
+{
+ return m_value;
+}
+
+bool
+ValueObject::ResolveValue (Scalar &scalar)
+{
+ if (UpdateValueIfNeeded(false)) // make sure that you are up to date before returning anything
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Value tmp_value(m_value);
+ scalar = tmp_value.ResolveValue(&exe_ctx);
+ if (scalar.IsValid())
+ {
+ const uint32_t bitfield_bit_size = GetBitfieldBitSize();
+ if (bitfield_bit_size)
+ return scalar.ExtractBitfield (bitfield_bit_size, GetBitfieldBitOffset());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+ValueObject::GetValueIsValid () const
+{
+ return m_value_is_valid;
+}
+
+
+void
+ValueObject::SetValueIsValid (bool b)
+{
+ m_value_is_valid = b;
+}
+
+bool
+ValueObject::GetValueDidChange ()
+{
+ GetValueAsCString ();
+ return m_value_did_change;
+}
+
+void
+ValueObject::SetValueDidChange (bool value_changed)
+{
+ m_value_did_change = value_changed;
+}
+
+ValueObjectSP
+ValueObject::GetChildAtIndex (size_t idx, bool can_create)
+{
+ ValueObjectSP child_sp;
+ // We may need to update our value if we are dynamic
+ if (IsPossibleDynamicType ())
+ UpdateValueIfNeeded(false);
+ if (idx < GetNumChildren())
+ {
+ // Check if we have already made the child value object?
+ if (can_create && !m_children.HasChildAtIndex(idx))
+ {
+ // No we haven't created the child at this index, so lets have our
+ // subclass do it and cache the result for quick future access.
+ m_children.SetChildAtIndex(idx,CreateChildAtIndex (idx, false, 0));
+ }
+
+ ValueObject* child = m_children.GetChildAtIndex(idx);
+ if (child != NULL)
+ return child->GetSP();
+ }
+ return child_sp;
+}
+
+ValueObjectSP
+ValueObject::GetChildAtIndexPath (const std::initializer_list<size_t>& idxs,
+ size_t* index_of_error)
+{
+ if (idxs.size() == 0)
+ return GetSP();
+ ValueObjectSP root(GetSP());
+ for (size_t idx : idxs)
+ {
+ root = root->GetChildAtIndex(idx, true);
+ if (!root)
+ {
+ if (index_of_error)
+ *index_of_error = idx;
+ return root;
+ }
+ }
+ return root;
+}
+
+ValueObjectSP
+ValueObject::GetChildAtIndexPath (const std::initializer_list< std::pair<size_t, bool> >& idxs,
+ size_t* index_of_error)
+{
+ if (idxs.size() == 0)
+ return GetSP();
+ ValueObjectSP root(GetSP());
+ for (std::pair<size_t, bool> idx : idxs)
+ {
+ root = root->GetChildAtIndex(idx.first, idx.second);
+ if (!root)
+ {
+ if (index_of_error)
+ *index_of_error = idx.first;
+ return root;
+ }
+ }
+ return root;
+}
+
+lldb::ValueObjectSP
+ValueObject::GetChildAtIndexPath (const std::vector<size_t> &idxs,
+ size_t* index_of_error)
+{
+ if (idxs.size() == 0)
+ return GetSP();
+ ValueObjectSP root(GetSP());
+ for (size_t idx : idxs)
+ {
+ root = root->GetChildAtIndex(idx, true);
+ if (!root)
+ {
+ if (index_of_error)
+ *index_of_error = idx;
+ return root;
+ }
+ }
+ return root;
+}
+
+lldb::ValueObjectSP
+ValueObject::GetChildAtIndexPath (const std::vector< std::pair<size_t, bool> > &idxs,
+ size_t* index_of_error)
+{
+ if (idxs.size() == 0)
+ return GetSP();
+ ValueObjectSP root(GetSP());
+ for (std::pair<size_t, bool> idx : idxs)
+ {
+ root = root->GetChildAtIndex(idx.first, idx.second);
+ if (!root)
+ {
+ if (index_of_error)
+ *index_of_error = idx.first;
+ return root;
+ }
+ }
+ return root;
+}
+
+size_t
+ValueObject::GetIndexOfChildWithName (const ConstString &name)
+{
+ bool omit_empty_base_classes = true;
+ return GetClangType().GetIndexOfChildWithName (name.GetCString(), omit_empty_base_classes);
+}
+
+ValueObjectSP
+ValueObject::GetChildMemberWithName (const ConstString &name, bool can_create)
+{
+ // when getting a child by name, it could be buried inside some base
+ // classes (which really aren't part of the expression path), so we
+ // need a vector of indexes that can get us down to the correct child
+ ValueObjectSP child_sp;
+
+ // We may need to update our value if we are dynamic
+ if (IsPossibleDynamicType ())
+ UpdateValueIfNeeded(false);
+
+ std::vector<uint32_t> child_indexes;
+ bool omit_empty_base_classes = true;
+ const size_t num_child_indexes = GetClangType().GetIndexOfChildMemberWithName (name.GetCString(),
+ omit_empty_base_classes,
+ child_indexes);
+ if (num_child_indexes > 0)
+ {
+ std::vector<uint32_t>::const_iterator pos = child_indexes.begin ();
+ std::vector<uint32_t>::const_iterator end = child_indexes.end ();
+
+ child_sp = GetChildAtIndex(*pos, can_create);
+ for (++pos; pos != end; ++pos)
+ {
+ if (child_sp)
+ {
+ ValueObjectSP new_child_sp(child_sp->GetChildAtIndex (*pos, can_create));
+ child_sp = new_child_sp;
+ }
+ else
+ {
+ child_sp.reset();
+ }
+
+ }
+ }
+ return child_sp;
+}
+
+
+size_t
+ValueObject::GetNumChildren ()
+{
+ UpdateValueIfNeeded();
+ if (!m_children_count_valid)
+ {
+ SetNumChildren (CalculateNumChildren());
+ }
+ return m_children.GetChildrenCount();
+}
+
+bool
+ValueObject::MightHaveChildren()
+{
+ bool has_children = false;
+ const uint32_t type_info = GetTypeInfo();
+ if (type_info)
+ {
+ if (type_info & (ClangASTType::eTypeHasChildren |
+ ClangASTType::eTypeIsPointer |
+ ClangASTType::eTypeIsReference))
+ has_children = true;
+ }
+ else
+ {
+ has_children = GetNumChildren () > 0;
+ }
+ return has_children;
+}
+
+// Should only be called by ValueObject::GetNumChildren()
+void
+ValueObject::SetNumChildren (size_t num_children)
+{
+ m_children_count_valid = true;
+ m_children.SetChildrenCount(num_children);
+}
+
+void
+ValueObject::SetName (const ConstString &name)
+{
+ m_name = name;
+}
+
+ValueObject *
+ValueObject::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ ValueObject *valobj = NULL;
+
+ bool omit_empty_base_classes = true;
+ bool ignore_array_bounds = synthetic_array_member;
+ std::string child_name_str;
+ uint32_t child_byte_size = 0;
+ int32_t child_byte_offset = 0;
+ uint32_t child_bitfield_bit_size = 0;
+ uint32_t child_bitfield_bit_offset = 0;
+ bool child_is_base_class = false;
+ bool child_is_deref_of_parent = false;
+
+ const bool transparent_pointers = synthetic_array_member == false;
+ ClangASTType child_clang_type;
+
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+
+ child_clang_type = GetClangType().GetChildClangTypeAtIndex (&exe_ctx,
+ GetName().GetCString(),
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ ignore_array_bounds,
+ child_name_str,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent);
+ if (child_clang_type)
+ {
+ if (synthetic_index)
+ child_byte_offset += child_byte_size * synthetic_index;
+
+ ConstString child_name;
+ if (!child_name_str.empty())
+ child_name.SetCString (child_name_str.c_str());
+
+ valobj = new ValueObjectChild (*this,
+ child_clang_type,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent,
+ eAddressTypeInvalid);
+ //if (valobj)
+ // valobj->SetAddressTypeOfChildren(eAddressTypeInvalid);
+ }
+
+ return valobj;
+}
+
+bool
+ValueObject::GetSummaryAsCString (TypeSummaryImpl* summary_ptr,
+ std::string& destination)
+{
+ destination.clear();
+
+ // ideally we would like to bail out if passing NULL, but if we do so
+ // we end up not providing the summary for function pointers anymore
+ if (/*summary_ptr == NULL ||*/ m_is_getting_summary)
+ return false;
+
+ m_is_getting_summary = true;
+
+ // this is a hot path in code and we prefer to avoid setting this string all too often also clearing out other
+ // information that we might care to see in a crash log. might be useful in very specific situations though.
+ /*Host::SetCrashDescriptionWithFormat("Trying to fetch a summary for %s %s. Summary provider's description is %s",
+ GetTypeName().GetCString(),
+ GetName().GetCString(),
+ summary_ptr->GetDescription().c_str());*/
+
+ if (UpdateValueIfNeeded (false))
+ {
+ if (summary_ptr)
+ {
+ if (HasSyntheticValue())
+ m_synthetic_value->UpdateValueIfNeeded(); // the summary might depend on the synthetic children being up-to-date (e.g. ${svar%#})
+ summary_ptr->FormatObject(this, destination);
+ }
+ else
+ {
+ ClangASTType clang_type = GetClangType();
+
+ // Do some default printout for function pointers
+ if (clang_type)
+ {
+ if (clang_type.IsFunctionPointerType ())
+ {
+ StreamString sstr;
+ AddressType func_ptr_address_type = eAddressTypeInvalid;
+ addr_t func_ptr_address = GetPointerValue (&func_ptr_address_type);
+ if (func_ptr_address != 0 && func_ptr_address != LLDB_INVALID_ADDRESS)
+ {
+ switch (func_ptr_address_type)
+ {
+ case eAddressTypeInvalid:
+ case eAddressTypeFile:
+ break;
+
+ case eAddressTypeLoad:
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+
+ Address so_addr;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target && target->GetSectionLoadList().IsEmpty() == false)
+ {
+ if (target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address, so_addr))
+ {
+ so_addr.Dump (&sstr,
+ exe_ctx.GetBestExecutionContextScope(),
+ Address::DumpStyleResolvedDescription,
+ Address::DumpStyleSectionNameOffset);
+ }
+ }
+ }
+ break;
+
+ case eAddressTypeHost:
+ break;
+ }
+ }
+ if (sstr.GetSize() > 0)
+ {
+ destination.assign (1, '(');
+ destination.append (sstr.GetData(), sstr.GetSize());
+ destination.append (1, ')');
+ }
+ }
+ }
+ }
+ }
+ m_is_getting_summary = false;
+ return !destination.empty();
+}
+
+const char *
+ValueObject::GetSummaryAsCString ()
+{
+ if (UpdateValueIfNeeded(true) && m_summary_str.empty())
+ {
+ GetSummaryAsCString(GetSummaryFormat().get(),
+ m_summary_str);
+ }
+ if (m_summary_str.empty())
+ return NULL;
+ return m_summary_str.c_str();
+}
+
+bool
+ValueObject::IsCStringContainer(bool check_pointer)
+{
+ ClangASTType pointee_or_element_clang_type;
+ const Flags type_flags (GetTypeInfo (&pointee_or_element_clang_type));
+ bool is_char_arr_ptr (type_flags.AnySet (ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer) &&
+ pointee_or_element_clang_type.IsCharType ());
+ if (!is_char_arr_ptr)
+ return false;
+ if (!check_pointer)
+ return true;
+ if (type_flags.Test(ClangASTType::eTypeIsArray))
+ return true;
+ addr_t cstr_address = LLDB_INVALID_ADDRESS;
+ AddressType cstr_address_type = eAddressTypeInvalid;
+ cstr_address = GetAddressOf (true, &cstr_address_type);
+ return (cstr_address != LLDB_INVALID_ADDRESS);
+}
+
+size_t
+ValueObject::GetPointeeData (DataExtractor& data,
+ uint32_t item_idx,
+ uint32_t item_count)
+{
+ ClangASTType pointee_or_element_clang_type;
+ const uint32_t type_info = GetTypeInfo (&pointee_or_element_clang_type);
+ const bool is_pointer_type = type_info & ClangASTType::eTypeIsPointer;
+ const bool is_array_type = type_info & ClangASTType::eTypeIsArray;
+ if (!(is_pointer_type || is_array_type))
+ return 0;
+
+ if (item_count == 0)
+ return 0;
+
+ const uint64_t item_type_size = pointee_or_element_clang_type.GetByteSize();
+ const uint64_t bytes = item_count * item_type_size;
+ const uint64_t offset = item_idx * item_type_size;
+
+ if (item_idx == 0 && item_count == 1) // simply a deref
+ {
+ if (is_pointer_type)
+ {
+ Error error;
+ ValueObjectSP pointee_sp = Dereference(error);
+ if (error.Fail() || pointee_sp.get() == NULL)
+ return 0;
+ return pointee_sp->GetDataExtractor().Copy(data);
+ }
+ else
+ {
+ ValueObjectSP child_sp = GetChildAtIndex(0, true);
+ if (child_sp.get() == NULL)
+ return 0;
+ return child_sp->GetDataExtractor().Copy(data);
+ }
+ return true;
+ }
+ else /* (items > 1) */
+ {
+ Error error;
+ lldb_private::DataBufferHeap* heap_buf_ptr = NULL;
+ lldb::DataBufferSP data_sp(heap_buf_ptr = new lldb_private::DataBufferHeap());
+
+ AddressType addr_type;
+ lldb::addr_t addr = is_pointer_type ? GetPointerValue(&addr_type) : GetAddressOf(true, &addr_type);
+
+ switch (addr_type)
+ {
+ case eAddressTypeFile:
+ {
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ {
+ addr = addr + offset;
+ Address so_addr;
+ module_sp->ResolveFileAddress(addr, so_addr);
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Target* target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ heap_buf_ptr->SetByteSize(bytes);
+ size_t bytes_read = target->ReadMemory(so_addr, false, heap_buf_ptr->GetBytes(), bytes, error);
+ if (error.Success())
+ {
+ data.SetData(data_sp);
+ return bytes_read;
+ }
+ }
+ }
+ }
+ break;
+ case eAddressTypeLoad:
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ heap_buf_ptr->SetByteSize(bytes);
+ size_t bytes_read = process->ReadMemory(addr + offset, heap_buf_ptr->GetBytes(), bytes, error);
+ if (error.Success())
+ {
+ data.SetData(data_sp);
+ return bytes_read;
+ }
+ }
+ }
+ break;
+ case eAddressTypeHost:
+ {
+ const uint64_t max_bytes = GetClangType().GetByteSize();
+ if (max_bytes > offset)
+ {
+ size_t bytes_read = std::min<uint64_t>(max_bytes - offset, bytes);
+ heap_buf_ptr->CopyData((uint8_t*)(addr + offset), bytes_read);
+ data.SetData(data_sp);
+ return bytes_read;
+ }
+ }
+ break;
+ case eAddressTypeInvalid:
+ break;
+ }
+ }
+ return 0;
+}
+
+uint64_t
+ValueObject::GetData (DataExtractor& data)
+{
+ UpdateValueIfNeeded(false);
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Error error = m_value.GetValueAsData(&exe_ctx, data, 0, GetModule().get());
+ if (error.Fail())
+ {
+ if (m_data.GetByteSize())
+ {
+ data = m_data;
+ return data.GetByteSize();
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ data.SetAddressByteSize(m_data.GetAddressByteSize());
+ data.SetByteOrder(m_data.GetByteOrder());
+ return data.GetByteSize();
+}
+
+bool
+ValueObject::SetData (DataExtractor &data, Error &error)
+{
+ error.Clear();
+ // Make sure our value is up to date first so that our location and location
+ // type is valid.
+ if (!UpdateValueIfNeeded(false))
+ {
+ error.SetErrorString("unable to read value");
+ return false;
+ }
+
+ uint64_t count = 0;
+ const Encoding encoding = GetClangType().GetEncoding(count);
+
+ const size_t byte_size = GetByteSize();
+
+ Value::ValueType value_type = m_value.GetValueType();
+
+ switch (value_type)
+ {
+ case Value::eValueTypeScalar:
+ {
+ Error set_error = m_value.GetScalar().SetValueFromData(data, encoding, byte_size);
+
+ if (!set_error.Success())
+ {
+ error.SetErrorStringWithFormat("unable to set scalar value: %s", set_error.AsCString());
+ return false;
+ }
+ }
+ break;
+ case Value::eValueTypeLoadAddress:
+ {
+ // If it is a load address, then the scalar value is the storage location
+ // of the data, and we have to shove this value down to that load location.
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ addr_t target_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ size_t bytes_written = process->WriteMemory(target_addr,
+ data.GetDataStart(),
+ byte_size,
+ error);
+ if (!error.Success())
+ return false;
+ if (bytes_written != byte_size)
+ {
+ error.SetErrorString("unable to write value to memory");
+ return false;
+ }
+ }
+ }
+ break;
+ case Value::eValueTypeHostAddress:
+ {
+ // If it is a host address, then we stuff the scalar as a DataBuffer into the Value's data.
+ DataBufferSP buffer_sp (new DataBufferHeap(byte_size, 0));
+ m_data.SetData(buffer_sp, 0);
+ data.CopyByteOrderedData (0,
+ byte_size,
+ const_cast<uint8_t *>(m_data.GetDataStart()),
+ byte_size,
+ m_data.GetByteOrder());
+ m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
+ }
+ break;
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeVector:
+ break;
+ }
+
+ // If we have reached this point, then we have successfully changed the value.
+ SetNeedsUpdate();
+ return true;
+}
+
+// will compute strlen(str), but without consuming more than
+// maxlen bytes out of str (this serves the purpose of reading
+// chunks of a string without having to worry about
+// missing NULL terminators in the chunk)
+// of course, if strlen(str) > maxlen, the function will return
+// maxlen_value (which should be != maxlen, because that allows you
+// to know whether strlen(str) == maxlen or strlen(str) > maxlen)
+static uint32_t
+strlen_or_inf (const char* str,
+ uint32_t maxlen,
+ uint32_t maxlen_value)
+{
+ uint32_t len = 0;
+ if (str)
+ {
+ while(*str)
+ {
+ len++;str++;
+ if (len >= maxlen)
+ return maxlen_value;
+ }
+ }
+ return len;
+}
+
+size_t
+ValueObject::ReadPointedString (Stream& s,
+ Error& error,
+ uint32_t max_length,
+ bool honor_array,
+ Format item_format)
+{
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Target* target = exe_ctx.GetTargetPtr();
+
+ if (!target)
+ {
+ s << "<no target to read from>";
+ error.SetErrorString("no target to read from");
+ return 0;
+ }
+
+ if (max_length == 0)
+ max_length = target->GetMaximumSizeOfStringSummary();
+
+ size_t bytes_read = 0;
+ size_t total_bytes_read = 0;
+
+ ClangASTType clang_type = GetClangType();
+ ClangASTType elem_or_pointee_clang_type;
+ const Flags type_flags (GetTypeInfo (&elem_or_pointee_clang_type));
+ if (type_flags.AnySet (ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer) &&
+ elem_or_pointee_clang_type.IsCharType ())
+ {
+ addr_t cstr_address = LLDB_INVALID_ADDRESS;
+ AddressType cstr_address_type = eAddressTypeInvalid;
+
+ size_t cstr_len = 0;
+ bool capped_data = false;
+ if (type_flags.Test (ClangASTType::eTypeIsArray))
+ {
+ // We have an array
+ uint64_t array_size = 0;
+ if (clang_type.IsArrayType(NULL, &array_size, NULL))
+ {
+ cstr_len = array_size;
+ if (cstr_len > max_length)
+ {
+ capped_data = true;
+ cstr_len = max_length;
+ }
+ }
+ cstr_address = GetAddressOf (true, &cstr_address_type);
+ }
+ else
+ {
+ // We have a pointer
+ cstr_address = GetPointerValue (&cstr_address_type);
+ }
+
+ if (cstr_address == 0 || cstr_address == LLDB_INVALID_ADDRESS)
+ {
+ s << "<invalid address>";
+ error.SetErrorString("invalid address");
+ return 0;
+ }
+
+ Address cstr_so_addr (cstr_address);
+ DataExtractor data;
+ if (cstr_len > 0 && honor_array)
+ {
+ // I am using GetPointeeData() here to abstract the fact that some ValueObjects are actually frozen pointers in the host
+ // but the pointed-to data lives in the debuggee, and GetPointeeData() automatically takes care of this
+ GetPointeeData(data, 0, cstr_len);
+
+ if ((bytes_read = data.GetByteSize()) > 0)
+ {
+ total_bytes_read = bytes_read;
+ s << '"';
+ data.Dump (&s,
+ 0, // Start offset in "data"
+ item_format,
+ 1, // Size of item (1 byte for a char!)
+ bytes_read, // How many bytes to print?
+ UINT32_MAX, // num per line
+ LLDB_INVALID_ADDRESS,// base address
+ 0, // bitfield bit size
+ 0); // bitfield bit offset
+ if (capped_data)
+ s << "...";
+ s << '"';
+ }
+ }
+ else
+ {
+ cstr_len = max_length;
+ const size_t k_max_buf_size = 64;
+
+ size_t offset = 0;
+
+ int cstr_len_displayed = -1;
+ bool capped_cstr = false;
+ // I am using GetPointeeData() here to abstract the fact that some ValueObjects are actually frozen pointers in the host
+ // but the pointed-to data lives in the debuggee, and GetPointeeData() automatically takes care of this
+ while ((bytes_read = GetPointeeData(data, offset, k_max_buf_size)) > 0)
+ {
+ total_bytes_read += bytes_read;
+ const char *cstr = data.PeekCStr(0);
+ size_t len = strlen_or_inf (cstr, k_max_buf_size, k_max_buf_size+1);
+ if (len > k_max_buf_size)
+ len = k_max_buf_size;
+ if (cstr && cstr_len_displayed < 0)
+ s << '"';
+
+ if (cstr_len_displayed < 0)
+ cstr_len_displayed = len;
+
+ if (len == 0)
+ break;
+ cstr_len_displayed += len;
+ if (len > bytes_read)
+ len = bytes_read;
+ if (len > cstr_len)
+ len = cstr_len;
+
+ data.Dump (&s,
+ 0, // Start offset in "data"
+ item_format,
+ 1, // Size of item (1 byte for a char!)
+ len, // How many bytes to print?
+ UINT32_MAX, // num per line
+ LLDB_INVALID_ADDRESS,// base address
+ 0, // bitfield bit size
+ 0); // bitfield bit offset
+
+ if (len < k_max_buf_size)
+ break;
+
+ if (len >= cstr_len)
+ {
+ capped_cstr = true;
+ break;
+ }
+
+ cstr_len -= len;
+ offset += len;
+ }
+
+ if (cstr_len_displayed >= 0)
+ {
+ s << '"';
+ if (capped_cstr)
+ s << "...";
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("not a string object");
+ s << "<not a string object>";
+ }
+ return total_bytes_read;
+}
+
+const char *
+ValueObject::GetObjectDescription ()
+{
+
+ if (!UpdateValueIfNeeded (true))
+ return NULL;
+
+ if (!m_object_desc_str.empty())
+ return m_object_desc_str.c_str();
+
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ return NULL;
+
+ StreamString s;
+
+ LanguageType language = GetObjectRuntimeLanguage();
+ LanguageRuntime *runtime = process->GetLanguageRuntime(language);
+
+ if (runtime == NULL)
+ {
+ // Aw, hell, if the things a pointer, or even just an integer, let's try ObjC anyway...
+ ClangASTType clang_type = GetClangType();
+ if (clang_type)
+ {
+ bool is_signed;
+ if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType ())
+ {
+ runtime = process->GetLanguageRuntime(eLanguageTypeObjC);
+ }
+ }
+ }
+
+ if (runtime && runtime->GetObjectDescription(s, *this))
+ {
+ m_object_desc_str.append (s.GetData());
+ }
+
+ if (m_object_desc_str.empty())
+ return NULL;
+ else
+ return m_object_desc_str.c_str();
+}
+
+bool
+ValueObject::GetValueAsCString (lldb::Format format,
+ std::string& destination)
+{
+ if (GetClangType().IsAggregateType () == false && UpdateValueIfNeeded(false))
+ {
+ const Value::ContextType context_type = m_value.GetContextType();
+
+ if (context_type == Value::eContextTypeRegisterInfo)
+ {
+ const RegisterInfo *reg_info = m_value.GetRegisterInfo();
+ if (reg_info)
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+
+ StreamString reg_sstr;
+ m_data.Dump (&reg_sstr,
+ 0,
+ format,
+ reg_info->byte_size,
+ 1,
+ UINT32_MAX,
+ LLDB_INVALID_ADDRESS,
+ 0,
+ 0,
+ exe_ctx.GetBestExecutionContextScope());
+ destination.swap(reg_sstr.GetString());
+ }
+ }
+ else
+ {
+ ClangASTType clang_type = GetClangType ();
+ if (clang_type)
+ {
+ // put custom bytes to display in this DataExtractor to override the default value logic
+ lldb_private::DataExtractor special_format_data;
+ if (format == eFormatCString)
+ {
+ Flags type_flags(clang_type.GetTypeInfo(NULL));
+ if (type_flags.Test(ClangASTType::eTypeIsPointer) && !type_flags.Test(ClangASTType::eTypeIsObjC))
+ {
+ // if we are dumping a pointer as a c-string, get the pointee data as a string
+ TargetSP target_sp(GetTargetSP());
+ if (target_sp)
+ {
+ size_t max_len = target_sp->GetMaximumSizeOfStringSummary();
+ Error error;
+ DataBufferSP buffer_sp(new DataBufferHeap(max_len+1,0));
+ Address address(GetPointerValue());
+ if (target_sp->ReadCStringFromMemory(address, (char*)buffer_sp->GetBytes(), max_len, error) && error.Success())
+ special_format_data.SetData(buffer_sp);
+ }
+ }
+ }
+
+ StreamString sstr;
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ clang_type.DumpTypeValue (&sstr, // The stream to use for display
+ format, // Format to display this type with
+ special_format_data.GetByteSize() ?
+ special_format_data: m_data, // Data to extract from
+ 0, // Byte offset into "m_data"
+ GetByteSize(), // Byte size of item in "m_data"
+ GetBitfieldBitSize(), // Bitfield bit size
+ GetBitfieldBitOffset(), // Bitfield bit offset
+ exe_ctx.GetBestExecutionContextScope());
+ // Don't set the m_error to anything here otherwise
+ // we won't be able to re-format as anything else. The
+ // code for ClangASTType::DumpTypeValue() should always
+ // return something, even if that something contains
+ // an error messsage. "m_error" is used to detect errors
+ // when reading the valid object, not for formatting errors.
+ if (sstr.GetString().empty())
+ destination.clear();
+ else
+ destination.swap(sstr.GetString());
+ }
+ }
+ return !destination.empty();
+ }
+ else
+ return false;
+}
+
+const char *
+ValueObject::GetValueAsCString ()
+{
+ if (UpdateValueIfNeeded(true))
+ {
+ lldb::Format my_format = GetFormat();
+ if (my_format == lldb::eFormatDefault)
+ {
+ if (m_type_format_sp)
+ my_format = m_type_format_sp->GetFormat();
+ else
+ {
+ if (m_is_bitfield_for_scalar)
+ my_format = eFormatUnsigned;
+ else
+ {
+ if (m_value.GetContextType() == Value::eContextTypeRegisterInfo)
+ {
+ const RegisterInfo *reg_info = m_value.GetRegisterInfo();
+ if (reg_info)
+ my_format = reg_info->format;
+ }
+ else
+ {
+ my_format = GetClangType().GetFormat();
+ }
+ }
+ }
+ }
+ if (my_format != m_last_format || m_value_str.empty())
+ {
+ m_last_format = my_format;
+ if (GetValueAsCString(my_format, m_value_str))
+ {
+ if (!m_value_did_change && m_old_value_valid)
+ {
+ // The value was gotten successfully, so we consider the
+ // value as changed if the value string differs
+ SetValueDidChange (m_old_value_str != m_value_str);
+ }
+ }
+ }
+ }
+ if (m_value_str.empty())
+ return NULL;
+ return m_value_str.c_str();
+}
+
+// if > 8bytes, 0 is returned. this method should mostly be used
+// to read address values out of pointers
+uint64_t
+ValueObject::GetValueAsUnsigned (uint64_t fail_value, bool *success)
+{
+ // If our byte size is zero this is an aggregate type that has children
+ if (!GetClangType().IsAggregateType())
+ {
+ Scalar scalar;
+ if (ResolveValue (scalar))
+ {
+ if (success)
+ *success = true;
+ return scalar.ULongLong(fail_value);
+ }
+ // fallthrough, otherwise...
+ }
+
+ if (success)
+ *success = false;
+ return fail_value;
+}
+
+// if any more "special cases" are added to ValueObject::DumpPrintableRepresentation() please keep
+// this call up to date by returning true for your new special cases. We will eventually move
+// to checking this call result before trying to display special cases
+bool
+ValueObject::HasSpecialPrintableRepresentation(ValueObjectRepresentationStyle val_obj_display,
+ Format custom_format)
+{
+ Flags flags(GetTypeInfo());
+ if (flags.AnySet(ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer)
+ && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue)
+ {
+ if (IsCStringContainer(true) &&
+ (custom_format == eFormatCString ||
+ custom_format == eFormatCharArray ||
+ custom_format == eFormatChar ||
+ custom_format == eFormatVectorOfChar))
+ return true;
+
+ if (flags.Test(ClangASTType::eTypeIsArray))
+ {
+ if ((custom_format == eFormatBytes) ||
+ (custom_format == eFormatBytesWithASCII))
+ return true;
+
+ if ((custom_format == eFormatVectorOfChar) ||
+ (custom_format == eFormatVectorOfFloat32) ||
+ (custom_format == eFormatVectorOfFloat64) ||
+ (custom_format == eFormatVectorOfSInt16) ||
+ (custom_format == eFormatVectorOfSInt32) ||
+ (custom_format == eFormatVectorOfSInt64) ||
+ (custom_format == eFormatVectorOfSInt8) ||
+ (custom_format == eFormatVectorOfUInt128) ||
+ (custom_format == eFormatVectorOfUInt16) ||
+ (custom_format == eFormatVectorOfUInt32) ||
+ (custom_format == eFormatVectorOfUInt64) ||
+ (custom_format == eFormatVectorOfUInt8))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+ValueObject::DumpPrintableRepresentation(Stream& s,
+ ValueObjectRepresentationStyle val_obj_display,
+ Format custom_format,
+ PrintableRepresentationSpecialCases special)
+{
+
+ Flags flags(GetTypeInfo());
+
+ bool allow_special = ((special & ePrintableRepresentationSpecialCasesAllow) == ePrintableRepresentationSpecialCasesAllow);
+ bool only_special = ((special & ePrintableRepresentationSpecialCasesOnly) == ePrintableRepresentationSpecialCasesOnly);
+
+ if (allow_special)
+ {
+ if (flags.AnySet(ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer)
+ && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue)
+ {
+ // when being asked to get a printable display an array or pointer type directly,
+ // try to "do the right thing"
+
+ if (IsCStringContainer(true) &&
+ (custom_format == eFormatCString ||
+ custom_format == eFormatCharArray ||
+ custom_format == eFormatChar ||
+ custom_format == eFormatVectorOfChar)) // print char[] & char* directly
+ {
+ Error error;
+ ReadPointedString(s,
+ error,
+ 0,
+ (custom_format == eFormatVectorOfChar) ||
+ (custom_format == eFormatCharArray));
+ return !error.Fail();
+ }
+
+ if (custom_format == eFormatEnum)
+ return false;
+
+ // this only works for arrays, because I have no way to know when
+ // the pointed memory ends, and no special \0 end of data marker
+ if (flags.Test(ClangASTType::eTypeIsArray))
+ {
+ if ((custom_format == eFormatBytes) ||
+ (custom_format == eFormatBytesWithASCII))
+ {
+ const size_t count = GetNumChildren();
+
+ s << '[';
+ for (size_t low = 0; low < count; low++)
+ {
+
+ if (low)
+ s << ',';
+
+ ValueObjectSP child = GetChildAtIndex(low,true);
+ if (!child.get())
+ {
+ s << "<invalid child>";
+ continue;
+ }
+ child->DumpPrintableRepresentation(s, ValueObject::eValueObjectRepresentationStyleValue, custom_format);
+ }
+
+ s << ']';
+
+ return true;
+ }
+
+ if ((custom_format == eFormatVectorOfChar) ||
+ (custom_format == eFormatVectorOfFloat32) ||
+ (custom_format == eFormatVectorOfFloat64) ||
+ (custom_format == eFormatVectorOfSInt16) ||
+ (custom_format == eFormatVectorOfSInt32) ||
+ (custom_format == eFormatVectorOfSInt64) ||
+ (custom_format == eFormatVectorOfSInt8) ||
+ (custom_format == eFormatVectorOfUInt128) ||
+ (custom_format == eFormatVectorOfUInt16) ||
+ (custom_format == eFormatVectorOfUInt32) ||
+ (custom_format == eFormatVectorOfUInt64) ||
+ (custom_format == eFormatVectorOfUInt8)) // arrays of bytes, bytes with ASCII or any vector format should be printed directly
+ {
+ const size_t count = GetNumChildren();
+
+ Format format = FormatManager::GetSingleItemFormat(custom_format);
+
+ s << '[';
+ for (size_t low = 0; low < count; low++)
+ {
+
+ if (low)
+ s << ',';
+
+ ValueObjectSP child = GetChildAtIndex(low,true);
+ if (!child.get())
+ {
+ s << "<invalid child>";
+ continue;
+ }
+ child->DumpPrintableRepresentation(s, ValueObject::eValueObjectRepresentationStyleValue, format);
+ }
+
+ s << ']';
+
+ return true;
+ }
+ }
+
+ if ((custom_format == eFormatBoolean) ||
+ (custom_format == eFormatBinary) ||
+ (custom_format == eFormatChar) ||
+ (custom_format == eFormatCharPrintable) ||
+ (custom_format == eFormatComplexFloat) ||
+ (custom_format == eFormatDecimal) ||
+ (custom_format == eFormatHex) ||
+ (custom_format == eFormatHexUppercase) ||
+ (custom_format == eFormatFloat) ||
+ (custom_format == eFormatOctal) ||
+ (custom_format == eFormatOSType) ||
+ (custom_format == eFormatUnicode16) ||
+ (custom_format == eFormatUnicode32) ||
+ (custom_format == eFormatUnsigned) ||
+ (custom_format == eFormatPointer) ||
+ (custom_format == eFormatComplexInteger) ||
+ (custom_format == eFormatComplex) ||
+ (custom_format == eFormatDefault)) // use the [] operator
+ return false;
+ }
+ }
+
+ if (only_special)
+ return false;
+
+ bool var_success = false;
+
+ {
+ const char *cstr = NULL;
+
+ // this is a local stream that we are using to ensure that the data pointed to by cstr survives
+ // long enough for us to copy it to its destination - it is necessary to have this temporary storage
+ // area for cases where our desired output is not backed by some other longer-term storage
+ StreamString strm;
+
+ if (custom_format != eFormatInvalid)
+ SetFormat(custom_format);
+
+ switch(val_obj_display)
+ {
+ case eValueObjectRepresentationStyleValue:
+ cstr = GetValueAsCString();
+ break;
+
+ case eValueObjectRepresentationStyleSummary:
+ cstr = GetSummaryAsCString();
+ break;
+
+ case eValueObjectRepresentationStyleLanguageSpecific:
+ cstr = GetObjectDescription();
+ break;
+
+ case eValueObjectRepresentationStyleLocation:
+ cstr = GetLocationAsCString();
+ break;
+
+ case eValueObjectRepresentationStyleChildrenCount:
+ strm.Printf("%zu", GetNumChildren());
+ cstr = strm.GetString().c_str();
+ break;
+
+ case eValueObjectRepresentationStyleType:
+ cstr = GetTypeName().AsCString();
+ break;
+
+ case eValueObjectRepresentationStyleName:
+ cstr = GetName().AsCString();
+ break;
+
+ case eValueObjectRepresentationStyleExpressionPath:
+ GetExpressionPath(strm, false);
+ cstr = strm.GetString().c_str();
+ break;
+ }
+
+ if (!cstr)
+ {
+ if (val_obj_display == eValueObjectRepresentationStyleValue)
+ cstr = GetSummaryAsCString();
+ else if (val_obj_display == eValueObjectRepresentationStyleSummary)
+ {
+ if (GetClangType().IsAggregateType())
+ {
+ strm.Printf("%s @ %s", GetTypeName().AsCString(), GetLocationAsCString());
+ cstr = strm.GetString().c_str();
+ }
+ else
+ cstr = GetValueAsCString();
+ }
+ }
+
+ if (cstr)
+ s.PutCString(cstr);
+ else
+ {
+ if (m_error.Fail())
+ s.Printf("<%s>", m_error.AsCString());
+ else if (val_obj_display == eValueObjectRepresentationStyleSummary)
+ s.PutCString("<no summary available>");
+ else if (val_obj_display == eValueObjectRepresentationStyleValue)
+ s.PutCString("<no value available>");
+ else if (val_obj_display == eValueObjectRepresentationStyleLanguageSpecific)
+ s.PutCString("<not a valid Objective-C object>"); // edit this if we have other runtimes that support a description
+ else
+ s.PutCString("<no printable representation>");
+ }
+
+ // we should only return false here if we could not do *anything*
+ // even if we have an error message as output, that's a success
+ // from our callers' perspective, so return true
+ var_success = true;
+
+ if (custom_format != eFormatInvalid)
+ SetFormat(eFormatDefault);
+ }
+
+ return var_success;
+}
+
+addr_t
+ValueObject::GetAddressOf (bool scalar_is_load_address, AddressType *address_type)
+{
+ if (!UpdateValueIfNeeded(false))
+ return LLDB_INVALID_ADDRESS;
+
+ switch (m_value.GetValueType())
+ {
+ case Value::eValueTypeScalar:
+ case Value::eValueTypeVector:
+ if (scalar_is_load_address)
+ {
+ if(address_type)
+ *address_type = eAddressTypeLoad;
+ return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ }
+ break;
+
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeHostAddress:
+ {
+ if(address_type)
+ *address_type = m_value.GetValueAddressType ();
+ return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ }
+ break;
+ }
+ if (address_type)
+ *address_type = eAddressTypeInvalid;
+ return LLDB_INVALID_ADDRESS;
+}
+
+addr_t
+ValueObject::GetPointerValue (AddressType *address_type)
+{
+ addr_t address = LLDB_INVALID_ADDRESS;
+ if(address_type)
+ *address_type = eAddressTypeInvalid;
+
+ if (!UpdateValueIfNeeded(false))
+ return address;
+
+ switch (m_value.GetValueType())
+ {
+ case Value::eValueTypeScalar:
+ case Value::eValueTypeVector:
+ address = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ break;
+
+ case Value::eValueTypeHostAddress:
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeFileAddress:
+ {
+ lldb::offset_t data_offset = 0;
+ address = m_data.GetPointer(&data_offset);
+ }
+ break;
+ }
+
+ if (address_type)
+ *address_type = GetAddressTypeOfChildren();
+
+ return address;
+}
+
+bool
+ValueObject::SetValueFromCString (const char *value_str, Error& error)
+{
+ error.Clear();
+ // Make sure our value is up to date first so that our location and location
+ // type is valid.
+ if (!UpdateValueIfNeeded(false))
+ {
+ error.SetErrorString("unable to read value");
+ return false;
+ }
+
+ uint64_t count = 0;
+ const Encoding encoding = GetClangType().GetEncoding (count);
+
+ const size_t byte_size = GetByteSize();
+
+ Value::ValueType value_type = m_value.GetValueType();
+
+ if (value_type == Value::eValueTypeScalar)
+ {
+ // If the value is already a scalar, then let the scalar change itself:
+ m_value.GetScalar().SetValueFromCString (value_str, encoding, byte_size);
+ }
+ else if (byte_size <= Scalar::GetMaxByteSize())
+ {
+ // If the value fits in a scalar, then make a new scalar and again let the
+ // scalar code do the conversion, then figure out where to put the new value.
+ Scalar new_scalar;
+ error = new_scalar.SetValueFromCString (value_str, encoding, byte_size);
+ if (error.Success())
+ {
+ switch (value_type)
+ {
+ case Value::eValueTypeLoadAddress:
+ {
+ // If it is a load address, then the scalar value is the storage location
+ // of the data, and we have to shove this value down to that load location.
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ addr_t target_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ size_t bytes_written = process->WriteScalarToMemory (target_addr,
+ new_scalar,
+ byte_size,
+ error);
+ if (!error.Success())
+ return false;
+ if (bytes_written != byte_size)
+ {
+ error.SetErrorString("unable to write value to memory");
+ return false;
+ }
+ }
+ }
+ break;
+ case Value::eValueTypeHostAddress:
+ {
+ // If it is a host address, then we stuff the scalar as a DataBuffer into the Value's data.
+ DataExtractor new_data;
+ new_data.SetByteOrder (m_data.GetByteOrder());
+
+ DataBufferSP buffer_sp (new DataBufferHeap(byte_size, 0));
+ m_data.SetData(buffer_sp, 0);
+ bool success = new_scalar.GetData(new_data);
+ if (success)
+ {
+ new_data.CopyByteOrderedData (0,
+ byte_size,
+ const_cast<uint8_t *>(m_data.GetDataStart()),
+ byte_size,
+ m_data.GetByteOrder());
+ }
+ m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
+
+ }
+ break;
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeScalar:
+ case Value::eValueTypeVector:
+ break;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // We don't support setting things bigger than a scalar at present.
+ error.SetErrorString("unable to write aggregate data type");
+ return false;
+ }
+
+ // If we have reached this point, then we have successfully changed the value.
+ SetNeedsUpdate();
+ return true;
+}
+
+bool
+ValueObject::GetDeclaration (Declaration &decl)
+{
+ decl.Clear();
+ return false;
+}
+
+ConstString
+ValueObject::GetTypeName()
+{
+ return GetClangType().GetConstTypeName();
+}
+
+ConstString
+ValueObject::GetQualifiedTypeName()
+{
+ return GetClangType().GetConstQualifiedTypeName();
+}
+
+
+LanguageType
+ValueObject::GetObjectRuntimeLanguage ()
+{
+ return GetClangType().GetMinimumLanguage ();
+}
+
+void
+ValueObject::AddSyntheticChild (const ConstString &key, ValueObject *valobj)
+{
+ m_synthetic_children[key] = valobj;
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticChild (const ConstString &key) const
+{
+ ValueObjectSP synthetic_child_sp;
+ std::map<ConstString, ValueObject *>::const_iterator pos = m_synthetic_children.find (key);
+ if (pos != m_synthetic_children.end())
+ synthetic_child_sp = pos->second->GetSP();
+ return synthetic_child_sp;
+}
+
+uint32_t
+ValueObject::GetTypeInfo (ClangASTType *pointee_or_element_clang_type)
+{
+ return GetClangType().GetTypeInfo (pointee_or_element_clang_type);
+}
+
+bool
+ValueObject::IsPointerType ()
+{
+ return GetClangType().IsPointerType();
+}
+
+bool
+ValueObject::IsArrayType ()
+{
+ return GetClangType().IsArrayType (NULL, NULL, NULL);
+}
+
+bool
+ValueObject::IsScalarType ()
+{
+ return GetClangType().IsScalarType ();
+}
+
+bool
+ValueObject::IsIntegerType (bool &is_signed)
+{
+ return GetClangType().IsIntegerType (is_signed);
+}
+
+bool
+ValueObject::IsPointerOrReferenceType ()
+{
+ return GetClangType().IsPointerOrReferenceType ();
+}
+
+bool
+ValueObject::IsPossibleDynamicType ()
+{
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ return process->IsPossibleDynamicValue(*this);
+ else
+ return GetClangType().IsPossibleDynamicType (NULL, true, true);
+}
+
+bool
+ValueObject::IsObjCNil ()
+{
+ const uint32_t mask = ClangASTType::eTypeIsObjC | ClangASTType::eTypeIsPointer;
+ bool isObjCpointer = (((GetClangType().GetTypeInfo(NULL)) & mask) == mask);
+ if (!isObjCpointer)
+ return false;
+ bool canReadValue = true;
+ bool isZero = GetValueAsUnsigned(0,&canReadValue) == 0;
+ return canReadValue && isZero;
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticArrayMember (size_t index, bool can_create)
+{
+ const uint32_t type_info = GetTypeInfo ();
+ if (type_info & ClangASTType::eTypeIsArray)
+ return GetSyntheticArrayMemberFromArray(index, can_create);
+
+ if (type_info & ClangASTType::eTypeIsPointer)
+ return GetSyntheticArrayMemberFromPointer(index, can_create);
+
+ return ValueObjectSP();
+
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticArrayMemberFromPointer (size_t index, bool can_create)
+{
+ ValueObjectSP synthetic_child_sp;
+ if (IsPointerType ())
+ {
+ char index_str[64];
+ snprintf(index_str, sizeof(index_str), "[%zu]", index);
+ ConstString index_const_str(index_str);
+ // Check if we have already created a synthetic array member in this
+ // valid object. If we have we will re-use it.
+ synthetic_child_sp = GetSyntheticChild (index_const_str);
+ if (!synthetic_child_sp)
+ {
+ ValueObject *synthetic_child;
+ // We haven't made a synthetic array member for INDEX yet, so
+ // lets make one and cache it for any future reference.
+ synthetic_child = CreateChildAtIndex(0, true, index);
+
+ // Cache the value if we got one back...
+ if (synthetic_child)
+ {
+ AddSyntheticChild(index_const_str, synthetic_child);
+ synthetic_child_sp = synthetic_child->GetSP();
+ synthetic_child_sp->SetName(ConstString(index_str));
+ synthetic_child_sp->m_is_array_item_for_pointer = true;
+ }
+ }
+ }
+ return synthetic_child_sp;
+}
+
+// This allows you to create an array member using and index
+// that doesn't not fall in the normal bounds of the array.
+// Many times structure can be defined as:
+// struct Collection
+// {
+// uint32_t item_count;
+// Item item_array[0];
+// };
+// The size of the "item_array" is 1, but many times in practice
+// there are more items in "item_array".
+
+ValueObjectSP
+ValueObject::GetSyntheticArrayMemberFromArray (size_t index, bool can_create)
+{
+ ValueObjectSP synthetic_child_sp;
+ if (IsArrayType ())
+ {
+ char index_str[64];
+ snprintf(index_str, sizeof(index_str), "[%zu]", index);
+ ConstString index_const_str(index_str);
+ // Check if we have already created a synthetic array member in this
+ // valid object. If we have we will re-use it.
+ synthetic_child_sp = GetSyntheticChild (index_const_str);
+ if (!synthetic_child_sp)
+ {
+ ValueObject *synthetic_child;
+ // We haven't made a synthetic array member for INDEX yet, so
+ // lets make one and cache it for any future reference.
+ synthetic_child = CreateChildAtIndex(0, true, index);
+
+ // Cache the value if we got one back...
+ if (synthetic_child)
+ {
+ AddSyntheticChild(index_const_str, synthetic_child);
+ synthetic_child_sp = synthetic_child->GetSP();
+ synthetic_child_sp->SetName(ConstString(index_str));
+ synthetic_child_sp->m_is_array_item_for_pointer = true;
+ }
+ }
+ }
+ return synthetic_child_sp;
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticBitFieldChild (uint32_t from, uint32_t to, bool can_create)
+{
+ ValueObjectSP synthetic_child_sp;
+ if (IsScalarType ())
+ {
+ char index_str[64];
+ snprintf(index_str, sizeof(index_str), "[%i-%i]", from, to);
+ ConstString index_const_str(index_str);
+ // Check if we have already created a synthetic array member in this
+ // valid object. If we have we will re-use it.
+ synthetic_child_sp = GetSyntheticChild (index_const_str);
+ if (!synthetic_child_sp)
+ {
+ // We haven't made a synthetic array member for INDEX yet, so
+ // lets make one and cache it for any future reference.
+ ValueObjectChild *synthetic_child = new ValueObjectChild (*this,
+ GetClangType(),
+ index_const_str,
+ GetByteSize(),
+ 0,
+ to-from+1,
+ from,
+ false,
+ false,
+ eAddressTypeInvalid);
+
+ // Cache the value if we got one back...
+ if (synthetic_child)
+ {
+ AddSyntheticChild(index_const_str, synthetic_child);
+ synthetic_child_sp = synthetic_child->GetSP();
+ synthetic_child_sp->SetName(ConstString(index_str));
+ synthetic_child_sp->m_is_bitfield_for_scalar = true;
+ }
+ }
+ }
+ return synthetic_child_sp;
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type, bool can_create)
+{
+
+ ValueObjectSP synthetic_child_sp;
+
+ char name_str[64];
+ snprintf(name_str, sizeof(name_str), "@%i", offset);
+ ConstString name_const_str(name_str);
+
+ // Check if we have already created a synthetic array member in this
+ // valid object. If we have we will re-use it.
+ synthetic_child_sp = GetSyntheticChild (name_const_str);
+
+ if (synthetic_child_sp.get())
+ return synthetic_child_sp;
+
+ if (!can_create)
+ return ValueObjectSP();
+
+ ValueObjectChild *synthetic_child = new ValueObjectChild(*this,
+ type,
+ name_const_str,
+ type.GetByteSize(),
+ offset,
+ 0,
+ 0,
+ false,
+ false,
+ eAddressTypeInvalid);
+ if (synthetic_child)
+ {
+ AddSyntheticChild(name_const_str, synthetic_child);
+ synthetic_child_sp = synthetic_child->GetSP();
+ synthetic_child_sp->SetName(name_const_str);
+ synthetic_child_sp->m_is_child_at_offset = true;
+ }
+ return synthetic_child_sp;
+}
+
+// your expression path needs to have a leading . or ->
+// (unless it somehow "looks like" an array, in which case it has
+// a leading [ symbol). while the [ is meaningful and should be shown
+// to the user, . and -> are just parser design, but by no means
+// added information for the user.. strip them off
+static const char*
+SkipLeadingExpressionPathSeparators(const char* expression)
+{
+ if (!expression || !expression[0])
+ return expression;
+ if (expression[0] == '.')
+ return expression+1;
+ if (expression[0] == '-' && expression[1] == '>')
+ return expression+2;
+ return expression;
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticExpressionPathChild(const char* expression, bool can_create)
+{
+ ValueObjectSP synthetic_child_sp;
+ ConstString name_const_string(expression);
+ // Check if we have already created a synthetic array member in this
+ // valid object. If we have we will re-use it.
+ synthetic_child_sp = GetSyntheticChild (name_const_string);
+ if (!synthetic_child_sp)
+ {
+ // We haven't made a synthetic array member for expression yet, so
+ // lets make one and cache it for any future reference.
+ synthetic_child_sp = GetValueForExpressionPath(expression,
+ NULL, NULL, NULL,
+ GetValueForExpressionPathOptions().DontAllowSyntheticChildren());
+
+ // Cache the value if we got one back...
+ if (synthetic_child_sp.get())
+ {
+ // FIXME: this causes a "real" child to end up with its name changed to the contents of expression
+ AddSyntheticChild(name_const_string, synthetic_child_sp.get());
+ synthetic_child_sp->SetName(ConstString(SkipLeadingExpressionPathSeparators(expression)));
+ }
+ }
+ return synthetic_child_sp;
+}
+
+void
+ValueObject::CalculateSyntheticValue (bool use_synthetic)
+{
+ if (use_synthetic == false)
+ return;
+
+ TargetSP target_sp(GetTargetSP());
+ if (target_sp && (target_sp->GetEnableSyntheticValue() == false || target_sp->GetSuppressSyntheticValue() == true))
+ {
+ m_synthetic_value = NULL;
+ return;
+ }
+
+ lldb::SyntheticChildrenSP current_synth_sp(m_synthetic_children_sp);
+
+ if (!UpdateFormatsIfNeeded() && m_synthetic_value)
+ return;
+
+ if (m_synthetic_children_sp.get() == NULL)
+ return;
+
+ if (current_synth_sp == m_synthetic_children_sp && m_synthetic_value)
+ return;
+
+ m_synthetic_value = new ValueObjectSynthetic(*this, m_synthetic_children_sp);
+}
+
+void
+ValueObject::CalculateDynamicValue (DynamicValueType use_dynamic)
+{
+ if (use_dynamic == eNoDynamicValues)
+ return;
+
+ if (!m_dynamic_value && !IsDynamic())
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process && process->IsPossibleDynamicValue(*this))
+ {
+ ClearDynamicTypeInformation ();
+ m_dynamic_value = new ValueObjectDynamicValue (*this, use_dynamic);
+ }
+ }
+}
+
+ValueObjectSP
+ValueObject::GetDynamicValue (DynamicValueType use_dynamic)
+{
+ if (use_dynamic == eNoDynamicValues)
+ return ValueObjectSP();
+
+ if (!IsDynamic() && m_dynamic_value == NULL)
+ {
+ CalculateDynamicValue(use_dynamic);
+ }
+ if (m_dynamic_value)
+ return m_dynamic_value->GetSP();
+ else
+ return ValueObjectSP();
+}
+
+ValueObjectSP
+ValueObject::GetStaticValue()
+{
+ return GetSP();
+}
+
+lldb::ValueObjectSP
+ValueObject::GetNonSyntheticValue ()
+{
+ return GetSP();
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticValue (bool use_synthetic)
+{
+ if (use_synthetic == false)
+ return ValueObjectSP();
+
+ CalculateSyntheticValue(use_synthetic);
+
+ if (m_synthetic_value)
+ return m_synthetic_value->GetSP();
+ else
+ return ValueObjectSP();
+}
+
+bool
+ValueObject::HasSyntheticValue()
+{
+ UpdateFormatsIfNeeded();
+
+ if (m_synthetic_children_sp.get() == NULL)
+ return false;
+
+ CalculateSyntheticValue(true);
+
+ if (m_synthetic_value)
+ return true;
+ else
+ return false;
+}
+
+bool
+ValueObject::GetBaseClassPath (Stream &s)
+{
+ if (IsBaseClass())
+ {
+ bool parent_had_base_class = GetParent() && GetParent()->GetBaseClassPath (s);
+ ClangASTType clang_type = GetClangType();
+ std::string cxx_class_name;
+ bool this_had_base_class = clang_type.GetCXXClassName (cxx_class_name);
+ if (this_had_base_class)
+ {
+ if (parent_had_base_class)
+ s.PutCString("::");
+ s.PutCString(cxx_class_name.c_str());
+ }
+ return parent_had_base_class || this_had_base_class;
+ }
+ return false;
+}
+
+
+ValueObject *
+ValueObject::GetNonBaseClassParent()
+{
+ if (GetParent())
+ {
+ if (GetParent()->IsBaseClass())
+ return GetParent()->GetNonBaseClassParent();
+ else
+ return GetParent();
+ }
+ return NULL;
+}
+
+void
+ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat epformat)
+{
+ const bool is_deref_of_parent = IsDereferenceOfParent ();
+
+ if (is_deref_of_parent && epformat == eGetExpressionPathFormatDereferencePointers)
+ {
+ // this is the original format of GetExpressionPath() producing code like *(a_ptr).memberName, which is entirely
+ // fine, until you put this into StackFrame::GetValueForVariableExpressionPath() which prefers to see a_ptr->memberName.
+ // the eHonorPointers mode is meant to produce strings in this latter format
+ s.PutCString("*(");
+ }
+
+ ValueObject* parent = GetParent();
+
+ if (parent)
+ parent->GetExpressionPath (s, qualify_cxx_base_classes, epformat);
+
+ // if we are a deref_of_parent just because we are synthetic array
+ // members made up to allow ptr[%d] syntax to work in variable
+ // printing, then add our name ([%d]) to the expression path
+ if (m_is_array_item_for_pointer && epformat == eGetExpressionPathFormatHonorPointers)
+ s.PutCString(m_name.AsCString());
+
+ if (!IsBaseClass())
+ {
+ if (!is_deref_of_parent)
+ {
+ ValueObject *non_base_class_parent = GetNonBaseClassParent();
+ if (non_base_class_parent)
+ {
+ ClangASTType non_base_class_parent_clang_type = non_base_class_parent->GetClangType();
+ if (non_base_class_parent_clang_type)
+ {
+ if (parent && parent->IsDereferenceOfParent() && epformat == eGetExpressionPathFormatHonorPointers)
+ {
+ s.PutCString("->");
+ }
+ else
+ {
+ const uint32_t non_base_class_parent_type_info = non_base_class_parent_clang_type.GetTypeInfo();
+
+ if (non_base_class_parent_type_info & ClangASTType::eTypeIsPointer)
+ {
+ s.PutCString("->");
+ }
+ else if ((non_base_class_parent_type_info & ClangASTType::eTypeHasChildren) &&
+ !(non_base_class_parent_type_info & ClangASTType::eTypeIsArray))
+ {
+ s.PutChar('.');
+ }
+ }
+ }
+ }
+
+ const char *name = GetName().GetCString();
+ if (name)
+ {
+ if (qualify_cxx_base_classes)
+ {
+ if (GetBaseClassPath (s))
+ s.PutCString("::");
+ }
+ s.PutCString(name);
+ }
+ }
+ }
+
+ if (is_deref_of_parent && epformat == eGetExpressionPathFormatDereferencePointers)
+ {
+ s.PutChar(')');
+ }
+}
+
+ValueObjectSP
+ValueObject::GetValueForExpressionPath(const char* expression,
+ const char** first_unparsed,
+ ExpressionPathScanEndReason* reason_to_stop,
+ ExpressionPathEndResultType* final_value_type,
+ const GetValueForExpressionPathOptions& options,
+ ExpressionPathAftermath* final_task_on_target)
+{
+
+ const char* dummy_first_unparsed;
+ ExpressionPathScanEndReason dummy_reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnknown;
+ ExpressionPathEndResultType dummy_final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid;
+ ExpressionPathAftermath dummy_final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
+
+ ValueObjectSP ret_val = GetValueForExpressionPath_Impl(expression,
+ first_unparsed ? first_unparsed : &dummy_first_unparsed,
+ reason_to_stop ? reason_to_stop : &dummy_reason_to_stop,
+ final_value_type ? final_value_type : &dummy_final_value_type,
+ options,
+ final_task_on_target ? final_task_on_target : &dummy_final_task_on_target);
+
+ if (!final_task_on_target || *final_task_on_target == ValueObject::eExpressionPathAftermathNothing)
+ return ret_val;
+
+ if (ret_val.get() && ((final_value_type ? *final_value_type : dummy_final_value_type) == eExpressionPathEndResultTypePlain)) // I can only deref and takeaddress of plain objects
+ {
+ if ( (final_task_on_target ? *final_task_on_target : dummy_final_task_on_target) == ValueObject::eExpressionPathAftermathDereference)
+ {
+ Error error;
+ ValueObjectSP final_value = ret_val->Dereference(error);
+ if (error.Fail() || !final_value.get())
+ {
+ if (reason_to_stop)
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
+ if (final_value_type)
+ *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ if (final_task_on_target)
+ *final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
+ return final_value;
+ }
+ }
+ if (*final_task_on_target == ValueObject::eExpressionPathAftermathTakeAddress)
+ {
+ Error error;
+ ValueObjectSP final_value = ret_val->AddressOf(error);
+ if (error.Fail() || !final_value.get())
+ {
+ if (reason_to_stop)
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonTakingAddressFailed;
+ if (final_value_type)
+ *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ if (final_task_on_target)
+ *final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
+ return final_value;
+ }
+ }
+ }
+ return ret_val; // final_task_on_target will still have its original value, so you know I did not do it
+}
+
+int
+ValueObject::GetValuesForExpressionPath(const char* expression,
+ ValueObjectListSP& list,
+ const char** first_unparsed,
+ ExpressionPathScanEndReason* reason_to_stop,
+ ExpressionPathEndResultType* final_value_type,
+ const GetValueForExpressionPathOptions& options,
+ ExpressionPathAftermath* final_task_on_target)
+{
+ const char* dummy_first_unparsed;
+ ExpressionPathScanEndReason dummy_reason_to_stop;
+ ExpressionPathEndResultType dummy_final_value_type;
+ ExpressionPathAftermath dummy_final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
+
+ ValueObjectSP ret_val = GetValueForExpressionPath_Impl(expression,
+ first_unparsed ? first_unparsed : &dummy_first_unparsed,
+ reason_to_stop ? reason_to_stop : &dummy_reason_to_stop,
+ final_value_type ? final_value_type : &dummy_final_value_type,
+ options,
+ final_task_on_target ? final_task_on_target : &dummy_final_task_on_target);
+
+ if (!ret_val.get()) // if there are errors, I add nothing to the list
+ return 0;
+
+ if ( (reason_to_stop ? *reason_to_stop : dummy_reason_to_stop) != eExpressionPathScanEndReasonArrayRangeOperatorMet)
+ {
+ // I need not expand a range, just post-process the final value and return
+ if (!final_task_on_target || *final_task_on_target == ValueObject::eExpressionPathAftermathNothing)
+ {
+ list->Append(ret_val);
+ return 1;
+ }
+ if (ret_val.get() && (final_value_type ? *final_value_type : dummy_final_value_type) == eExpressionPathEndResultTypePlain) // I can only deref and takeaddress of plain objects
+ {
+ if (*final_task_on_target == ValueObject::eExpressionPathAftermathDereference)
+ {
+ Error error;
+ ValueObjectSP final_value = ret_val->Dereference(error);
+ if (error.Fail() || !final_value.get())
+ {
+ if (reason_to_stop)
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
+ if (final_value_type)
+ *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ *final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
+ list->Append(final_value);
+ return 1;
+ }
+ }
+ if (*final_task_on_target == ValueObject::eExpressionPathAftermathTakeAddress)
+ {
+ Error error;
+ ValueObjectSP final_value = ret_val->AddressOf(error);
+ if (error.Fail() || !final_value.get())
+ {
+ if (reason_to_stop)
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonTakingAddressFailed;
+ if (final_value_type)
+ *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ *final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
+ list->Append(final_value);
+ return 1;
+ }
+ }
+ }
+ }
+ else
+ {
+ return ExpandArraySliceExpression(first_unparsed ? *first_unparsed : dummy_first_unparsed,
+ first_unparsed ? first_unparsed : &dummy_first_unparsed,
+ ret_val,
+ list,
+ reason_to_stop ? reason_to_stop : &dummy_reason_to_stop,
+ final_value_type ? final_value_type : &dummy_final_value_type,
+ options,
+ final_task_on_target ? final_task_on_target : &dummy_final_task_on_target);
+ }
+ // in any non-covered case, just do the obviously right thing
+ list->Append(ret_val);
+ return 1;
+}
+
+ValueObjectSP
+ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
+ const char** first_unparsed,
+ ExpressionPathScanEndReason* reason_to_stop,
+ ExpressionPathEndResultType* final_result,
+ const GetValueForExpressionPathOptions& options,
+ ExpressionPathAftermath* what_next)
+{
+ ValueObjectSP root = GetSP();
+
+ if (!root.get())
+ return ValueObjectSP();
+
+ *first_unparsed = expression_cstr;
+
+ while (true)
+ {
+
+ const char* expression_cstr = *first_unparsed; // hide the top level expression_cstr
+
+ ClangASTType root_clang_type = root->GetClangType();
+ ClangASTType pointee_clang_type;
+ Flags pointee_clang_type_info;
+
+ Flags root_clang_type_info(root_clang_type.GetTypeInfo(&pointee_clang_type));
+ if (pointee_clang_type)
+ pointee_clang_type_info.Reset(pointee_clang_type.GetTypeInfo());
+
+ if (!expression_cstr || *expression_cstr == '\0')
+ {
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString;
+ return root;
+ }
+
+ switch (*expression_cstr)
+ {
+ case '-':
+ {
+ if (options.m_check_dot_vs_arrow_syntax &&
+ root_clang_type_info.Test(ClangASTType::eTypeIsPointer) ) // if you are trying to use -> on a non-pointer and I must catch the error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrowInsteadOfDot;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ if (root_clang_type_info.Test(ClangASTType::eTypeIsObjC) && // if yo are trying to extract an ObjC IVar when this is forbidden
+ root_clang_type_info.Test(ClangASTType::eTypeIsPointer) &&
+ options.m_no_fragile_ivar)
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonFragileIVarNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ if (expression_cstr[1] != '>')
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ expression_cstr++; // skip the -
+ }
+ case '.': // or fallthrough from ->
+ {
+ if (options.m_check_dot_vs_arrow_syntax && *expression_cstr == '.' &&
+ root_clang_type_info.Test(ClangASTType::eTypeIsPointer)) // if you are trying to use . on a pointer and I must catch the error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDotInsteadOfArrow;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ expression_cstr++; // skip .
+ const char *next_separator = strpbrk(expression_cstr+1,"-.[");
+ ConstString child_name;
+ if (!next_separator) // if no other separator just expand this last layer
+ {
+ child_name.SetCString (expression_cstr);
+ ValueObjectSP child_valobj_sp = root->GetChildMemberWithName(child_name, true);
+
+ if (child_valobj_sp.get()) // we know we are done, so just return
+ {
+ *first_unparsed = "";
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString;
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ return child_valobj_sp;
+ }
+ else if (options.m_no_synthetic_children == false) // let's try with synthetic children
+ {
+ if (root->IsSynthetic())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+
+ child_valobj_sp = root->GetSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+
+ // if we are here and options.m_no_synthetic_children is true, child_valobj_sp is going to be a NULL SP,
+ // so we hit the "else" branch, and return an error
+ if(child_valobj_sp.get()) // if it worked, just return
+ {
+ *first_unparsed = "";
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString;
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ return child_valobj_sp;
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ else // other layers do expand
+ {
+ child_name.SetCStringWithLength(expression_cstr, next_separator - expression_cstr);
+ ValueObjectSP child_valobj_sp = root->GetChildMemberWithName(child_name, true);
+ if (child_valobj_sp.get()) // store the new root and move on
+ {
+ root = child_valobj_sp;
+ *first_unparsed = next_separator;
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ continue;
+ }
+ else if (options.m_no_synthetic_children == false) // let's try with synthetic children
+ {
+ if (root->IsSynthetic())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+
+ child_valobj_sp = root->GetSyntheticValue(true);
+ if (child_valobj_sp)
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+
+ // if we are here and options.m_no_synthetic_children is true, child_valobj_sp is going to be a NULL SP,
+ // so we hit the "else" branch, and return an error
+ if(child_valobj_sp.get()) // if it worked, move on
+ {
+ root = child_valobj_sp;
+ *first_unparsed = next_separator;
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ continue;
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ break;
+ }
+ case '[':
+ {
+ if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray) && !root_clang_type_info.Test(ClangASTType::eTypeIsPointer) && !root_clang_type_info.Test(ClangASTType::eTypeIsVector)) // if this is not a T[] nor a T*
+ {
+ if (!root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // if this is not even a scalar...
+ {
+ if (options.m_no_synthetic_children) // ...only chance left is synthetic
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorInvalid;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ else if (!options.m_allow_bitfields_syntax) // if this is a scalar, check that we can expand bitfields
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ if (*(expression_cstr+1) == ']') // if this is an unbounded range it only works for arrays
+ {
+ if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else // even if something follows, we cannot expand unbounded ranges, just let the caller do it
+ {
+ *first_unparsed = expression_cstr+2;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet;
+ *final_result = ValueObject::eExpressionPathEndResultTypeUnboundedRange;
+ return root;
+ }
+ }
+ const char *separator_position = ::strchr(expression_cstr+1,'-');
+ const char *close_bracket_position = ::strchr(expression_cstr+1,']');
+ if (!close_bracket_position) // if there is no ], this is a syntax error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ if (!separator_position || separator_position > close_bracket_position) // if no separator, this is either [] or [N]
+ {
+ char *end = NULL;
+ unsigned long index = ::strtoul (expression_cstr+1, &end, 0);
+ if (!end || end != close_bracket_position) // if something weird is in our way return an error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ if (end - expression_cstr == 1) // if this is [], only return a valid value for arrays
+ {
+ if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ {
+ *first_unparsed = expression_cstr+2;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet;
+ *final_result = ValueObject::eExpressionPathEndResultTypeUnboundedRange;
+ return root;
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ // from here on we do have a valid index
+ if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ {
+ ValueObjectSP child_valobj_sp = root->GetChildAtIndex(index, true);
+ if (!child_valobj_sp)
+ child_valobj_sp = root->GetSyntheticArrayMemberFromArray(index, true);
+ if (!child_valobj_sp)
+ if (root->HasSyntheticValue() && root->GetSyntheticValue()->GetNumChildren() > index)
+ child_valobj_sp = root->GetSyntheticValue()->GetChildAtIndex(index, true);
+ if (child_valobj_sp)
+ {
+ root = child_valobj_sp;
+ *first_unparsed = end+1; // skip ]
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ continue;
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ else if (root_clang_type_info.Test(ClangASTType::eTypeIsPointer))
+ {
+ if (*what_next == ValueObject::eExpressionPathAftermathDereference && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
+ pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ {
+ Error error;
+ root = root->Dereference(error);
+ if (error.Fail() || !root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ *what_next = eExpressionPathAftermathNothing;
+ continue;
+ }
+ }
+ else
+ {
+ if (root->GetClangType().GetMinimumLanguage() == eLanguageTypeObjC
+ && pointee_clang_type_info.AllClear(ClangASTType::eTypeIsPointer)
+ && root->HasSyntheticValue()
+ && options.m_no_synthetic_children == false)
+ {
+ root = root->GetSyntheticValue()->GetChildAtIndex(index, true);
+ }
+ else
+ root = root->GetSyntheticArrayMemberFromPointer(index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ *first_unparsed = end+1; // skip ]
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ continue;
+ }
+ }
+ }
+ else if (root_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ {
+ root = root->GetSyntheticBitFieldChild(index, index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else // we do not know how to expand members of bitfields, so we just return and let the caller do any further processing
+ {
+ *first_unparsed = end+1; // skip ]
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonBitfieldRangeOperatorMet;
+ *final_result = ValueObject::eExpressionPathEndResultTypeBitfield;
+ return root;
+ }
+ }
+ else if (root_clang_type_info.Test(ClangASTType::eTypeIsVector))
+ {
+ root = root->GetChildAtIndex(index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ *first_unparsed = end+1; // skip ]
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ continue;
+ }
+ }
+ else if (options.m_no_synthetic_children == false)
+ {
+ if (root->HasSyntheticValue())
+ root = root->GetSyntheticValue();
+ else if (!root->IsSynthetic())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonSyntheticValueMissing;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ // if we are here, then root itself is a synthetic VO.. should be good to go
+
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonSyntheticValueMissing;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ root = root->GetChildAtIndex(index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ *first_unparsed = end+1; // skip ]
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ continue;
+ }
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ else // we have a low and a high index
+ {
+ char *end = NULL;
+ unsigned long index_lower = ::strtoul (expression_cstr+1, &end, 0);
+ if (!end || end != separator_position) // if something weird is in our way return an error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ unsigned long index_higher = ::strtoul (separator_position+1, &end, 0);
+ if (!end || end != close_bracket_position) // if something weird is in our way return an error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ if (index_lower > index_higher) // swap indices if required
+ {
+ unsigned long temp = index_lower;
+ index_lower = index_higher;
+ index_higher = temp;
+ }
+ if (root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // expansion only works for scalars
+ {
+ root = root->GetSyntheticBitFieldChild(index_lower, index_higher, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ *first_unparsed = end+1; // skip ]
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonBitfieldRangeOperatorMet;
+ *final_result = ValueObject::eExpressionPathEndResultTypeBitfield;
+ return root;
+ }
+ }
+ else if (root_clang_type_info.Test(ClangASTType::eTypeIsPointer) && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
+ *what_next == ValueObject::eExpressionPathAftermathDereference &&
+ pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ {
+ Error error;
+ root = root->Dereference(error);
+ if (error.Fail() || !root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ *what_next = ValueObject::eExpressionPathAftermathNothing;
+ continue;
+ }
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet;
+ *final_result = ValueObject::eExpressionPathEndResultTypeBoundedRange;
+ return root;
+ }
+ }
+ break;
+ }
+ default: // some non-separator is in the way
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ break;
+ }
+ }
+ }
+}
+
+int
+ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
+ const char** first_unparsed,
+ ValueObjectSP root,
+ ValueObjectListSP& list,
+ ExpressionPathScanEndReason* reason_to_stop,
+ ExpressionPathEndResultType* final_result,
+ const GetValueForExpressionPathOptions& options,
+ ExpressionPathAftermath* what_next)
+{
+ if (!root.get())
+ return 0;
+
+ *first_unparsed = expression_cstr;
+
+ while (true)
+ {
+
+ const char* expression_cstr = *first_unparsed; // hide the top level expression_cstr
+
+ ClangASTType root_clang_type = root->GetClangType();
+ ClangASTType pointee_clang_type;
+ Flags pointee_clang_type_info;
+ Flags root_clang_type_info(root_clang_type.GetTypeInfo(&pointee_clang_type));
+ if (pointee_clang_type)
+ pointee_clang_type_info.Reset(pointee_clang_type.GetTypeInfo());
+
+ if (!expression_cstr || *expression_cstr == '\0')
+ {
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString;
+ list->Append(root);
+ return 1;
+ }
+
+ switch (*expression_cstr)
+ {
+ case '[':
+ {
+ if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray) && !root_clang_type_info.Test(ClangASTType::eTypeIsPointer)) // if this is not a T[] nor a T*
+ {
+ if (!root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // if this is not even a scalar, this syntax is just plain wrong!
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorInvalid;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else if (!options.m_allow_bitfields_syntax) // if this is a scalar, check that we can expand bitfields
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ }
+ if (*(expression_cstr+1) == ']') // if this is an unbounded range it only works for arrays
+ {
+ if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else // expand this into list
+ {
+ const size_t max_index = root->GetNumChildren() - 1;
+ for (size_t index = 0; index < max_index; index++)
+ {
+ ValueObjectSP child =
+ root->GetChildAtIndex(index, true);
+ list->Append(child);
+ }
+ *first_unparsed = expression_cstr+2;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ return max_index; // tell me number of items I added to the VOList
+ }
+ }
+ const char *separator_position = ::strchr(expression_cstr+1,'-');
+ const char *close_bracket_position = ::strchr(expression_cstr+1,']');
+ if (!close_bracket_position) // if there is no ], this is a syntax error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ if (!separator_position || separator_position > close_bracket_position) // if no separator, this is either [] or [N]
+ {
+ char *end = NULL;
+ unsigned long index = ::strtoul (expression_cstr+1, &end, 0);
+ if (!end || end != close_bracket_position) // if something weird is in our way return an error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ if (end - expression_cstr == 1) // if this is [], only return a valid value for arrays
+ {
+ if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ {
+ const size_t max_index = root->GetNumChildren() - 1;
+ for (size_t index = 0; index < max_index; index++)
+ {
+ ValueObjectSP child =
+ root->GetChildAtIndex(index, true);
+ list->Append(child);
+ }
+ *first_unparsed = expression_cstr+2;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ return max_index; // tell me number of items I added to the VOList
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ }
+ // from here on we do have a valid index
+ if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ {
+ root = root->GetChildAtIndex(index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ list->Append(root);
+ *first_unparsed = end+1; // skip ]
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ return 1;
+ }
+ }
+ else if (root_clang_type_info.Test(ClangASTType::eTypeIsPointer))
+ {
+ if (*what_next == ValueObject::eExpressionPathAftermathDereference && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
+ pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ {
+ Error error;
+ root = root->Dereference(error);
+ if (error.Fail() || !root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ *what_next = eExpressionPathAftermathNothing;
+ continue;
+ }
+ }
+ else
+ {
+ root = root->GetSyntheticArrayMemberFromPointer(index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ list->Append(root);
+ *first_unparsed = end+1; // skip ]
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ return 1;
+ }
+ }
+ }
+ else /*if (ClangASTContext::IsScalarType(root_clang_type))*/
+ {
+ root = root->GetSyntheticBitFieldChild(index, index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else // we do not know how to expand members of bitfields, so we just return and let the caller do any further processing
+ {
+ list->Append(root);
+ *first_unparsed = end+1; // skip ]
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ return 1;
+ }
+ }
+ }
+ else // we have a low and a high index
+ {
+ char *end = NULL;
+ unsigned long index_lower = ::strtoul (expression_cstr+1, &end, 0);
+ if (!end || end != separator_position) // if something weird is in our way return an error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ unsigned long index_higher = ::strtoul (separator_position+1, &end, 0);
+ if (!end || end != close_bracket_position) // if something weird is in our way return an error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ if (index_lower > index_higher) // swap indices if required
+ {
+ unsigned long temp = index_lower;
+ index_lower = index_higher;
+ index_higher = temp;
+ }
+ if (root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // expansion only works for scalars
+ {
+ root = root->GetSyntheticBitFieldChild(index_lower, index_higher, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ list->Append(root);
+ *first_unparsed = end+1; // skip ]
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ return 1;
+ }
+ }
+ else if (root_clang_type_info.Test(ClangASTType::eTypeIsPointer) && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
+ *what_next == ValueObject::eExpressionPathAftermathDereference &&
+ pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ {
+ Error error;
+ root = root->Dereference(error);
+ if (error.Fail() || !root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ *what_next = ValueObject::eExpressionPathAftermathNothing;
+ continue;
+ }
+ }
+ else
+ {
+ for (unsigned long index = index_lower;
+ index <= index_higher; index++)
+ {
+ ValueObjectSP child =
+ root->GetChildAtIndex(index, true);
+ list->Append(child);
+ }
+ *first_unparsed = end+1;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ return index_higher-index_lower+1; // tell me number of items I added to the VOList
+ }
+ }
+ break;
+ }
+ default: // some non-[ separator, or something entirely wrong, is in the way
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ break;
+ }
+ }
+ }
+}
+
+static void
+DumpValueObject_Impl (Stream &s,
+ ValueObject *valobj,
+ const ValueObject::DumpValueObjectOptions& options,
+ uint32_t ptr_depth,
+ uint32_t curr_depth)
+{
+ if (valobj)
+ {
+ bool update_success = valobj->UpdateValueIfNeeded (true);
+
+ const char *root_valobj_name =
+ options.m_root_valobj_name.empty() ?
+ valobj->GetName().AsCString() :
+ options.m_root_valobj_name.c_str();
+
+ if (update_success && options.m_use_dynamic != eNoDynamicValues)
+ {
+ ValueObject *dynamic_value = valobj->GetDynamicValue(options.m_use_dynamic).get();
+ if (dynamic_value)
+ valobj = dynamic_value;
+ }
+
+ ClangASTType clang_type = valobj->GetClangType();
+ const Flags type_flags (clang_type.GetTypeInfo ());
+ const char *err_cstr = NULL;
+ const bool has_children = type_flags.Test (ClangASTType::eTypeHasChildren);
+ const bool has_value = type_flags.Test (ClangASTType::eTypeHasValue);
+
+ const bool print_valobj = options.m_flat_output == false || has_value;
+
+ if (print_valobj)
+ {
+ if (options.m_show_location)
+ {
+ s.Printf("%s: ", valobj->GetLocationAsCString());
+ }
+
+ s.Indent();
+
+ bool show_type = true;
+ // if we are at the root-level and been asked to hide the root's type, then hide it
+ if (curr_depth == 0 && options.m_hide_root_type)
+ show_type = false;
+ else
+ // otherwise decide according to the usual rules (asked to show types - always at the root level)
+ show_type = options.m_show_types || (curr_depth == 0 && !options.m_flat_output);
+
+ if (show_type)
+ {
+ // Some ValueObjects don't have types (like registers sets). Only print
+ // the type if there is one to print
+ ConstString qualified_type_name(valobj->GetQualifiedTypeName());
+ if (qualified_type_name)
+ s.Printf("(%s) ", qualified_type_name.GetCString());
+ }
+
+ if (options.m_flat_output)
+ {
+ // If we are showing types, also qualify the C++ base classes
+ const bool qualify_cxx_base_classes = options.m_show_types;
+ if (!options.m_hide_name)
+ {
+ valobj->GetExpressionPath(s, qualify_cxx_base_classes);
+ s.PutCString(" =");
+ }
+ }
+ else if (!options.m_hide_name)
+ {
+ const char *name_cstr = root_valobj_name ? root_valobj_name : valobj->GetName().AsCString("");
+ s.Printf ("%s =", name_cstr);
+ }
+
+ if (!options.m_scope_already_checked && !valobj->IsInScope())
+ {
+ err_cstr = "out of scope";
+ }
+ }
+
+ std::string summary_str;
+ std::string value_str;
+ const char *val_cstr = NULL;
+ const char *sum_cstr = NULL;
+ TypeSummaryImpl* entry = options.m_summary_sp ? options.m_summary_sp.get() : valobj->GetSummaryFormat().get();
+
+ if (options.m_omit_summary_depth > 0)
+ entry = NULL;
+
+ bool is_nil = valobj->IsObjCNil();
+
+ if (err_cstr == NULL)
+ {
+ if (options.m_format != eFormatDefault && options.m_format != valobj->GetFormat())
+ {
+ valobj->GetValueAsCString(options.m_format,
+ value_str);
+ }
+ else
+ {
+ val_cstr = valobj->GetValueAsCString();
+ if (val_cstr)
+ value_str = val_cstr;
+ }
+ err_cstr = valobj->GetError().AsCString();
+ }
+
+ if (err_cstr)
+ {
+ s.Printf (" <%s>\n", err_cstr);
+ }
+ else
+ {
+ const bool is_ref = type_flags.Test (ClangASTType::eTypeIsReference);
+ if (print_valobj)
+ {
+ if (is_nil)
+ sum_cstr = "nil";
+ else if (options.m_omit_summary_depth == 0)
+ {
+ if (options.m_summary_sp)
+ {
+ valobj->GetSummaryAsCString(entry, summary_str);
+ sum_cstr = summary_str.c_str();
+ }
+ else
+ sum_cstr = valobj->GetSummaryAsCString();
+ }
+
+ // Make sure we have a value and make sure the summary didn't
+ // specify that the value should not be printed - and do not print
+ // the value if this thing is nil
+ // (but show the value if the user passes a format explicitly)
+ if (!is_nil && !value_str.empty() && (entry == NULL || (entry->DoesPrintValue() || options.m_format != eFormatDefault) || sum_cstr == NULL) && !options.m_hide_value)
+ s.Printf(" %s", value_str.c_str());
+
+ if (sum_cstr)
+ s.Printf(" %s", sum_cstr);
+
+ // let's avoid the overly verbose no description error for a nil thing
+ if (options.m_use_objc && !is_nil)
+ {
+ if (!options.m_hide_value || !options.m_hide_name)
+ s.Printf(" ");
+ const char *object_desc = valobj->GetObjectDescription();
+ if (object_desc)
+ s.Printf("%s\n", object_desc);
+ else
+ s.Printf ("[no Objective-C description available]\n");
+ return;
+ }
+ }
+
+ if (curr_depth < options.m_max_depth)
+ {
+ // We will show children for all concrete types. We won't show
+ // pointer contents unless a pointer depth has been specified.
+ // We won't reference contents unless the reference is the
+ // root object (depth of zero).
+ bool print_children = true;
+
+ // Use a new temporary pointer depth in case we override the
+ // current pointer depth below...
+ uint32_t curr_ptr_depth = ptr_depth;
+
+ const bool is_ptr = type_flags.Test (ClangASTType::eTypeIsPointer);
+ if (is_ptr || is_ref)
+ {
+ // We have a pointer or reference whose value is an address.
+ // Make sure that address is not NULL
+ AddressType ptr_address_type;
+ if (valobj->GetPointerValue (&ptr_address_type) == 0)
+ print_children = false;
+
+ else if (is_ref && curr_depth == 0)
+ {
+ // If this is the root object (depth is zero) that we are showing
+ // and it is a reference, and no pointer depth has been supplied
+ // print out what it references. Don't do this at deeper depths
+ // otherwise we can end up with infinite recursion...
+ curr_ptr_depth = 1;
+ }
+
+ if (curr_ptr_depth == 0)
+ print_children = false;
+ }
+
+ if (print_children && (!entry || entry->DoesPrintChildren() || !sum_cstr))
+ {
+ ValueObjectSP synth_valobj_sp = valobj->GetSyntheticValue (options.m_use_synthetic);
+ ValueObject* synth_valobj = (synth_valobj_sp ? synth_valobj_sp.get() : valobj);
+
+ size_t num_children = synth_valobj->GetNumChildren();
+ bool print_dotdotdot = false;
+ if (num_children)
+ {
+ if (options.m_flat_output)
+ {
+ if (print_valobj)
+ s.EOL();
+ }
+ else
+ {
+ if (print_valobj)
+ s.PutCString(is_ref ? ": {\n" : " {\n");
+ s.IndentMore();
+ }
+
+ const size_t max_num_children = valobj->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
+
+ if (num_children > max_num_children && !options.m_ignore_cap)
+ {
+ num_children = max_num_children;
+ print_dotdotdot = true;
+ }
+
+ ValueObject::DumpValueObjectOptions child_options(options);
+ child_options.SetFormat(options.m_format).SetSummary().SetRootValueObjectName();
+ child_options.SetScopeChecked(true).SetHideName(options.m_hide_name).SetHideValue(options.m_hide_value)
+ .SetOmitSummaryDepth(child_options.m_omit_summary_depth > 1 ? child_options.m_omit_summary_depth - 1 : 0);
+ for (size_t idx=0; idx<num_children; ++idx)
+ {
+ ValueObjectSP child_sp(synth_valobj->GetChildAtIndex(idx, true));
+ if (child_sp.get())
+ {
+ DumpValueObject_Impl (s,
+ child_sp.get(),
+ child_options,
+ (is_ptr || is_ref) ? curr_ptr_depth - 1 : curr_ptr_depth,
+ curr_depth + 1);
+ }
+ }
+
+ if (!options.m_flat_output)
+ {
+ if (print_dotdotdot)
+ {
+ ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ target->GetDebugger().GetCommandInterpreter().ChildrenTruncated();
+ s.Indent("...\n");
+ }
+ s.IndentLess();
+ s.Indent("}\n");
+ }
+ }
+ else if (has_children)
+ {
+ // Aggregate, no children...
+ if (print_valobj)
+ s.PutCString(" {}\n");
+ }
+ else
+ {
+ if (print_valobj)
+ s.EOL();
+ }
+
+ }
+ else
+ {
+ s.EOL();
+ }
+ }
+ else
+ {
+ if (has_children && print_valobj)
+ {
+ s.PutCString("{...}\n");
+ }
+ }
+ }
+ }
+}
+
+void
+ValueObject::LogValueObject (Log *log,
+ ValueObject *valobj)
+{
+ if (log && valobj)
+ return LogValueObject (log, valobj, DumpValueObjectOptions::DefaultOptions());
+}
+
+void
+ValueObject::LogValueObject (Log *log,
+ ValueObject *valobj,
+ const DumpValueObjectOptions& options)
+{
+ if (log && valobj)
+ {
+ StreamString s;
+ ValueObject::DumpValueObject (s, valobj, options);
+ if (s.GetSize())
+ log->PutCString(s.GetData());
+ }
+}
+
+void
+ValueObject::DumpValueObject (Stream &s,
+ ValueObject *valobj)
+{
+
+ if (!valobj)
+ return;
+
+ DumpValueObject_Impl(s,
+ valobj,
+ DumpValueObjectOptions::DefaultOptions(),
+ 0,
+ 0);
+}
+
+void
+ValueObject::DumpValueObject (Stream &s,
+ ValueObject *valobj,
+ const DumpValueObjectOptions& options)
+{
+ DumpValueObject_Impl(s,
+ valobj,
+ options,
+ options.m_max_ptr_depth, // max pointer depth allowed, we will go down from here
+ 0 // current object depth is 0 since we are just starting
+ );
+}
+
+ValueObjectSP
+ValueObject::CreateConstantValue (const ConstString &name)
+{
+ ValueObjectSP valobj_sp;
+
+ if (UpdateValueIfNeeded(false) && m_error.Success())
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+
+ DataExtractor data;
+ data.SetByteOrder (m_data.GetByteOrder());
+ data.SetAddressByteSize(m_data.GetAddressByteSize());
+
+ if (IsBitfield())
+ {
+ Value v(Scalar(GetValueAsUnsigned(UINT64_MAX)));
+ m_error = v.GetValueAsData (&exe_ctx, data, 0, GetModule().get());
+ }
+ else
+ m_error = m_value.GetValueAsData (&exe_ctx, data, 0, GetModule().get());
+
+ valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
+ GetClangType(),
+ name,
+ data,
+ GetAddressOf());
+ }
+
+ if (!valobj_sp)
+ {
+ valobj_sp = ValueObjectConstResult::Create (NULL, m_error);
+ }
+ return valobj_sp;
+}
+
+ValueObjectSP
+ValueObject::Dereference (Error &error)
+{
+ if (m_deref_valobj)
+ return m_deref_valobj->GetSP();
+
+ const bool is_pointer_type = IsPointerType();
+ if (is_pointer_type)
+ {
+ bool omit_empty_base_classes = true;
+ bool ignore_array_bounds = false;
+
+ std::string child_name_str;
+ uint32_t child_byte_size = 0;
+ int32_t child_byte_offset = 0;
+ uint32_t child_bitfield_bit_size = 0;
+ uint32_t child_bitfield_bit_offset = 0;
+ bool child_is_base_class = false;
+ bool child_is_deref_of_parent = false;
+ const bool transparent_pointers = false;
+ ClangASTType clang_type = GetClangType();
+ ClangASTType child_clang_type;
+
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+
+ child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
+ GetName().GetCString(),
+ 0,
+ transparent_pointers,
+ omit_empty_base_classes,
+ ignore_array_bounds,
+ child_name_str,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent);
+ if (child_clang_type && child_byte_size)
+ {
+ ConstString child_name;
+ if (!child_name_str.empty())
+ child_name.SetCString (child_name_str.c_str());
+
+ m_deref_valobj = new ValueObjectChild (*this,
+ child_clang_type,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent,
+ eAddressTypeInvalid);
+ }
+ }
+
+ if (m_deref_valobj)
+ {
+ error.Clear();
+ return m_deref_valobj->GetSP();
+ }
+ else
+ {
+ StreamString strm;
+ GetExpressionPath(strm, true);
+
+ if (is_pointer_type)
+ error.SetErrorStringWithFormat("dereference failed: (%s) %s", GetTypeName().AsCString("<invalid type>"), strm.GetString().c_str());
+ else
+ error.SetErrorStringWithFormat("not a pointer type: (%s) %s", GetTypeName().AsCString("<invalid type>"), strm.GetString().c_str());
+ return ValueObjectSP();
+ }
+}
+
+ValueObjectSP
+ValueObject::AddressOf (Error &error)
+{
+ if (m_addr_of_valobj_sp)
+ return m_addr_of_valobj_sp;
+
+ AddressType address_type = eAddressTypeInvalid;
+ const bool scalar_is_load_address = false;
+ addr_t addr = GetAddressOf (scalar_is_load_address, &address_type);
+ error.Clear();
+ if (addr != LLDB_INVALID_ADDRESS)
+ {
+ switch (address_type)
+ {
+ case eAddressTypeInvalid:
+ {
+ StreamString expr_path_strm;
+ GetExpressionPath(expr_path_strm, true);
+ error.SetErrorStringWithFormat("'%s' is not in memory", expr_path_strm.GetString().c_str());
+ }
+ break;
+
+ case eAddressTypeFile:
+ case eAddressTypeLoad:
+ case eAddressTypeHost:
+ {
+ ClangASTType clang_type = GetClangType();
+ if (clang_type)
+ {
+ std::string name (1, '&');
+ name.append (m_name.AsCString(""));
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ m_addr_of_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
+ clang_type.GetPointerType(),
+ ConstString (name.c_str()),
+ addr,
+ eAddressTypeInvalid,
+ m_data.GetAddressByteSize());
+ }
+ }
+ break;
+ }
+ }
+ else
+ {
+ StreamString expr_path_strm;
+ GetExpressionPath(expr_path_strm, true);
+ error.SetErrorStringWithFormat("'%s' doesn't have a valid address", expr_path_strm.GetString().c_str());
+ }
+
+ return m_addr_of_valobj_sp;
+}
+
+ValueObjectSP
+ValueObject::Cast (const ClangASTType &clang_ast_type)
+{
+ return ValueObjectCast::Create (*this, GetName(), clang_ast_type);
+}
+
+ValueObjectSP
+ValueObject::CastPointerType (const char *name, ClangASTType &clang_ast_type)
+{
+ ValueObjectSP valobj_sp;
+ AddressType address_type;
+ addr_t ptr_value = GetPointerValue (&address_type);
+
+ if (ptr_value != LLDB_INVALID_ADDRESS)
+ {
+ Address ptr_addr (ptr_value);
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ valobj_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(),
+ name,
+ ptr_addr,
+ clang_ast_type);
+ }
+ return valobj_sp;
+}
+
+ValueObjectSP
+ValueObject::CastPointerType (const char *name, TypeSP &type_sp)
+{
+ ValueObjectSP valobj_sp;
+ AddressType address_type;
+ addr_t ptr_value = GetPointerValue (&address_type);
+
+ if (ptr_value != LLDB_INVALID_ADDRESS)
+ {
+ Address ptr_addr (ptr_value);
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ valobj_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(),
+ name,
+ ptr_addr,
+ type_sp);
+ }
+ return valobj_sp;
+}
+
+ValueObject::EvaluationPoint::EvaluationPoint () :
+ m_mod_id(),
+ m_exe_ctx_ref(),
+ m_needs_update (true),
+ m_first_update (true)
+{
+}
+
+ValueObject::EvaluationPoint::EvaluationPoint (ExecutionContextScope *exe_scope, bool use_selected):
+ m_mod_id(),
+ m_exe_ctx_ref(),
+ m_needs_update (true),
+ m_first_update (true)
+{
+ ExecutionContext exe_ctx(exe_scope);
+ TargetSP target_sp (exe_ctx.GetTargetSP());
+ if (target_sp)
+ {
+ m_exe_ctx_ref.SetTargetSP (target_sp);
+ ProcessSP process_sp (exe_ctx.GetProcessSP());
+ if (!process_sp)
+ process_sp = target_sp->GetProcessSP();
+
+ if (process_sp)
+ {
+ m_mod_id = process_sp->GetModID();
+ m_exe_ctx_ref.SetProcessSP (process_sp);
+
+ ThreadSP thread_sp (exe_ctx.GetThreadSP());
+
+ if (!thread_sp)
+ {
+ if (use_selected)
+ thread_sp = process_sp->GetThreadList().GetSelectedThread();
+ }
+
+ if (thread_sp)
+ {
+ m_exe_ctx_ref.SetThreadSP(thread_sp);
+
+ StackFrameSP frame_sp (exe_ctx.GetFrameSP());
+ if (!frame_sp)
+ {
+ if (use_selected)
+ frame_sp = thread_sp->GetSelectedFrame();
+ }
+ if (frame_sp)
+ m_exe_ctx_ref.SetFrameSP(frame_sp);
+ }
+ }
+ }
+}
+
+ValueObject::EvaluationPoint::EvaluationPoint (const ValueObject::EvaluationPoint &rhs) :
+ m_mod_id(),
+ m_exe_ctx_ref(rhs.m_exe_ctx_ref),
+ m_needs_update (true),
+ m_first_update (true)
+{
+}
+
+ValueObject::EvaluationPoint::~EvaluationPoint ()
+{
+}
+
+// This function checks the EvaluationPoint against the current process state. If the current
+// state matches the evaluation point, or the evaluation point is already invalid, then we return
+// false, meaning "no change". If the current state is different, we update our state, and return
+// true meaning "yes, change". If we did see a change, we also set m_needs_update to true, so
+// future calls to NeedsUpdate will return true.
+// exe_scope will be set to the current execution context scope.
+
+bool
+ValueObject::EvaluationPoint::SyncWithProcessState()
+{
+
+ // Start with the target, if it is NULL, then we're obviously not going to get any further:
+ ExecutionContext exe_ctx(m_exe_ctx_ref.Lock());
+
+ if (exe_ctx.GetTargetPtr() == NULL)
+ return false;
+
+ // If we don't have a process nothing can change.
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ return false;
+
+ // If our stop id is the current stop ID, nothing has changed:
+ ProcessModID current_mod_id = process->GetModID();
+
+ // If the current stop id is 0, either we haven't run yet, or the process state has been cleared.
+ // In either case, we aren't going to be able to sync with the process state.
+ if (current_mod_id.GetStopID() == 0)
+ return false;
+
+ bool changed = false;
+ const bool was_valid = m_mod_id.IsValid();
+ if (was_valid)
+ {
+ if (m_mod_id == current_mod_id)
+ {
+ // Everything is already up to date in this object, no need to
+ // update the execution context scope.
+ changed = false;
+ }
+ else
+ {
+ m_mod_id = current_mod_id;
+ m_needs_update = true;
+ changed = true;
+ }
+ }
+
+ // Now re-look up the thread and frame in case the underlying objects have gone away & been recreated.
+ // That way we'll be sure to return a valid exe_scope.
+ // If we used to have a thread or a frame but can't find it anymore, then mark ourselves as invalid.
+
+ if (m_exe_ctx_ref.HasThreadRef())
+ {
+ ThreadSP thread_sp (m_exe_ctx_ref.GetThreadSP());
+ if (thread_sp)
+ {
+ if (m_exe_ctx_ref.HasFrameRef())
+ {
+ StackFrameSP frame_sp (m_exe_ctx_ref.GetFrameSP());
+ if (!frame_sp)
+ {
+ // We used to have a frame, but now it is gone
+ SetInvalid();
+ changed = was_valid;
+ }
+ }
+ }
+ else
+ {
+ // We used to have a thread, but now it is gone
+ SetInvalid();
+ changed = was_valid;
+ }
+
+ }
+ return changed;
+}
+
+void
+ValueObject::EvaluationPoint::SetUpdated ()
+{
+ ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
+ if (process_sp)
+ m_mod_id = process_sp->GetModID();
+ m_first_update = false;
+ m_needs_update = false;
+}
+
+
+
+void
+ValueObject::ClearUserVisibleData(uint32_t clear_mask)
+{
+ if ((clear_mask & eClearUserVisibleDataItemsValue) == eClearUserVisibleDataItemsValue)
+ m_value_str.clear();
+
+ if ((clear_mask & eClearUserVisibleDataItemsLocation) == eClearUserVisibleDataItemsLocation)
+ m_location_str.clear();
+
+ if ((clear_mask & eClearUserVisibleDataItemsSummary) == eClearUserVisibleDataItemsSummary)
+ {
+ m_summary_str.clear();
+ }
+
+ if ((clear_mask & eClearUserVisibleDataItemsDescription) == eClearUserVisibleDataItemsDescription)
+ m_object_desc_str.clear();
+
+ if ((clear_mask & eClearUserVisibleDataItemsSyntheticChildren) == eClearUserVisibleDataItemsSyntheticChildren)
+ {
+ if (m_synthetic_value)
+ m_synthetic_value = NULL;
+ }
+}
+
+SymbolContextScope *
+ValueObject::GetSymbolContextScope()
+{
+ if (m_parent)
+ {
+ if (!m_parent->IsPointerOrReferenceType())
+ return m_parent->GetSymbolContextScope();
+ }
+ return NULL;
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromExpression (const char* name,
+ const char* expression,
+ const ExecutionContext& exe_ctx)
+{
+ lldb::ValueObjectSP retval_sp;
+ lldb::TargetSP target_sp(exe_ctx.GetTargetSP());
+ if (!target_sp)
+ return retval_sp;
+ if (!expression || !*expression)
+ return retval_sp;
+ target_sp->EvaluateExpression (expression,
+ exe_ctx.GetFrameSP().get(),
+ retval_sp);
+ if (retval_sp && name && *name)
+ retval_sp->SetName(ConstString(name));
+ return retval_sp;
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromAddress (const char* name,
+ uint64_t address,
+ const ExecutionContext& exe_ctx,
+ ClangASTType type)
+{
+ if (type)
+ {
+ ClangASTType pointer_type(type.GetPointerType());
+ if (pointer_type)
+ {
+ lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&address,sizeof(lldb::addr_t)));
+ lldb::ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
+ pointer_type,
+ ConstString(name),
+ buffer,
+ lldb::endian::InlHostByteOrder(),
+ exe_ctx.GetAddressByteSize()));
+ if (ptr_result_valobj_sp)
+ {
+ ptr_result_valobj_sp->GetValue().SetValueType(Value::eValueTypeLoadAddress);
+ Error err;
+ ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err);
+ if (ptr_result_valobj_sp && name && *name)
+ ptr_result_valobj_sp->SetName(ConstString(name));
+ }
+ return ptr_result_valobj_sp;
+ }
+ }
+ return lldb::ValueObjectSP();
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromData (const char* name,
+ DataExtractor& data,
+ const ExecutionContext& exe_ctx,
+ ClangASTType type)
+{
+ lldb::ValueObjectSP new_value_sp;
+ new_value_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
+ type,
+ ConstString(name),
+ data,
+ LLDB_INVALID_ADDRESS);
+ new_value_sp->SetAddressTypeOfChildren(eAddressTypeLoad);
+ if (new_value_sp && name && *name)
+ new_value_sp->SetName(ConstString(name));
+ return new_value_sp;
+}
+
+ModuleSP
+ValueObject::GetModule ()
+{
+ ValueObject* root(GetRoot());
+ if (root != this)
+ return root->GetModule();
+ return lldb::ModuleSP();
+}
+
+ValueObject*
+ValueObject::GetRoot ()
+{
+ if (m_root)
+ return m_root;
+ ValueObject* parent = m_parent;
+ if (!parent)
+ return (m_root = this);
+ while (parent->m_parent)
+ {
+ if (parent->m_root)
+ return (m_root = parent->m_root);
+ parent = parent->m_parent;
+ }
+ return (m_root = parent);
+}
+
+AddressType
+ValueObject::GetAddressTypeOfChildren()
+{
+ if (m_address_type_of_ptr_or_ref_children == eAddressTypeInvalid)
+ {
+ ValueObject* root(GetRoot());
+ if (root != this)
+ return root->GetAddressTypeOfChildren();
+ }
+ return m_address_type_of_ptr_or_ref_children;
+}
+
+lldb::DynamicValueType
+ValueObject::GetDynamicValueType ()
+{
+ ValueObject* with_dv_info = this;
+ while (with_dv_info)
+ {
+ if (with_dv_info->HasDynamicValueTypeInfo())
+ return with_dv_info->GetDynamicValueTypeImpl();
+ with_dv_info = with_dv_info->m_parent;
+ }
+ return lldb::eNoDynamicValues;
+}
+
+lldb::Format
+ValueObject::GetFormat () const
+{
+ const ValueObject* with_fmt_info = this;
+ while (with_fmt_info)
+ {
+ if (with_fmt_info->m_format != lldb::eFormatDefault)
+ return with_fmt_info->m_format;
+ with_fmt_info = with_fmt_info->m_parent;
+ }
+ return m_format;
+}
diff --git a/source/Core/ValueObjectCast.cpp b/source/Core/ValueObjectCast.cpp
new file mode 100644
index 0000000..4f4f8cc
--- /dev/null
+++ b/source/Core/ValueObjectCast.cpp
@@ -0,0 +1,129 @@
+//===-- ValueObjectDynamicValue.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/ValueObjectCast.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb_private;
+
+lldb::ValueObjectSP
+ValueObjectCast::Create (ValueObject &parent,
+ const ConstString &name,
+ const ClangASTType &cast_type)
+{
+ ValueObjectCast *cast_valobj_ptr = new ValueObjectCast (parent, name, cast_type);
+ return cast_valobj_ptr->GetSP();
+}
+
+ValueObjectCast::ValueObjectCast
+(
+ ValueObject &parent,
+ const ConstString &name,
+ const ClangASTType &cast_type
+) :
+ ValueObject(parent),
+ m_cast_type (cast_type)
+{
+ SetName (name);
+ //m_value.SetContext (Value::eContextTypeClangType, cast_type.GetOpaqueQualType());
+ m_value.SetClangType (cast_type);
+}
+
+ValueObjectCast::~ValueObjectCast()
+{
+}
+
+ClangASTType
+ValueObjectCast::GetClangTypeImpl ()
+{
+ return m_cast_type;
+}
+
+size_t
+ValueObjectCast::CalculateNumChildren()
+{
+ return GetClangType().GetNumChildren (true);
+}
+
+uint64_t
+ValueObjectCast::GetByteSize()
+{
+ return m_value.GetValueByteSize(NULL);
+}
+
+lldb::ValueType
+ValueObjectCast::GetValueType() const
+{
+ // Let our parent answer global, local, argument, etc...
+ return m_parent->GetValueType();
+}
+
+bool
+ValueObjectCast::UpdateValue ()
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ if (m_parent->UpdateValueIfNeeded(false))
+ {
+ Value old_value(m_value);
+ m_update_point.SetUpdated();
+ m_value = m_parent->GetValue();
+ ClangASTType clang_type (GetClangType());
+ //m_value.SetContext (Value::eContextTypeClangType, clang_type);
+ m_value.SetClangType (clang_type);
+ SetAddressTypeOfChildren(m_parent->GetAddressTypeOfChildren());
+ if (clang_type.IsAggregateType ())
+ {
+ // this value object represents an aggregate type whose
+ // children have values, but this object does not. So we
+ // say we are changed if our location has changed.
+ SetValueDidChange (m_value.GetValueType() != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar());
+ }
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ m_error = m_value.GetValueAsData(&exe_ctx, m_data, 0, GetModule().get());
+ SetValueDidChange (m_parent->GetValueDidChange());
+ return true;
+ }
+
+ // The dynamic value failed to get an error, pass the error along
+ if (m_error.Success() && m_parent->GetError().Fail())
+ m_error = m_parent->GetError();
+ SetValueIsValid (false);
+ return false;
+}
+
+bool
+ValueObjectCast::IsInScope ()
+{
+ return m_parent->IsInScope();
+}
diff --git a/source/Core/ValueObjectChild.cpp b/source/Core/ValueObjectChild.cpp
new file mode 100644
index 0000000..23add1c
--- /dev/null
+++ b/source/Core/ValueObjectChild.cpp
@@ -0,0 +1,234 @@
+//===-- ValueObjectChild.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/ValueObjectChild.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb_private;
+
+ValueObjectChild::ValueObjectChild
+(
+ ValueObject &parent,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ uint64_t byte_size,
+ int32_t byte_offset,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset,
+ bool is_base_class,
+ bool is_deref_of_parent,
+ AddressType child_ptr_or_ref_addr_type
+) :
+ ValueObject (parent),
+ m_clang_type (clang_type),
+ m_byte_size (byte_size),
+ m_byte_offset (byte_offset),
+ m_bitfield_bit_size (bitfield_bit_size),
+ m_bitfield_bit_offset (bitfield_bit_offset),
+ m_is_base_class (is_base_class),
+ m_is_deref_of_parent (is_deref_of_parent)
+{
+ m_name = name;
+ SetAddressTypeOfChildren(child_ptr_or_ref_addr_type);
+}
+
+ValueObjectChild::~ValueObjectChild()
+{
+}
+
+lldb::ValueType
+ValueObjectChild::GetValueType() const
+{
+ return m_parent->GetValueType();
+}
+
+size_t
+ValueObjectChild::CalculateNumChildren()
+{
+ return GetClangType().GetNumChildren (true);
+}
+
+ConstString
+ValueObjectChild::GetTypeName()
+{
+ if (m_type_name.IsEmpty())
+ {
+ m_type_name = GetClangType().GetConstTypeName ();
+ if (m_type_name)
+ {
+ if (m_bitfield_bit_size > 0)
+ {
+ const char *clang_type_name = m_type_name.AsCString();
+ if (clang_type_name)
+ {
+ std::vector<char> bitfield_type_name (strlen(clang_type_name) + 32, 0);
+ ::snprintf (&bitfield_type_name.front(), bitfield_type_name.size(), "%s:%u", clang_type_name, m_bitfield_bit_size);
+ m_type_name.SetCString(&bitfield_type_name.front());
+ }
+ }
+ }
+ }
+ return m_type_name;
+}
+
+ConstString
+ValueObjectChild::GetQualifiedTypeName()
+{
+ ConstString qualified_name = GetClangType().GetConstTypeName();
+ if (qualified_name)
+ {
+ if (m_bitfield_bit_size > 0)
+ {
+ const char *clang_type_name = qualified_name.AsCString();
+ if (clang_type_name)
+ {
+ std::vector<char> bitfield_type_name (strlen(clang_type_name) + 32, 0);
+ ::snprintf (&bitfield_type_name.front(), bitfield_type_name.size(), "%s:%u", clang_type_name, m_bitfield_bit_size);
+ qualified_name.SetCString(&bitfield_type_name.front());
+ }
+ }
+ }
+ return qualified_name;
+}
+
+bool
+ValueObjectChild::UpdateValue ()
+{
+ m_error.Clear();
+ SetValueIsValid (false);
+ ValueObject* parent = m_parent;
+ if (parent)
+ {
+ if (parent->UpdateValueIfNeeded(false))
+ {
+ m_value.SetClangType(GetClangType());
+
+ // Copy the parent scalar value and the scalar value type
+ m_value.GetScalar() = parent->GetValue().GetScalar();
+ Value::ValueType value_type = parent->GetValue().GetValueType();
+ m_value.SetValueType (value_type);
+
+ if (parent->GetClangType().IsPointerOrReferenceType ())
+ {
+ lldb::addr_t addr = parent->GetPointerValue ();
+ m_value.GetScalar() = addr;
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ m_error.SetErrorString ("parent address is invalid.");
+ }
+ else if (addr == 0)
+ {
+ m_error.SetErrorString ("parent is NULL");
+ }
+ else
+ {
+ m_value.GetScalar() += m_byte_offset;
+ AddressType addr_type = parent->GetAddressTypeOfChildren();
+
+ switch (addr_type)
+ {
+ case eAddressTypeFile:
+ {
+ lldb::ProcessSP process_sp (GetProcessSP());
+ if (process_sp && process_sp->IsAlive() == true)
+ m_value.SetValueType (Value::eValueTypeLoadAddress);
+ else
+ m_value.SetValueType(Value::eValueTypeFileAddress);
+ }
+ break;
+ case eAddressTypeLoad:
+ m_value.SetValueType (Value::eValueTypeLoadAddress);
+ break;
+ case eAddressTypeHost:
+ m_value.SetValueType(Value::eValueTypeHostAddress);
+ break;
+ case eAddressTypeInvalid:
+ // TODO: does this make sense?
+ m_value.SetValueType(Value::eValueTypeScalar);
+ break;
+ }
+ }
+ }
+ else
+ {
+ switch (value_type)
+ {
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeHostAddress:
+ {
+ lldb::addr_t addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ m_error.SetErrorString ("parent address is invalid.");
+ }
+ else if (addr == 0)
+ {
+ m_error.SetErrorString ("parent is NULL");
+ }
+ else
+ {
+ // Set this object's scalar value to the address of its
+ // value by adding its byte offset to the parent address
+ m_value.GetScalar() += GetByteOffset();
+ }
+ }
+ break;
+
+ case Value::eValueTypeScalar:
+ // TODO: What if this is a register value? Do we try and
+ // extract the child value from within the parent data?
+ // Probably...
+ default:
+ m_error.SetErrorString ("parent has invalid value.");
+ break;
+ }
+ }
+
+ if (m_error.Success())
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef().Lock());
+ m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
+ }
+ }
+ else
+ {
+ m_error.SetErrorStringWithFormat("parent failed to evaluate: %s", parent->GetError().AsCString());
+ }
+ }
+ else
+ {
+ m_error.SetErrorString("ValueObjectChild has a NULL parent ValueObject.");
+ }
+
+ return m_error.Success();
+}
+
+
+bool
+ValueObjectChild::IsInScope ()
+{
+ ValueObject* root(GetRoot());
+ if (root)
+ return root->IsInScope ();
+ return false;
+}
diff --git a/source/Core/ValueObjectConstResult.cpp b/source/Core/ValueObjectConstResult.cpp
new file mode 100644
index 0000000..d6d8638
--- /dev/null
+++ b/source/Core/ValueObjectConstResult.cpp
@@ -0,0 +1,354 @@
+//===-- ValueObjectConstResult.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/ValueObjectConstResult.h"
+
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Core/ValueObjectConstResultChild.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectDynamicValue.h"
+#include "lldb/Core/ValueObjectList.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ValueObjectSP
+ValueObjectConstResult::Create (ExecutionContextScope *exe_scope,
+ ByteOrder byte_order,
+ uint32_t addr_byte_size,
+ lldb::addr_t address)
+{
+ return (new ValueObjectConstResult (exe_scope,
+ byte_order,
+ addr_byte_size,
+ address))->GetSP();
+}
+
+ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ ByteOrder byte_order,
+ uint32_t addr_byte_size,
+ lldb::addr_t address) :
+ ValueObject (exe_scope),
+ m_type_name (),
+ m_byte_size (0),
+ m_impl(this, address)
+{
+ SetIsConstant ();
+ SetValueIsValid(true);
+ m_data.SetByteOrder(byte_order);
+ m_data.SetAddressByteSize(addr_byte_size);
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+}
+
+ValueObjectSP
+ValueObjectConstResult::Create
+(
+ ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ const DataExtractor &data,
+ lldb::addr_t address
+)
+{
+ return (new ValueObjectConstResult (exe_scope,
+ clang_type,
+ name,
+ data,
+ address))->GetSP();
+}
+
+ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ const DataExtractor &data,
+ lldb::addr_t address) :
+ ValueObject (exe_scope),
+ m_type_name (),
+ m_byte_size (0),
+ m_impl(this, address)
+{
+ m_data = data;
+
+ if (!m_data.GetSharedDataBuffer())
+ {
+ DataBufferSP shared_data_buffer(new DataBufferHeap(data.GetDataStart(), data.GetByteSize()));
+ m_data.SetData(shared_data_buffer);
+ }
+
+ m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
+ m_value.SetValueType(Value::eValueTypeHostAddress);
+ m_value.SetClangType(clang_type);
+ m_name = name;
+ SetIsConstant ();
+ SetValueIsValid(true);
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+}
+
+ValueObjectSP
+ValueObjectConstResult::Create (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ const lldb::DataBufferSP &data_sp,
+ lldb::ByteOrder data_byte_order,
+ uint32_t data_addr_size,
+ lldb::addr_t address)
+{
+ return (new ValueObjectConstResult (exe_scope,
+ clang_type,
+ name,
+ data_sp,
+ data_byte_order,
+ data_addr_size,
+ address))->GetSP();
+}
+
+ValueObjectSP
+ValueObjectConstResult::Create (ExecutionContextScope *exe_scope,
+ Value &value,
+ const ConstString &name)
+{
+ return (new ValueObjectConstResult (exe_scope, value, name))->GetSP();
+}
+
+ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ const lldb::DataBufferSP &data_sp,
+ lldb::ByteOrder data_byte_order,
+ uint32_t data_addr_size,
+ lldb::addr_t address) :
+ ValueObject (exe_scope),
+ m_type_name (),
+ m_byte_size (0),
+ m_impl(this, address)
+{
+ m_data.SetByteOrder(data_byte_order);
+ m_data.SetAddressByteSize(data_addr_size);
+ m_data.SetData(data_sp);
+ m_value.GetScalar() = (uintptr_t)data_sp->GetBytes();
+ m_value.SetValueType(Value::eValueTypeHostAddress);
+ //m_value.SetContext(Value::eContextTypeClangType, clang_type);
+ m_value.SetClangType (clang_type);
+ m_name = name;
+ SetIsConstant ();
+ SetValueIsValid(true);
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+}
+
+ValueObjectSP
+ValueObjectConstResult::Create (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ lldb::addr_t address,
+ AddressType address_type,
+ uint32_t addr_byte_size)
+{
+ return (new ValueObjectConstResult (exe_scope,
+ clang_type,
+ name,
+ address,
+ address_type,
+ addr_byte_size))->GetSP();
+}
+
+ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ lldb::addr_t address,
+ AddressType address_type,
+ uint32_t addr_byte_size) :
+ ValueObject (exe_scope),
+ m_type_name (),
+ m_byte_size (0),
+ m_impl(this, address)
+{
+ m_value.GetScalar() = address;
+ m_data.SetAddressByteSize(addr_byte_size);
+ m_value.GetScalar().GetData (m_data, addr_byte_size);
+ //m_value.SetValueType(Value::eValueTypeHostAddress);
+ switch (address_type)
+ {
+ case eAddressTypeInvalid: m_value.SetValueType(Value::eValueTypeScalar); break;
+ case eAddressTypeFile: m_value.SetValueType(Value::eValueTypeFileAddress); break;
+ case eAddressTypeLoad: m_value.SetValueType(Value::eValueTypeLoadAddress); break;
+ case eAddressTypeHost: m_value.SetValueType(Value::eValueTypeHostAddress); break;
+ }
+// m_value.SetContext(Value::eContextTypeClangType, clang_type);
+ m_value.SetClangType (clang_type);
+ m_name = name;
+ SetIsConstant ();
+ SetValueIsValid(true);
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+}
+
+ValueObjectSP
+ValueObjectConstResult::Create
+(
+ ExecutionContextScope *exe_scope,
+ const Error& error
+)
+{
+ return (new ValueObjectConstResult (exe_scope,
+ error))->GetSP();
+}
+
+ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const Error& error) :
+ ValueObject (exe_scope),
+ m_type_name (),
+ m_byte_size (0),
+ m_impl(this)
+{
+ m_error = error;
+ SetIsConstant ();
+}
+
+ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const Value &value,
+ const ConstString &name) :
+ ValueObject (exe_scope),
+ m_type_name (),
+ m_byte_size (0),
+ m_impl(this)
+{
+ m_value = value;
+ m_value.GetData(m_data);
+}
+
+ValueObjectConstResult::~ValueObjectConstResult()
+{
+}
+
+ClangASTType
+ValueObjectConstResult::GetClangTypeImpl()
+{
+ return m_value.GetClangType();
+}
+
+lldb::ValueType
+ValueObjectConstResult::GetValueType() const
+{
+ return eValueTypeConstResult;
+}
+
+uint64_t
+ValueObjectConstResult::GetByteSize()
+{
+ if (m_byte_size == 0)
+ m_byte_size = GetClangType().GetByteSize();
+ return m_byte_size;
+}
+
+void
+ValueObjectConstResult::SetByteSize (size_t size)
+{
+ m_byte_size = size;
+}
+
+size_t
+ValueObjectConstResult::CalculateNumChildren()
+{
+ return GetClangType().GetNumChildren (true);
+}
+
+ConstString
+ValueObjectConstResult::GetTypeName()
+{
+ if (m_type_name.IsEmpty())
+ m_type_name = GetClangType().GetConstTypeName ();
+ return m_type_name;
+}
+
+bool
+ValueObjectConstResult::UpdateValue ()
+{
+ // Const value is always valid
+ SetValueIsValid (true);
+ return true;
+}
+
+
+bool
+ValueObjectConstResult::IsInScope ()
+{
+ // A const result value is always in scope since it serializes all
+ // information needed to contain the constant value.
+ return true;
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResult::Dereference (Error &error)
+{
+ return m_impl.Dereference(error);
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResult::GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type, bool can_create)
+{
+ return m_impl.GetSyntheticChildAtOffset(offset, type, can_create);
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResult::AddressOf (Error &error)
+{
+ return m_impl.AddressOf(error);
+}
+
+lldb::addr_t
+ValueObjectConstResult::GetAddressOf (bool scalar_is_load_address,
+ AddressType *address_type)
+{
+ return m_impl.GetAddressOf(scalar_is_load_address, address_type);
+}
+
+ValueObject *
+ValueObjectConstResult::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ return m_impl.CreateChildAtIndex(idx, synthetic_array_member, synthetic_index);
+}
+
+size_t
+ValueObjectConstResult::GetPointeeData (DataExtractor& data,
+ uint32_t item_idx,
+ uint32_t item_count)
+{
+ return m_impl.GetPointeeData(data, item_idx, item_count);
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResult::GetDynamicValue (lldb::DynamicValueType use_dynamic)
+{
+ // Always recalculate dynamic values for const results as the memory that
+ // they might point to might have changed at any time.
+ if (use_dynamic != eNoDynamicValues)
+ {
+ if (!IsDynamic())
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process && process->IsPossibleDynamicValue(*this))
+ m_dynamic_value = new ValueObjectDynamicValue (*this, use_dynamic);
+ }
+ if (m_dynamic_value)
+ return m_dynamic_value->GetSP();
+ }
+ return ValueObjectSP();
+}
+
diff --git a/source/Core/ValueObjectConstResultChild.cpp b/source/Core/ValueObjectConstResultChild.cpp
new file mode 100644
index 0000000..64425ea
--- /dev/null
+++ b/source/Core/ValueObjectConstResultChild.cpp
@@ -0,0 +1,80 @@
+//===-- ValueObjectConstResultChild.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/ValueObjectConstResultChild.h"
+
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectList.h"
+
+#include "lldb/Symbol/ClangASTContext.h"
+
+using namespace lldb_private;
+
+ValueObjectConstResultChild::ValueObjectConstResultChild
+(
+ ValueObject &parent,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ uint32_t byte_size,
+ int32_t byte_offset,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset,
+ bool is_base_class,
+ bool is_deref_of_parent
+) :
+ ValueObjectChild (parent,
+ clang_type,
+ name,
+ byte_size,
+ byte_offset,
+ bitfield_bit_size,
+ bitfield_bit_offset,
+ is_base_class,
+ is_deref_of_parent,
+ eAddressTypeLoad),
+ m_impl(this)
+{
+ m_name = name;
+}
+
+ValueObjectConstResultChild::~ValueObjectConstResultChild()
+{
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResultChild::Dereference (Error &error)
+{
+ return m_impl.Dereference(error);
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResultChild::GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type, bool can_create)
+{
+ return m_impl.GetSyntheticChildAtOffset(offset, type, can_create);
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResultChild::AddressOf (Error &error)
+{
+ return m_impl.AddressOf(error);
+}
+
+ValueObject *
+ValueObjectConstResultChild::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ return m_impl.CreateChildAtIndex(idx, synthetic_array_member, synthetic_index);
+}
+
+size_t
+ValueObjectConstResultChild::GetPointeeData (DataExtractor& data,
+ uint32_t item_idx,
+ uint32_t item_count)
+{
+ return m_impl.GetPointeeData(data, item_idx, item_count);
+}
diff --git a/source/Core/ValueObjectConstResultImpl.cpp b/source/Core/ValueObjectConstResultImpl.cpp
new file mode 100644
index 0000000..e0757f6
--- /dev/null
+++ b/source/Core/ValueObjectConstResultImpl.cpp
@@ -0,0 +1,236 @@
+//===-- ValueObjectConstResultImpl.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/ValueObjectConstResultImpl.h"
+
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectConstResultChild.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// this macro enables a simpler implementation for some method calls in this object that relies only upon
+// ValueObject knowning how to set the address type of its children correctly. the alternative implementation
+// relies on being able to create a target copy of the frozen object, which makes it less bug-prone but less
+// efficient as well. once we are confident the faster implementation is bug-free, this macro (and the slower
+// implementations) can go
+#define TRIVIAL_IMPL 1
+
+ValueObjectConstResultImpl::ValueObjectConstResultImpl (ValueObject* valobj,
+ lldb::addr_t live_address) :
+ m_impl_backend(valobj),
+ m_live_address(live_address),
+ m_live_address_type(eAddressTypeLoad),
+ m_load_addr_backend(),
+ m_address_of_backend()
+{
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResultImpl::DerefOnTarget()
+{
+ if (m_load_addr_backend.get() == NULL)
+ {
+ lldb::addr_t tgt_address = m_impl_backend->GetPointerValue();
+ ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
+ m_load_addr_backend = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
+ m_impl_backend->GetClangType(),
+ m_impl_backend->GetName(),
+ tgt_address,
+ eAddressTypeLoad,
+ exe_ctx.GetAddressByteSize());
+ }
+ return m_load_addr_backend;
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResultImpl::Dereference (Error &error)
+{
+ if (m_impl_backend == NULL)
+ return lldb::ValueObjectSP();
+
+#if defined (TRIVIAL_IMPL) && TRIVIAL_IMPL == 1
+ return m_impl_backend->ValueObject::Dereference(error);
+#else
+ m_impl_backend->UpdateValueIfNeeded(false);
+
+ if (NeedsDerefOnTarget())
+ return DerefOnTarget()->Dereference(error);
+ else
+ return m_impl_backend->ValueObject::Dereference(error);
+#endif
+}
+
+ValueObject *
+ValueObjectConstResultImpl::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ if (m_impl_backend == NULL)
+ return NULL;
+
+ m_impl_backend->UpdateValueIfNeeded(false);
+
+ ValueObjectConstResultChild *valobj = NULL;
+
+ bool omit_empty_base_classes = true;
+ bool ignore_array_bounds = synthetic_array_member;
+ std::string child_name_str;
+ uint32_t child_byte_size = 0;
+ int32_t child_byte_offset = 0;
+ uint32_t child_bitfield_bit_size = 0;
+ uint32_t child_bitfield_bit_offset = 0;
+ bool child_is_base_class = false;
+ bool child_is_deref_of_parent = false;
+
+ const bool transparent_pointers = synthetic_array_member == false;
+ ClangASTType clang_type = m_impl_backend->GetClangType();
+ ClangASTType child_clang_type;
+
+ ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
+
+ child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
+ m_impl_backend->GetName().GetCString(),
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ ignore_array_bounds,
+ child_name_str,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent);
+ if (child_clang_type && child_byte_size)
+ {
+ if (synthetic_index)
+ child_byte_offset += child_byte_size * synthetic_index;
+
+ ConstString child_name;
+ if (!child_name_str.empty())
+ child_name.SetCString (child_name_str.c_str());
+
+ valobj = new ValueObjectConstResultChild (*m_impl_backend,
+ child_clang_type,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent);
+ valobj->m_impl.SetLiveAddress(m_live_address+child_byte_offset);
+ }
+
+ return valobj;
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResultImpl::GetSyntheticChildAtOffset (uint32_t offset, const ClangASTType& type, bool can_create)
+{
+ if (m_impl_backend == NULL)
+ return lldb::ValueObjectSP();
+
+#if defined (TRIVIAL_IMPL) && TRIVIAL_IMPL == 1
+ return m_impl_backend->ValueObject::GetSyntheticChildAtOffset(offset, type, can_create);
+#else
+ m_impl_backend->UpdateValueIfNeeded(false);
+
+ if (NeedsDerefOnTarget())
+ return DerefOnTarget()->GetSyntheticChildAtOffset(offset, type, can_create);
+ else
+ return m_impl_backend->ValueObject::GetSyntheticChildAtOffset(offset, type, can_create);
+#endif
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResultImpl::AddressOf (Error &error)
+{
+ if (m_address_of_backend.get() != NULL)
+ return m_address_of_backend;
+
+ if (m_impl_backend == NULL)
+ return lldb::ValueObjectSP();
+ if (m_live_address != LLDB_INVALID_ADDRESS)
+ {
+ ClangASTType clang_type(m_impl_backend->GetClangType());
+
+ lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&m_live_address,sizeof(lldb::addr_t)));
+
+ std::string new_name("&");
+ new_name.append(m_impl_backend->GetName().AsCString(""));
+ ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
+ m_address_of_backend = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
+ clang_type.GetPointerType(),
+ ConstString(new_name.c_str()),
+ buffer,
+ lldb::endian::InlHostByteOrder(),
+ exe_ctx.GetAddressByteSize());
+
+ m_address_of_backend->GetValue().SetValueType(Value::eValueTypeScalar);
+ m_address_of_backend->GetValue().GetScalar() = m_live_address;
+
+ return m_address_of_backend;
+ }
+ else
+ return lldb::ValueObjectSP();
+}
+
+lldb::addr_t
+ValueObjectConstResultImpl::GetAddressOf (bool scalar_is_load_address,
+ AddressType *address_type)
+{
+
+ if (m_impl_backend == NULL)
+ return 0;
+
+ if (m_live_address == LLDB_INVALID_ADDRESS)
+ {
+ return m_impl_backend->ValueObject::GetAddressOf (scalar_is_load_address,
+ address_type);
+ }
+
+ if (address_type)
+ *address_type = m_live_address_type;
+
+ return m_live_address;
+}
+
+size_t
+ValueObjectConstResultImpl::GetPointeeData (DataExtractor& data,
+ uint32_t item_idx,
+ uint32_t item_count)
+{
+ if (m_impl_backend == NULL)
+ return 0;
+#if defined (TRIVIAL_IMPL) && TRIVIAL_IMPL == 1
+ return m_impl_backend->ValueObject::GetPointeeData(data, item_idx, item_count);
+#else
+ m_impl_backend->UpdateValueIfNeeded(false);
+
+ if (NeedsDerefOnTarget() && m_impl_backend->IsPointerType())
+ return DerefOnTarget()->GetPointeeData(data, item_idx, item_count);
+ else
+ return m_impl_backend->ValueObject::GetPointeeData(data, item_idx, item_count);
+#endif
+}
diff --git a/source/Core/ValueObjectDynamicValue.cpp b/source/Core/ValueObjectDynamicValue.cpp
new file mode 100644
index 0000000..977cc4c
--- /dev/null
+++ b/source/Core/ValueObjectDynamicValue.cpp
@@ -0,0 +1,372 @@
+//===-- ValueObjectDynamicValue.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/ValueObjectDynamicValue.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb_private;
+
+ValueObjectDynamicValue::ValueObjectDynamicValue (ValueObject &parent, lldb::DynamicValueType use_dynamic) :
+ ValueObject(parent),
+ m_address (),
+ m_dynamic_type_info(),
+ m_use_dynamic (use_dynamic)
+{
+ SetName (parent.GetName());
+}
+
+ValueObjectDynamicValue::~ValueObjectDynamicValue()
+{
+ m_owning_valobj_sp.reset();
+}
+
+ClangASTType
+ValueObjectDynamicValue::GetClangTypeImpl ()
+{
+ if (m_dynamic_type_info.HasTypeSP())
+ return m_value.GetClangType();
+ else
+ return m_parent->GetClangType();
+}
+
+ConstString
+ValueObjectDynamicValue::GetTypeName()
+{
+ const bool success = UpdateValueIfNeeded(false);
+ if (success)
+ {
+ if (m_dynamic_type_info.HasTypeSP())
+ return GetClangType().GetConstTypeName();
+ if (m_dynamic_type_info.HasName())
+ return m_dynamic_type_info.GetName();
+ }
+ return m_parent->GetTypeName();
+}
+
+ConstString
+ValueObjectDynamicValue::GetQualifiedTypeName()
+{
+ const bool success = UpdateValueIfNeeded(false);
+ if (success)
+ {
+ if (m_dynamic_type_info.HasTypeSP())
+ return GetClangType().GetConstQualifiedTypeName ();
+ if (m_dynamic_type_info.HasName())
+ return m_dynamic_type_info.GetName();
+ }
+ return m_parent->GetTypeName();
+}
+
+size_t
+ValueObjectDynamicValue::CalculateNumChildren()
+{
+ const bool success = UpdateValueIfNeeded(false);
+ if (success && m_dynamic_type_info.HasTypeSP())
+ return GetClangType().GetNumChildren (true);
+ else
+ return m_parent->GetNumChildren();
+}
+
+uint64_t
+ValueObjectDynamicValue::GetByteSize()
+{
+ const bool success = UpdateValueIfNeeded(false);
+ if (success && m_dynamic_type_info.HasTypeSP())
+ return m_value.GetValueByteSize(NULL);
+ else
+ return m_parent->GetByteSize();
+}
+
+lldb::ValueType
+ValueObjectDynamicValue::GetValueType() const
+{
+ return m_parent->GetValueType();
+}
+
+bool
+ValueObjectDynamicValue::UpdateValue ()
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ if (!m_parent->UpdateValueIfNeeded(false))
+ {
+ // The dynamic value failed to get an error, pass the error along
+ if (m_error.Success() && m_parent->GetError().Fail())
+ m_error = m_parent->GetError();
+ return false;
+ }
+
+ // Setting our type_sp to NULL will route everything back through our
+ // parent which is equivalent to not using dynamic values.
+ if (m_use_dynamic == lldb::eNoDynamicValues)
+ {
+ m_dynamic_type_info.Clear();
+ return true;
+ }
+
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());
+ m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
+ }
+
+ // First make sure our Type and/or Address haven't changed:
+ Process *process = exe_ctx.GetProcessPtr();
+ if (!process)
+ return false;
+
+ TypeAndOrName class_type_or_name;
+ Address dynamic_address;
+ bool found_dynamic_type = false;
+
+ lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage();
+ if (known_type != lldb::eLanguageTypeUnknown && known_type != lldb::eLanguageTypeC)
+ {
+ LanguageRuntime *runtime = process->GetLanguageRuntime (known_type);
+ if (runtime)
+ found_dynamic_type = runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address);
+ }
+ else
+ {
+ LanguageRuntime *cpp_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeC_plus_plus);
+ if (cpp_runtime)
+ found_dynamic_type = cpp_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address);
+
+ if (!found_dynamic_type)
+ {
+ LanguageRuntime *objc_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeObjC);
+ if (objc_runtime)
+ found_dynamic_type = objc_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address);
+ }
+ }
+
+ // Getting the dynamic value may have run the program a bit, and so marked us as needing updating, but we really
+ // don't...
+
+ m_update_point.SetUpdated();
+
+ // If we don't have a dynamic type, then make ourselves just a echo of our parent.
+ // Or we could return false, and make ourselves an echo of our parent?
+ if (!found_dynamic_type)
+ {
+ if (m_dynamic_type_info)
+ SetValueDidChange(true);
+ ClearDynamicTypeInformation();
+ m_dynamic_type_info.Clear();
+ m_value = m_parent->GetValue();
+ m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
+ return m_error.Success();
+ }
+
+ Value old_value(m_value);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+
+ bool has_changed_type = false;
+
+ if (!m_dynamic_type_info)
+ {
+ m_dynamic_type_info = class_type_or_name;
+ has_changed_type = true;
+ }
+ else if (class_type_or_name != m_dynamic_type_info)
+ {
+ // We are another type, we need to tear down our children...
+ m_dynamic_type_info = class_type_or_name;
+ SetValueDidChange (true);
+ has_changed_type = true;
+ }
+
+ if (has_changed_type)
+ ClearDynamicTypeInformation ();
+
+ if (!m_address.IsValid() || m_address != dynamic_address)
+ {
+ if (m_address.IsValid())
+ SetValueDidChange (true);
+
+ // We've moved, so we should be fine...
+ m_address = dynamic_address;
+ lldb::TargetSP target_sp (GetTargetSP());
+ lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());
+ m_value.GetScalar() = load_address;
+ }
+
+ ClangASTType corrected_type;
+ if (m_dynamic_type_info.HasTypeSP())
+ {
+ // The type will always be the type of the dynamic object. If our parent's type was a pointer,
+ // then our type should be a pointer to the type of the dynamic object. If a reference, then the original type
+ // should be okay...
+ ClangASTType orig_type = m_dynamic_type_info.GetTypeSP()->GetClangForwardType();
+ corrected_type = orig_type;
+ if (m_parent->IsPointerType())
+ corrected_type = orig_type.GetPointerType ();
+ else if (m_parent->IsPointerOrReferenceType())
+ corrected_type = orig_type.GetLValueReferenceType ();
+ }
+ else /*if (m_dynamic_type_info.HasName())*/
+ {
+ // If we are here we need to adjust our dynamic type name to include the correct & or * symbol
+ std::string type_name_buf (m_dynamic_type_info.GetName().GetCString());
+ if (m_parent->IsPointerType())
+ type_name_buf.append(" *");
+ else if (m_parent->IsPointerOrReferenceType())
+ type_name_buf.append(" &");
+ corrected_type = m_parent->GetClangType();
+ m_dynamic_type_info.SetName(type_name_buf.c_str());
+ }
+
+ //m_value.SetContext (Value::eContextTypeClangType, corrected_type);
+ m_value.SetClangType (corrected_type);
+
+ // Our address is the location of the dynamic type stored in memory. It isn't a load address,
+ // because we aren't pointing to the LOCATION that stores the pointer to us, we're pointing to us...
+ m_value.SetValueType(Value::eValueTypeScalar);
+
+ if (has_changed_type && log)
+ log->Printf("[%s %p] has a new dynamic type %s",
+ GetName().GetCString(),
+ this,
+ GetTypeName().GetCString());
+
+ if (m_address.IsValid() && m_dynamic_type_info)
+ {
+ // The variable value is in the Scalar value inside the m_value.
+ // We can point our m_data right to it.
+ m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
+ if (m_error.Success())
+ {
+ if (GetClangType().IsAggregateType ())
+ {
+ // this value object represents an aggregate type whose
+ // children have values, but this object does not. So we
+ // say we are changed if our location has changed.
+ SetValueDidChange (m_value.GetValueType() != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar());
+ }
+
+ SetValueIsValid (true);
+ return true;
+ }
+ }
+
+ // We get here if we've failed above...
+ SetValueIsValid (false);
+ return false;
+}
+
+
+
+bool
+ValueObjectDynamicValue::IsInScope ()
+{
+ return m_parent->IsInScope();
+}
+
+bool
+ValueObjectDynamicValue::SetValueFromCString (const char *value_str, Error& error)
+{
+ if (!UpdateValueIfNeeded(false))
+ {
+ error.SetErrorString("unable to read value");
+ return false;
+ }
+
+ uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);
+ uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);
+
+ if (my_value == UINT64_MAX || parent_value == UINT64_MAX)
+ {
+ error.SetErrorString("unable to read value");
+ return false;
+ }
+
+ // if we are at an offset from our parent, in order to set ourselves correctly we would need
+ // to change the new value so that it refers to the correct dynamic type. we choose not to deal
+ // with that - if anything more than a value overwrite is required, you should be using the
+ // expression parser instead of the value editing facility
+ if (my_value != parent_value)
+ {
+ // but NULL'ing out a value should always be allowed
+ if (strcmp(value_str,"0"))
+ {
+ error.SetErrorString("unable to modify dynamic value, use 'expression' command");
+ return false;
+ }
+ }
+
+ bool ret_val = m_parent->SetValueFromCString(value_str,error);
+ SetNeedsUpdate();
+ return ret_val;
+}
+
+bool
+ValueObjectDynamicValue::SetData (DataExtractor &data, Error &error)
+{
+ if (!UpdateValueIfNeeded(false))
+ {
+ error.SetErrorString("unable to read value");
+ return false;
+ }
+
+ uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);
+ uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);
+
+ if (my_value == UINT64_MAX || parent_value == UINT64_MAX)
+ {
+ error.SetErrorString("unable to read value");
+ return false;
+ }
+
+ // if we are at an offset from our parent, in order to set ourselves correctly we would need
+ // to change the new value so that it refers to the correct dynamic type. we choose not to deal
+ // with that - if anything more than a value overwrite is required, you should be using the
+ // expression parser instead of the value editing facility
+ if (my_value != parent_value)
+ {
+ // but NULL'ing out a value should always be allowed
+ lldb::offset_t offset = 0;
+
+ if (data.GetPointer(&offset) != 0)
+ {
+ error.SetErrorString("unable to modify dynamic value, use 'expression' command");
+ return false;
+ }
+ }
+
+ bool ret_val = m_parent->SetData(data, error);
+ SetNeedsUpdate();
+ return ret_val;
+}
diff --git a/source/Core/ValueObjectList.cpp b/source/Core/ValueObjectList.cpp
new file mode 100644
index 0000000..180d4a0
--- /dev/null
+++ b/source/Core/ValueObjectList.cpp
@@ -0,0 +1,166 @@
+//===-- ValueObjectList.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/ValueObjectList.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Core/ValueObjectRegister.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ValueObjectList::ValueObjectList () :
+ m_value_objects()
+{
+}
+
+ValueObjectList::ValueObjectList (const ValueObjectList &rhs) :
+ m_value_objects(rhs.m_value_objects)
+{
+}
+
+
+ValueObjectList::~ValueObjectList ()
+{
+}
+
+const ValueObjectList &
+ValueObjectList::operator = (const ValueObjectList &rhs)
+{
+ if (this != &rhs)
+ m_value_objects = rhs.m_value_objects;
+ return *this;
+}
+
+void
+ValueObjectList::Append (const ValueObjectSP &val_obj_sp)
+{
+ m_value_objects.push_back(val_obj_sp);
+}
+
+void
+ValueObjectList::Append (const ValueObjectList &valobj_list)
+{
+ std::copy(valobj_list.m_value_objects.begin(), // source begin
+ valobj_list.m_value_objects.end(), // source end
+ back_inserter(m_value_objects)); // destination
+
+}
+
+
+size_t
+ValueObjectList::GetSize() const
+{
+ return m_value_objects.size();
+}
+
+void
+ValueObjectList::Resize (size_t size)
+{
+ m_value_objects.resize (size);
+}
+
+lldb::ValueObjectSP
+ValueObjectList::GetValueObjectAtIndex (size_t idx)
+{
+ lldb::ValueObjectSP valobj_sp;
+ if (idx < m_value_objects.size())
+ valobj_sp = m_value_objects[idx];
+ return valobj_sp;
+}
+
+lldb::ValueObjectSP
+ValueObjectList::RemoveValueObjectAtIndex (size_t idx)
+{
+ lldb::ValueObjectSP valobj_sp;
+ if (idx < m_value_objects.size())
+ {
+ valobj_sp = m_value_objects[idx];
+ m_value_objects.erase (m_value_objects.begin() + idx);
+ }
+ return valobj_sp;
+}
+
+void
+ValueObjectList::SetValueObjectAtIndex (size_t idx, const ValueObjectSP &valobj_sp)
+{
+ if (idx >= m_value_objects.size())
+ m_value_objects.resize (idx + 1);
+ m_value_objects[idx] = valobj_sp;
+}
+
+ValueObjectSP
+ValueObjectList::FindValueObjectByValueName (const char *name)
+{
+ ConstString name_const_str(name);
+ ValueObjectSP val_obj_sp;
+ collection::iterator pos, end = m_value_objects.end();
+ for (pos = m_value_objects.begin(); pos != end; ++pos)
+ {
+ ValueObject *valobj = (*pos).get();
+ if (valobj && valobj->GetName() == name_const_str)
+ {
+ val_obj_sp = *pos;
+ break;
+ }
+ }
+ return val_obj_sp;
+}
+
+ValueObjectSP
+ValueObjectList::FindValueObjectByUID (lldb::user_id_t uid)
+{
+ ValueObjectSP valobj_sp;
+ collection::iterator pos, end = m_value_objects.end();
+
+ for (pos = m_value_objects.begin(); pos != end; ++pos)
+ {
+ // Watch out for NULL objects in our list as the list
+ // might get resized to a specific size and lazily filled in
+ ValueObject *valobj = (*pos).get();
+ if (valobj && valobj->GetID() == uid)
+ {
+ valobj_sp = *pos;
+ break;
+ }
+ }
+ return valobj_sp;
+}
+
+
+ValueObjectSP
+ValueObjectList::FindValueObjectByPointer (ValueObject *find_valobj)
+{
+ ValueObjectSP valobj_sp;
+ collection::iterator pos, end = m_value_objects.end();
+
+ for (pos = m_value_objects.begin(); pos != end; ++pos)
+ {
+ ValueObject *valobj = (*pos).get();
+ if (valobj && valobj == find_valobj)
+ {
+ valobj_sp = *pos;
+ break;
+ }
+ }
+ return valobj_sp;
+}
+
+void
+ValueObjectList::Swap (ValueObjectList &value_object_list)
+{
+ m_value_objects.swap (value_object_list.m_value_objects);
+}
diff --git a/source/Core/ValueObjectMemory.cpp b/source/Core/ValueObjectMemory.cpp
new file mode 100644
index 0000000..42fd0e8
--- /dev/null
+++ b/source/Core/ValueObjectMemory.cpp
@@ -0,0 +1,275 @@
+//===-- ValueObjectMemory.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/ValueObjectMemory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ValueObjectSP
+ValueObjectMemory::Create (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ lldb::TypeSP &type_sp)
+{
+ return (new ValueObjectMemory (exe_scope, name, address, type_sp))->GetSP();
+}
+
+ValueObjectSP
+ValueObjectMemory::Create (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ const ClangASTType &ast_type)
+{
+ return (new ValueObjectMemory (exe_scope, name, address, ast_type))->GetSP();
+}
+
+ValueObjectMemory::ValueObjectMemory (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ lldb::TypeSP &type_sp) :
+ ValueObject(exe_scope),
+ m_address (address),
+ m_type_sp(type_sp),
+ m_clang_type()
+{
+ // Do not attempt to construct one of these objects with no variable!
+ assert (m_type_sp.get() != NULL);
+ SetName (ConstString(name));
+ m_value.SetContext(Value::eContextTypeLLDBType, m_type_sp.get());
+ TargetSP target_sp (GetTargetSP());
+ lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());
+ if (load_address != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeLoadAddress);
+ m_value.GetScalar() = load_address;
+ }
+ else
+ {
+ lldb::addr_t file_address = m_address.GetFileAddress();
+ if (file_address != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeFileAddress);
+ m_value.GetScalar() = file_address;
+ }
+ else
+ {
+ m_value.GetScalar() = m_address.GetOffset();
+ m_value.SetValueType (Value::eValueTypeScalar);
+ }
+ }
+}
+
+ValueObjectMemory::ValueObjectMemory (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ const ClangASTType &ast_type) :
+ ValueObject(exe_scope),
+ m_address (address),
+ m_type_sp(),
+ m_clang_type(ast_type)
+{
+ // Do not attempt to construct one of these objects with no variable!
+ assert (m_clang_type.GetASTContext());
+ assert (m_clang_type.GetOpaqueQualType());
+
+ TargetSP target_sp (GetTargetSP());
+
+ SetName (ConstString(name));
+// m_value.SetContext(Value::eContextTypeClangType, m_clang_type.GetOpaqueQualType());
+ m_value.SetClangType(m_clang_type);
+ lldb::addr_t load_address = m_address.GetLoadAddress (target_sp.get());
+ if (load_address != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeLoadAddress);
+ m_value.GetScalar() = load_address;
+ }
+ else
+ {
+ lldb::addr_t file_address = m_address.GetFileAddress();
+ if (file_address != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeFileAddress);
+ m_value.GetScalar() = file_address;
+ }
+ else
+ {
+ m_value.GetScalar() = m_address.GetOffset();
+ m_value.SetValueType (Value::eValueTypeScalar);
+ }
+ }
+}
+
+ValueObjectMemory::~ValueObjectMemory()
+{
+}
+
+ClangASTType
+ValueObjectMemory::GetClangTypeImpl ()
+{
+ if (m_type_sp)
+ return m_type_sp->GetClangForwardType();
+ return m_clang_type;
+}
+
+ConstString
+ValueObjectMemory::GetTypeName()
+{
+ if (m_type_sp)
+ return m_type_sp->GetName();
+ return m_clang_type.GetConstTypeName();
+}
+
+size_t
+ValueObjectMemory::CalculateNumChildren()
+{
+ if (m_type_sp)
+ return m_type_sp->GetNumChildren(true);
+ const bool omit_empty_base_classes = true;
+ return m_clang_type.GetNumChildren (omit_empty_base_classes);
+}
+
+uint64_t
+ValueObjectMemory::GetByteSize()
+{
+ if (m_type_sp)
+ return m_type_sp->GetByteSize();
+ return m_clang_type.GetByteSize ();
+}
+
+lldb::ValueType
+ValueObjectMemory::GetValueType() const
+{
+ // RETHINK: Should this be inherited from somewhere?
+ return lldb::eValueTypeVariableGlobal;
+}
+
+bool
+ValueObjectMemory::UpdateValue ()
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());
+ m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
+ }
+
+ Value old_value(m_value);
+ if (m_address.IsValid())
+ {
+ Value::ValueType value_type = m_value.GetValueType();
+
+ switch (value_type)
+ {
+ default:
+ assert(!"Unhandled expression result value kind...");
+ break;
+
+ case Value::eValueTypeScalar:
+ // The variable value is in the Scalar value inside the m_value.
+ // We can point our m_data right to it.
+ m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
+ break;
+
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeHostAddress:
+ // The DWARF expression result was an address in the inferior
+ // process. If this variable is an aggregate type, we just need
+ // the address as the main value as all child variable objects
+ // will rely upon this location and add an offset and then read
+ // their own values as needed. If this variable is a simple
+ // type, we read all data for it into m_data.
+ // Make sure this type has a value before we try and read it
+
+ // If we have a file address, convert it to a load address if we can.
+ if (value_type == Value::eValueTypeFileAddress && exe_ctx.GetProcessPtr())
+ {
+ lldb::addr_t load_addr = m_address.GetLoadAddress(target);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeLoadAddress);
+ m_value.GetScalar() = load_addr;
+ }
+ }
+
+ if (GetClangType().IsAggregateType())
+ {
+ // this value object represents an aggregate type whose
+ // children have values, but this object does not. So we
+ // say we are changed if our location has changed.
+ SetValueDidChange (value_type != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar());
+ }
+ else
+ {
+ // Copy the Value and set the context to use our Variable
+ // so it can extract read its value into m_data appropriately
+ Value value(m_value);
+ if (m_type_sp)
+ value.SetContext(Value::eContextTypeLLDBType, m_type_sp.get());
+ else
+ {
+ //value.SetContext(Value::eContextTypeClangType, m_clang_type.GetOpaqueQualType());
+ value.SetClangType(m_clang_type);
+ }
+
+ m_error = value.GetValueAsData(&exe_ctx, m_data, 0, GetModule().get());
+ }
+ break;
+ }
+
+ SetValueIsValid (m_error.Success());
+ }
+ return m_error.Success();
+}
+
+
+
+bool
+ValueObjectMemory::IsInScope ()
+{
+ // FIXME: Maybe try to read the memory address, and if that works, then
+ // we are in scope?
+ return true;
+}
+
+
+lldb::ModuleSP
+ValueObjectMemory::GetModule()
+{
+ return m_address.GetModule();
+}
+
+
diff --git a/source/Core/ValueObjectRegister.cpp b/source/Core/ValueObjectRegister.cpp
new file mode 100644
index 0000000..4f21457
--- /dev/null
+++ b/source/Core/ValueObjectRegister.cpp
@@ -0,0 +1,431 @@
+//===-- ValueObjectRegister.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/ValueObjectRegister.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#pragma mark ValueObjectRegisterContext
+
+ValueObjectRegisterContext::ValueObjectRegisterContext (ValueObject &parent, RegisterContextSP &reg_ctx) :
+ ValueObject (parent),
+ m_reg_ctx_sp (reg_ctx)
+{
+ assert (reg_ctx);
+ m_name.SetCString("Registers");
+ SetValueIsValid (true);
+}
+
+ValueObjectRegisterContext::~ValueObjectRegisterContext()
+{
+}
+
+ClangASTType
+ValueObjectRegisterContext::GetClangTypeImpl ()
+{
+ return ClangASTType();
+}
+
+ConstString
+ValueObjectRegisterContext::GetTypeName()
+{
+ return ConstString();
+}
+
+ConstString
+ValueObjectRegisterContext::GetQualifiedTypeName()
+{
+ return ConstString();
+}
+
+size_t
+ValueObjectRegisterContext::CalculateNumChildren()
+{
+ return m_reg_ctx_sp->GetRegisterSetCount();
+}
+
+uint64_t
+ValueObjectRegisterContext::GetByteSize()
+{
+ return 0;
+}
+
+bool
+ValueObjectRegisterContext::UpdateValue ()
+{
+ m_error.Clear();
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame)
+ m_reg_ctx_sp = frame->GetRegisterContext();
+ else
+ m_reg_ctx_sp.reset();
+
+ if (m_reg_ctx_sp.get() == NULL)
+ {
+ SetValueIsValid (false);
+ m_error.SetErrorToGenericError();
+ }
+ else
+ SetValueIsValid (true);
+
+ return m_error.Success();
+}
+
+ValueObject *
+ValueObjectRegisterContext::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ ValueObject *new_valobj = NULL;
+
+ const size_t num_children = GetNumChildren();
+ if (idx < num_children)
+ {
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ new_valobj = new ValueObjectRegisterSet(exe_ctx.GetBestExecutionContextScope(), m_reg_ctx_sp, idx);
+ }
+
+ return new_valobj;
+}
+
+
+#pragma mark -
+#pragma mark ValueObjectRegisterSet
+
+ValueObjectSP
+ValueObjectRegisterSet::Create (ExecutionContextScope *exe_scope, lldb::RegisterContextSP &reg_ctx_sp, uint32_t set_idx)
+{
+ return (new ValueObjectRegisterSet (exe_scope, reg_ctx_sp, set_idx))->GetSP();
+}
+
+
+ValueObjectRegisterSet::ValueObjectRegisterSet (ExecutionContextScope *exe_scope, lldb::RegisterContextSP &reg_ctx, uint32_t reg_set_idx) :
+ ValueObject (exe_scope),
+ m_reg_ctx_sp (reg_ctx),
+ m_reg_set (NULL),
+ m_reg_set_idx (reg_set_idx)
+{
+ assert (reg_ctx);
+ m_reg_set = reg_ctx->GetRegisterSet(m_reg_set_idx);
+ if (m_reg_set)
+ {
+ m_name.SetCString (m_reg_set->name);
+ }
+}
+
+ValueObjectRegisterSet::~ValueObjectRegisterSet()
+{
+}
+
+ClangASTType
+ValueObjectRegisterSet::GetClangTypeImpl ()
+{
+ return ClangASTType();
+}
+
+ConstString
+ValueObjectRegisterSet::GetTypeName()
+{
+ return ConstString();
+}
+
+ConstString
+ValueObjectRegisterSet::GetQualifiedTypeName()
+{
+ return ConstString();
+}
+
+size_t
+ValueObjectRegisterSet::CalculateNumChildren()
+{
+ const RegisterSet *reg_set = m_reg_ctx_sp->GetRegisterSet(m_reg_set_idx);
+ if (reg_set)
+ return reg_set->num_registers;
+ return 0;
+}
+
+uint64_t
+ValueObjectRegisterSet::GetByteSize()
+{
+ return 0;
+}
+
+bool
+ValueObjectRegisterSet::UpdateValue ()
+{
+ m_error.Clear();
+ SetValueDidChange (false);
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame == NULL)
+ m_reg_ctx_sp.reset();
+ else
+ {
+ m_reg_ctx_sp = frame->GetRegisterContext ();
+ if (m_reg_ctx_sp)
+ {
+ const RegisterSet *reg_set = m_reg_ctx_sp->GetRegisterSet (m_reg_set_idx);
+ if (reg_set == NULL)
+ m_reg_ctx_sp.reset();
+ else if (m_reg_set != reg_set)
+ {
+ SetValueDidChange (true);
+ m_name.SetCString(reg_set->name);
+ }
+ }
+ }
+ if (m_reg_ctx_sp)
+ {
+ SetValueIsValid (true);
+ }
+ else
+ {
+ SetValueIsValid (false);
+ m_error.SetErrorToGenericError ();
+ m_children.Clear();
+ }
+ return m_error.Success();
+}
+
+
+ValueObject *
+ValueObjectRegisterSet::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ ValueObject *valobj = NULL;
+ if (m_reg_ctx_sp && m_reg_set)
+ {
+ const size_t num_children = GetNumChildren();
+ if (idx < num_children)
+ valobj = new ValueObjectRegister(*this, m_reg_ctx_sp, m_reg_set->registers[idx]);
+ }
+ return valobj;
+}
+
+lldb::ValueObjectSP
+ValueObjectRegisterSet::GetChildMemberWithName (const ConstString &name, bool can_create)
+{
+ ValueObject *valobj = NULL;
+ if (m_reg_ctx_sp && m_reg_set)
+ {
+ const RegisterInfo *reg_info = m_reg_ctx_sp->GetRegisterInfoByName (name.AsCString());
+ if (reg_info != NULL)
+ valobj = new ValueObjectRegister(*this, m_reg_ctx_sp, reg_info->kinds[eRegisterKindLLDB]);
+ }
+ if (valobj)
+ return valobj->GetSP();
+ else
+ return ValueObjectSP();
+}
+
+size_t
+ValueObjectRegisterSet::GetIndexOfChildWithName (const ConstString &name)
+{
+ if (m_reg_ctx_sp && m_reg_set)
+ {
+ const RegisterInfo *reg_info = m_reg_ctx_sp->GetRegisterInfoByName (name.AsCString());
+ if (reg_info != NULL)
+ return reg_info->kinds[eRegisterKindLLDB];
+ }
+ return UINT32_MAX;
+}
+
+#pragma mark -
+#pragma mark ValueObjectRegister
+
+void
+ValueObjectRegister::ConstructObject (uint32_t reg_num)
+{
+ const RegisterInfo *reg_info = m_reg_ctx_sp->GetRegisterInfoAtIndex (reg_num);
+ if (reg_info)
+ {
+ m_reg_info = *reg_info;
+ if (reg_info->name)
+ m_name.SetCString(reg_info->name);
+ else if (reg_info->alt_name)
+ m_name.SetCString(reg_info->alt_name);
+ }
+}
+
+ValueObjectRegister::ValueObjectRegister (ValueObject &parent, lldb::RegisterContextSP &reg_ctx_sp, uint32_t reg_num) :
+ ValueObject (parent),
+ m_reg_ctx_sp (reg_ctx_sp),
+ m_reg_info (),
+ m_reg_value (),
+ m_type_name (),
+ m_clang_type ()
+{
+ assert (reg_ctx_sp.get());
+ ConstructObject(reg_num);
+}
+
+ValueObjectSP
+ValueObjectRegister::Create (ExecutionContextScope *exe_scope, lldb::RegisterContextSP &reg_ctx_sp, uint32_t reg_num)
+{
+ return (new ValueObjectRegister (exe_scope, reg_ctx_sp, reg_num))->GetSP();
+}
+
+ValueObjectRegister::ValueObjectRegister (ExecutionContextScope *exe_scope, lldb::RegisterContextSP &reg_ctx, uint32_t reg_num) :
+ ValueObject (exe_scope),
+ m_reg_ctx_sp (reg_ctx),
+ m_reg_info (),
+ m_reg_value (),
+ m_type_name (),
+ m_clang_type ()
+{
+ assert (reg_ctx);
+ ConstructObject(reg_num);
+}
+
+ValueObjectRegister::~ValueObjectRegister()
+{
+}
+
+ClangASTType
+ValueObjectRegister::GetClangTypeImpl ()
+{
+ if (!m_clang_type.IsValid())
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ Module *exe_module = target->GetExecutableModulePointer();
+ if (exe_module)
+ {
+ m_clang_type = exe_module->GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize (m_reg_info.encoding,
+ m_reg_info.byte_size * 8);
+ }
+ }
+ }
+ return m_clang_type;
+}
+
+ConstString
+ValueObjectRegister::GetTypeName()
+{
+ if (m_type_name.IsEmpty())
+ m_type_name = GetClangType().GetConstTypeName ();
+ return m_type_name;
+}
+
+size_t
+ValueObjectRegister::CalculateNumChildren()
+{
+ return GetClangType().GetNumChildren(true);
+}
+
+uint64_t
+ValueObjectRegister::GetByteSize()
+{
+ return m_reg_info.byte_size;
+}
+
+bool
+ValueObjectRegister::UpdateValue ()
+{
+ m_error.Clear();
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame == NULL)
+ {
+ m_reg_ctx_sp.reset();
+ m_reg_value.Clear();
+ }
+
+
+ if (m_reg_ctx_sp)
+ {
+ if (m_reg_ctx_sp->ReadRegister (&m_reg_info, m_reg_value))
+ {
+ if (m_reg_value.GetData (m_data))
+ {
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ m_data.SetAddressByteSize(process->GetAddressByteSize());
+ m_value.SetContext(Value::eContextTypeRegisterInfo, (void *)&m_reg_info);
+ m_value.SetValueType(Value::eValueTypeHostAddress);
+ m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
+ SetValueIsValid (true);
+ return true;
+ }
+ }
+ }
+
+ SetValueIsValid (false);
+ m_error.SetErrorToGenericError ();
+ return false;
+}
+
+bool
+ValueObjectRegister::SetValueFromCString (const char *value_str, Error& error)
+{
+ // The new value will be in the m_data. Copy that into our register value.
+ error = m_reg_value.SetValueFromCString (&m_reg_info, value_str);
+ if (error.Success())
+ {
+ if (m_reg_ctx_sp->WriteRegister (&m_reg_info, m_reg_value))
+ {
+ SetNeedsUpdate();
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+}
+
+bool
+ValueObjectRegister::SetData (DataExtractor &data, Error &error)
+{
+ error = m_reg_value.SetValueFromData(&m_reg_info, data, 0, false);
+ if (error.Success())
+ {
+ if (m_reg_ctx_sp->WriteRegister (&m_reg_info, m_reg_value))
+ {
+ SetNeedsUpdate();
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+}
+
+bool
+ValueObjectRegister::ResolveValue (Scalar &scalar)
+{
+ if (UpdateValueIfNeeded(false)) // make sure that you are up to date before returning anything
+ return m_reg_value.GetScalarValue(scalar);
+ return false;
+}
+
+void
+ValueObjectRegister::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat epformat)
+{
+ s.Printf("$%s", m_reg_info.name);
+}
+
+
diff --git a/source/Core/ValueObjectSyntheticFilter.cpp b/source/Core/ValueObjectSyntheticFilter.cpp
new file mode 100644
index 0000000..522ca08
--- /dev/null
+++ b/source/Core/ValueObjectSyntheticFilter.cpp
@@ -0,0 +1,270 @@
+//===-- ValueObjectSyntheticFilter.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/lldb-python.h"
+
+#include "lldb/Core/ValueObjectSyntheticFilter.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/FormatClasses.h"
+
+using namespace lldb_private;
+
+class DummySyntheticFrontEnd : public SyntheticChildrenFrontEnd
+{
+public:
+ DummySyntheticFrontEnd(ValueObject &backend) :
+ SyntheticChildrenFrontEnd(backend)
+ {}
+
+ size_t
+ CalculateNumChildren()
+ {
+ return 0;
+ }
+
+ lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx)
+ {
+ return lldb::ValueObjectSP();
+ }
+
+ size_t
+ GetIndexOfChildWithName (const ConstString &name)
+ {
+ return UINT32_MAX;
+ }
+
+ bool
+ MightHaveChildren ()
+ {
+ return true;
+ }
+
+ bool
+ Update()
+ {
+ return false;
+ }
+
+};
+
+ValueObjectSynthetic::ValueObjectSynthetic (ValueObject &parent, lldb::SyntheticChildrenSP filter) :
+ ValueObject(parent),
+ m_synth_sp(filter),
+ m_children_byindex(),
+ m_name_toindex(),
+ m_synthetic_children_count(UINT32_MAX),
+ m_parent_type_name(parent.GetTypeName()),
+ m_might_have_children(eLazyBoolCalculate)
+{
+#ifdef LLDB_CONFIGURATION_DEBUG
+ std::string new_name(parent.GetName().AsCString());
+ new_name += "$$__synth__";
+ SetName (ConstString(new_name.c_str()));
+#else
+ SetName(parent.GetName());
+#endif
+ CopyParentData();
+ CreateSynthFilter();
+}
+
+ValueObjectSynthetic::~ValueObjectSynthetic()
+{
+}
+
+ClangASTType
+ValueObjectSynthetic::GetClangTypeImpl ()
+{
+ return m_parent->GetClangType();
+}
+
+ConstString
+ValueObjectSynthetic::GetTypeName()
+{
+ return m_parent->GetTypeName();
+}
+
+ConstString
+ValueObjectSynthetic::GetQualifiedTypeName()
+{
+ return m_parent->GetQualifiedTypeName();
+}
+
+size_t
+ValueObjectSynthetic::CalculateNumChildren()
+{
+ UpdateValueIfNeeded();
+ if (m_synthetic_children_count < UINT32_MAX)
+ return m_synthetic_children_count;
+ return (m_synthetic_children_count = m_synth_filter_ap->CalculateNumChildren());
+}
+
+lldb::ValueObjectSP
+ValueObjectSynthetic::GetDynamicValue (lldb::DynamicValueType valueType)
+{
+ if (!m_parent)
+ return lldb::ValueObjectSP();
+ if (IsDynamic() && GetDynamicValueType() == valueType)
+ return GetSP();
+ return m_parent->GetDynamicValue(valueType);
+}
+
+bool
+ValueObjectSynthetic::MightHaveChildren()
+{
+ if (m_might_have_children == eLazyBoolCalculate)
+ m_might_have_children = (m_synth_filter_ap->MightHaveChildren() ? eLazyBoolYes : eLazyBoolNo);
+ return (m_might_have_children == eLazyBoolNo ? false : true);
+}
+
+uint64_t
+ValueObjectSynthetic::GetByteSize()
+{
+ return m_parent->GetByteSize();
+}
+
+lldb::ValueType
+ValueObjectSynthetic::GetValueType() const
+{
+ return m_parent->GetValueType();
+}
+
+void
+ValueObjectSynthetic::CreateSynthFilter ()
+{
+ m_synth_filter_ap = (m_synth_sp->GetFrontEnd(*m_parent));
+ if (!m_synth_filter_ap.get())
+ m_synth_filter_ap.reset(new DummySyntheticFrontEnd(*m_parent));
+}
+
+bool
+ValueObjectSynthetic::UpdateValue ()
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ if (!m_parent->UpdateValueIfNeeded(false))
+ {
+ // our parent could not update.. as we are meaningless without a parent, just stop
+ if (m_parent->GetError().Fail())
+ m_error = m_parent->GetError();
+ return false;
+ }
+
+ // regenerate the synthetic filter if our typename changes
+ // <rdar://problem/12424824>
+ ConstString new_parent_type_name = m_parent->GetTypeName();
+ if (new_parent_type_name != m_parent_type_name)
+ {
+ m_parent_type_name = new_parent_type_name;
+ CreateSynthFilter();
+ }
+
+ // let our backend do its update
+ if (m_synth_filter_ap->Update() == false)
+ {
+ // filter said that cached values are stale
+ m_children_byindex.clear();
+ m_name_toindex.clear();
+ // usually, an object's value can change but this does not alter its children count
+ // for a synthetic VO that might indeed happen, so we need to tell the upper echelons
+ // that they need to come back to us asking for children
+ m_children_count_valid = false;
+ m_synthetic_children_count = UINT32_MAX;
+ m_might_have_children = eLazyBoolCalculate;
+ }
+
+ CopyParentData();
+
+ SetValueIsValid(true);
+ return true;
+}
+
+lldb::ValueObjectSP
+ValueObjectSynthetic::GetChildAtIndex (size_t idx, bool can_create)
+{
+ UpdateValueIfNeeded();
+
+ ByIndexIterator iter = m_children_byindex.find(idx);
+
+ if (iter == m_children_byindex.end())
+ {
+ if (can_create && m_synth_filter_ap.get() != NULL)
+ {
+ lldb::ValueObjectSP synth_guy = m_synth_filter_ap->GetChildAtIndex (idx);
+ if (!synth_guy)
+ return synth_guy;
+ m_children_byindex[idx]= synth_guy.get();
+ return synth_guy;
+ }
+ else
+ return lldb::ValueObjectSP();
+ }
+ else
+ return iter->second->GetSP();
+}
+
+lldb::ValueObjectSP
+ValueObjectSynthetic::GetChildMemberWithName (const ConstString &name, bool can_create)
+{
+ UpdateValueIfNeeded();
+
+ uint32_t index = GetIndexOfChildWithName(name);
+
+ if (index == UINT32_MAX)
+ return lldb::ValueObjectSP();
+
+ return GetChildAtIndex(index, can_create);
+}
+
+size_t
+ValueObjectSynthetic::GetIndexOfChildWithName (const ConstString &name)
+{
+ UpdateValueIfNeeded();
+
+ NameToIndexIterator iter = m_name_toindex.find(name.GetCString());
+
+ if (iter == m_name_toindex.end() && m_synth_filter_ap.get() != NULL)
+ {
+ uint32_t index = m_synth_filter_ap->GetIndexOfChildWithName (name);
+ if (index == UINT32_MAX)
+ return index;
+ m_name_toindex[name.GetCString()] = index;
+ return index;
+ }
+ else if (iter == m_name_toindex.end() && m_synth_filter_ap.get() == NULL)
+ return UINT32_MAX;
+ else /*if (iter != m_name_toindex.end())*/
+ return iter->second;
+}
+
+bool
+ValueObjectSynthetic::IsInScope ()
+{
+ return m_parent->IsInScope();
+}
+
+lldb::ValueObjectSP
+ValueObjectSynthetic::GetNonSyntheticValue ()
+{
+ return m_parent->GetSP();
+}
+
+void
+ValueObjectSynthetic::CopyParentData ()
+{
+ m_value = m_parent->GetValue();
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
+}
diff --git a/source/Core/ValueObjectVariable.cpp b/source/Core/ValueObjectVariable.cpp
new file mode 100644
index 0000000..38c0d91
--- /dev/null
+++ b/source/Core/ValueObjectVariable.cpp
@@ -0,0 +1,386 @@
+//===-- ValueObjectVariable.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/ValueObjectVariable.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/Value.h"
+
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolContextScope.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+
+using namespace lldb_private;
+
+lldb::ValueObjectSP
+ValueObjectVariable::Create (ExecutionContextScope *exe_scope, const lldb::VariableSP &var_sp)
+{
+ return (new ValueObjectVariable (exe_scope, var_sp))->GetSP();
+}
+
+ValueObjectVariable::ValueObjectVariable (ExecutionContextScope *exe_scope, const lldb::VariableSP &var_sp) :
+ ValueObject(exe_scope),
+ m_variable_sp(var_sp)
+{
+ // Do not attempt to construct one of these objects with no variable!
+ assert (m_variable_sp.get() != NULL);
+ m_name = var_sp->GetName();
+}
+
+ValueObjectVariable::~ValueObjectVariable()
+{
+}
+
+ClangASTType
+ValueObjectVariable::GetClangTypeImpl ()
+{
+ Type *var_type = m_variable_sp->GetType();
+ if (var_type)
+ return var_type->GetClangForwardType();
+ return ClangASTType();
+}
+
+ConstString
+ValueObjectVariable::GetTypeName()
+{
+ Type * var_type = m_variable_sp->GetType();
+ if (var_type)
+ return var_type->GetName();
+ return ConstString();
+}
+
+ConstString
+ValueObjectVariable::GetQualifiedTypeName()
+{
+ Type * var_type = m_variable_sp->GetType();
+ if (var_type)
+ return var_type->GetQualifiedName();
+ return ConstString();
+}
+
+size_t
+ValueObjectVariable::CalculateNumChildren()
+{
+ ClangASTType type(GetClangType());
+
+ if (!type.IsValid())
+ return 0;
+
+ const bool omit_empty_base_classes = true;
+ return type.GetNumChildren(omit_empty_base_classes);
+}
+
+uint64_t
+ValueObjectVariable::GetByteSize()
+{
+ ClangASTType type(GetClangType());
+
+ if (!type.IsValid())
+ return 0;
+
+ return type.GetByteSize();
+}
+
+lldb::ValueType
+ValueObjectVariable::GetValueType() const
+{
+ if (m_variable_sp)
+ return m_variable_sp->GetScope();
+ return lldb::eValueTypeInvalid;
+}
+
+bool
+ValueObjectVariable::UpdateValue ()
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ Variable *variable = m_variable_sp.get();
+ DWARFExpression &expr = variable->LocationExpression();
+
+ if (variable->GetLocationIsConstantValueData())
+ {
+ // expr doesn't contain DWARF bytes, it contains the constant variable
+ // value bytes themselves...
+ if (expr.GetExpressionData(m_data))
+ m_value.SetContext(Value::eContextTypeVariable, variable);
+ else
+ m_error.SetErrorString ("empty constant data");
+ // constant bytes can't be edited - sorry
+ m_resolved_value.SetContext(Value::eContextTypeInvalid, NULL);
+ }
+ else
+ {
+ lldb::addr_t loclist_base_load_addr = LLDB_INVALID_ADDRESS;
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());
+ m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
+ }
+
+ if (expr.IsLocationList())
+ {
+ SymbolContext sc;
+ variable->CalculateSymbolContext (&sc);
+ if (sc.function)
+ loclist_base_load_addr = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress (target);
+ }
+ Value old_value(m_value);
+ if (expr.Evaluate (&exe_ctx, NULL, NULL, NULL, loclist_base_load_addr, NULL, m_value, &m_error))
+ {
+ m_resolved_value = m_value;
+ m_value.SetContext(Value::eContextTypeVariable, variable);
+
+ Value::ValueType value_type = m_value.GetValueType();
+
+ switch (value_type)
+ {
+ case Value::eValueTypeFileAddress:
+ SetAddressTypeOfChildren(eAddressTypeFile);
+ break;
+ case Value::eValueTypeHostAddress:
+ SetAddressTypeOfChildren(eAddressTypeHost);
+ break;
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeScalar:
+ case Value::eValueTypeVector:
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+ break;
+ }
+
+ switch (value_type)
+ {
+ case Value::eValueTypeVector:
+ // fall through
+ case Value::eValueTypeScalar:
+ // The variable value is in the Scalar value inside the m_value.
+ // We can point our m_data right to it.
+ m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
+ break;
+
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeHostAddress:
+ // The DWARF expression result was an address in the inferior
+ // process. If this variable is an aggregate type, we just need
+ // the address as the main value as all child variable objects
+ // will rely upon this location and add an offset and then read
+ // their own values as needed. If this variable is a simple
+ // type, we read all data for it into m_data.
+ // Make sure this type has a value before we try and read it
+
+ // If we have a file address, convert it to a load address if we can.
+ Process *process = exe_ctx.GetProcessPtr();
+ if (value_type == Value::eValueTypeFileAddress && process && process->IsAlive())
+ {
+ lldb::addr_t file_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ if (file_addr != LLDB_INVALID_ADDRESS)
+ {
+ SymbolContext var_sc;
+ variable->CalculateSymbolContext(&var_sc);
+ if (var_sc.module_sp)
+ {
+ ObjectFile *objfile = var_sc.module_sp->GetObjectFile();
+ if (objfile)
+ {
+ Address so_addr(file_addr, objfile->GetSectionList());
+ lldb::addr_t load_addr = so_addr.GetLoadAddress (target);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeLoadAddress);
+ m_value.GetScalar() = load_addr;
+ }
+ }
+ }
+ }
+ }
+
+ if (GetClangType().IsAggregateType())
+ {
+ // this value object represents an aggregate type whose
+ // children have values, but this object does not. So we
+ // say we are changed if our location has changed.
+ SetValueDidChange (value_type != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar());
+ }
+ else
+ {
+ // Copy the Value and set the context to use our Variable
+ // so it can extract read its value into m_data appropriately
+ Value value(m_value);
+ value.SetContext(Value::eContextTypeVariable, variable);
+ m_error = value.GetValueAsData(&exe_ctx, m_data, 0, GetModule().get());
+ }
+ break;
+ }
+
+ SetValueIsValid (m_error.Success());
+ }
+ else
+ {
+ // could not find location, won't allow editing
+ m_resolved_value.SetContext(Value::eContextTypeInvalid, NULL);
+ }
+ }
+ return m_error.Success();
+}
+
+
+
+bool
+ValueObjectVariable::IsInScope ()
+{
+ const ExecutionContextRef &exe_ctx_ref = GetExecutionContextRef();
+ if (exe_ctx_ref.HasFrameRef())
+ {
+ ExecutionContext exe_ctx (exe_ctx_ref);
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ return m_variable_sp->IsInScope (frame);
+ }
+ else
+ {
+ // This ValueObject had a frame at one time, but now we
+ // can't locate it, so return false since we probably aren't
+ // in scope.
+ return false;
+ }
+ }
+ // We have a variable that wasn't tied to a frame, which
+ // means it is a global and is always in scope.
+ return true;
+
+}
+
+lldb::ModuleSP
+ValueObjectVariable::GetModule()
+{
+ if (m_variable_sp)
+ {
+ SymbolContextScope *sc_scope = m_variable_sp->GetSymbolContextScope();
+ if (sc_scope)
+ {
+ return sc_scope->CalculateSymbolContextModule();
+ }
+ }
+ return lldb::ModuleSP();
+}
+
+SymbolContextScope *
+ValueObjectVariable::GetSymbolContextScope()
+{
+ if (m_variable_sp)
+ return m_variable_sp->GetSymbolContextScope();
+ return NULL;
+}
+
+bool
+ValueObjectVariable::GetDeclaration (Declaration &decl)
+{
+ if (m_variable_sp)
+ {
+ decl = m_variable_sp->GetDeclaration();
+ return true;
+ }
+ return false;
+}
+
+const char *
+ValueObjectVariable::GetLocationAsCString ()
+{
+ if (m_resolved_value.GetContextType() == Value::eContextTypeRegisterInfo)
+ return GetLocationAsCStringImpl(m_resolved_value,
+ m_data);
+ else
+ return ValueObject::GetLocationAsCString();
+}
+
+bool
+ValueObjectVariable::SetValueFromCString (const char *value_str, Error& error)
+{
+ if (m_resolved_value.GetContextType() == Value::eContextTypeRegisterInfo)
+ {
+ RegisterInfo *reg_info = m_resolved_value.GetRegisterInfo();
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ RegisterContext *reg_ctx = exe_ctx.GetRegisterContext();
+ RegisterValue reg_value;
+ if (!reg_info || !reg_ctx)
+ {
+ error.SetErrorString("unable to retrieve register info");
+ return false;
+ }
+ error = reg_value.SetValueFromCString(reg_info, value_str);
+ if (error.Fail())
+ return false;
+ if (reg_ctx->WriteRegister (reg_info, reg_value))
+ {
+ SetNeedsUpdate();
+ return true;
+ }
+ else
+ {
+ error.SetErrorString("unable to write back to register");
+ return false;
+ }
+ }
+ else
+ return ValueObject::SetValueFromCString(value_str, error);
+}
+
+bool
+ValueObjectVariable::SetData (DataExtractor &data, Error &error)
+{
+ if (m_resolved_value.GetContextType() == Value::eContextTypeRegisterInfo)
+ {
+ RegisterInfo *reg_info = m_resolved_value.GetRegisterInfo();
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ RegisterContext *reg_ctx = exe_ctx.GetRegisterContext();
+ RegisterValue reg_value;
+ if (!reg_info || !reg_ctx)
+ {
+ error.SetErrorString("unable to retrieve register info");
+ return false;
+ }
+ error = reg_value.SetValueFromData(reg_info, data, 0, false);
+ if (error.Fail())
+ return false;
+ if (reg_ctx->WriteRegister (reg_info, reg_value))
+ {
+ SetNeedsUpdate();
+ return true;
+ }
+ else
+ {
+ error.SetErrorString("unable to write back to register");
+ return false;
+ }
+ }
+ else
+ return ValueObject::SetData(data, error);
+}
OpenPOWER on IntegriCloud