summaryrefslogtreecommitdiffstats
path: root/lldb/source/Core
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Core')
-rw-r--r--lldb/source/Core/Address.cpp875
-rw-r--r--lldb/source/Core/AddressRange.cpp222
-rw-r--r--lldb/source/Core/AddressResolver.cpp67
-rw-r--r--lldb/source/Core/AddressResolverFileLine.cpp100
-rw-r--r--lldb/source/Core/AddressResolverName.cpp231
-rw-r--r--lldb/source/Core/ArchSpec.cpp1681
-rw-r--r--lldb/source/Core/Args.cpp1179
-rw-r--r--lldb/source/Core/Baton.cpp25
-rw-r--r--lldb/source/Core/Broadcaster.cpp219
-rw-r--r--lldb/source/Core/Communication.cpp363
-rw-r--r--lldb/source/Core/Connection.cpp24
-rw-r--r--lldb/source/Core/ConnectionFileDescriptor.cpp563
-rw-r--r--lldb/source/Core/ConstString.cpp480
-rw-r--r--lldb/source/Core/DataBufferHeap.cpp105
-rw-r--r--lldb/source/Core/DataBufferMemoryMap.cpp214
-rw-r--r--lldb/source/Core/DataExtractor.cpp1517
-rw-r--r--lldb/source/Core/Debugger.cpp434
-rw-r--r--lldb/source/Core/Disassembler.cpp299
-rw-r--r--lldb/source/Core/DynamicLoader.cpp75
-rw-r--r--lldb/source/Core/Error.cpp365
-rw-r--r--lldb/source/Core/Event.cpp241
-rw-r--r--lldb/source/Core/FileSpec.cpp580
-rw-r--r--lldb/source/Core/FileSpecList.cpp228
-rw-r--r--lldb/source/Core/Flags.cpp122
-rw-r--r--lldb/source/Core/InputReader.cpp343
-rw-r--r--lldb/source/Core/Language.cpp150
-rw-r--r--lldb/source/Core/Listener.cpp480
-rw-r--r--lldb/source/Core/Log.cpp590
-rw-r--r--lldb/source/Core/Mangled.cpp733
-rw-r--r--lldb/source/Core/Module.cpp515
-rw-r--r--lldb/source/Core/ModuleChild.cpp52
-rw-r--r--lldb/source/Core/ModuleList.cpp626
-rw-r--r--lldb/source/Core/Options.cpp700
-rw-r--r--lldb/source/Core/PluginManager.cpp1133
-rw-r--r--lldb/source/Core/RegularExpression.cpp154
-rw-r--r--lldb/source/Core/Scalar.cpp2084
-rw-r--r--lldb/source/Core/SearchFilter.cpp435
-rw-r--r--lldb/source/Core/Section.cpp791
-rw-r--r--lldb/source/Core/SourceManager.cpp305
-rw-r--r--lldb/source/Core/State.cpp87
-rw-r--r--lldb/source/Core/Stream.cpp776
-rw-r--r--lldb/source/Core/StreamFile.cpp132
-rw-r--r--lldb/source/Core/StreamString.cpp81
-rw-r--r--lldb/source/Core/StringList.cpp200
-rw-r--r--lldb/source/Core/TTYState.cpp203
-rw-r--r--lldb/source/Core/Timer.cpp235
-rw-r--r--lldb/source/Core/UUID.cpp218
-rw-r--r--lldb/source/Core/UserID.cpp73
-rw-r--r--lldb/source/Core/VMRange.cpp100
-rw-r--r--lldb/source/Core/Value.cpp803
-rw-r--r--lldb/source/Core/ValueObject.cpp678
-rw-r--r--lldb/source/Core/ValueObjectChild.cpp207
-rw-r--r--lldb/source/Core/ValueObjectList.cpp119
-rw-r--r--lldb/source/Core/ValueObjectRegister.cpp331
-rw-r--r--lldb/source/Core/ValueObjectVariable.cpp167
55 files changed, 23710 insertions, 0 deletions
diff --git a/lldb/source/Core/Address.cpp b/lldb/source/Core/Address.cpp
new file mode 100644
index 00000000000..e2481e133fa
--- /dev/null
+++ b/lldb/source/Core/Address.cpp
@@ -0,0 +1,875 @@
+//===-- 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/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.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;
+
+ lldb::AddressType addr_type = eAddressTypeInvalid;
+ addr_t addr = LLDB_INVALID_ADDRESS;
+
+ Process *process = exe_scope->CalculateProcess();
+
+ if (process && process->IsAlive())
+ {
+ addr = address.GetLoadAddress(process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ addr_type = eAddressTypeLoad;
+ }
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ addr = address.GetFileAddress();
+ if (addr != LLDB_INVALID_ADDRESS)
+ addr_type = eAddressTypeFile;
+ }
+
+ if (addr_type == eAddressTypeInvalid)
+ return false;
+
+ Target *target = exe_scope->CalculateTarget();
+ if (target)
+ {
+ Error error;
+ return target->ReadMemory (addr_type, addr, dst, dst_len, error, NULL);
+ }
+ 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;
+
+ Process *process = exe_scope->CalculateProcess();
+ if (process)
+ {
+ byte_order = process->GetByteOrder();
+ addr_size = process->GetAddressByteSize();
+ }
+
+ if (byte_order == eByteOrderInvalid || addr_size == 0)
+ {
+ Module *module = address.GetModule();
+ if (module)
+ {
+ byte_order = module->GetArchitecture().GetDefaultEndian();
+ addr_size = module->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;
+
+ 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);
+ uint32_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)
+ {
+ Process *process = exe_scope->CalculateProcess();
+ if (process && process->IsAlive())
+ {
+ if (!process->ResolveLoadAddress (deref_addr, deref_so_addr))
+ {
+ deref_so_addr.SetSection(NULL);
+ deref_so_addr.SetOffset(deref_addr);
+ }
+ }
+ else
+ {
+ Target *target = exe_scope->CalculateTarget();
+ if (target == NULL)
+ return false;
+
+ if (!target->GetImages().ResolveFileAddress(deref_addr, deref_so_addr))
+ {
+ deref_so_addr.SetSection(NULL);
+ deref_so_addr.SetOffset(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)
+ 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.data(), 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 adderss size don't matter for C string dumping..
+ DataExtractor data (buf, sizeof(buf), eByteOrderHost, 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 () :
+ m_section (NULL),
+ m_offset (LLDB_INVALID_ADDRESS)
+{
+}
+
+Address::Address (const Address& rhs) :
+ m_section (rhs.m_section),
+ m_offset (rhs.m_offset)
+{
+}
+
+Address::Address (const Section* section, addr_t offset) :
+ m_section (section),
+ m_offset (offset)
+{
+}
+
+Address::Address (addr_t address, const SectionList * sections) :
+ m_section (NULL),
+ m_offset (LLDB_INVALID_ADDRESS)
+{
+ ResolveAddressUsingFileSections(address, sections);
+}
+
+Address::~Address ()
+{
+}
+
+
+const Address&
+Address::operator= (const Address& rhs)
+{
+ if (this != &rhs)
+ {
+ m_section = rhs.m_section;
+ m_offset = rhs.m_offset;
+ }
+ return *this;
+}
+
+bool
+Address::IsValid() const
+{
+ return m_offset != LLDB_INVALID_ADDRESS;
+}
+
+bool
+Address::IsSectionOffset() const
+{
+ return m_section != NULL && IsValid();
+}
+
+bool
+Address::ResolveAddressUsingFileSections (addr_t addr, const SectionList *sections)
+{
+ if (sections)
+ m_section = sections->FindSectionContainingFileAddress(addr).get();
+ else
+ m_section = NULL;
+
+ if (m_section != NULL)
+ {
+ assert( m_section->ContainsFileAddress(addr) );
+ m_offset = addr - m_section->GetFileAddress();
+ return true; // Successfully transformed addr into a section offset address
+ }
+
+ m_offset = addr;
+ return false; // Failed to resolve this address to a section offset value
+}
+
+//bool
+//Address::ResolveAddressUsingLoadSections (addr_t addr, const SectionList *sections)
+//{
+// if (sections)
+// m_section = sections->FindSectionContainingLoadAddress(addr).get();
+// else
+// m_section = NULL;
+//
+// if (m_section != NULL)
+// {
+// assert( m_section->ContainsLoadAddress(addr) );
+// m_offset = addr - m_section->GetLoadBaseAddress();
+// return true; // Successfully transformed addr into a section offset address
+// }
+//
+// m_offset = addr;
+// return false; // Failed to resolve this address to a section offset value
+//}
+//
+Module *
+Address::GetModule () const
+{
+ if (m_section)
+ return m_section->GetModule();
+ return NULL;
+}
+
+const Section*
+Address::GetSection () const
+{
+ return m_section;
+}
+
+
+//addr_t
+//Address::Address() const
+//{
+// addr_t addr = GetLoadAddress();
+// if (addr != LLDB_INVALID_ADDRESS)
+// return addr;
+// return GetFileAddress();
+//}
+//
+
+addr_t
+Address::GetFileAddress () const
+{
+ if (m_section != NULL)
+ {
+ addr_t sect_file_addr = m_section->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 (Process *process) const
+{
+ if (m_section != NULL)
+ {
+ if (process)
+ {
+ addr_t sect_load_addr = m_section->GetLoadBaseAddress (process);
+
+ 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;
+ }
+ // No section, we just return the offset since it is the value in this case
+ return m_offset;
+}
+
+addr_t
+Address::GetOffset () const
+{
+ return m_offset;
+}
+
+bool
+Address::SetOffset (addr_t offset)
+{
+ bool changed = m_offset != offset;
+ m_offset = offset;
+ return changed;
+}
+
+void
+Address::SetSection (const Section* section)
+{
+ m_section = section;
+}
+
+void
+Address::Clear()
+{
+ m_section = NULL;
+ m_offset = LLDB_INVALID_ADDRESS;
+}
+
+
+bool
+Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style) const
+{
+ // If the section was NULL, only load address is going to work.
+ if (m_section == NULL)
+ style = DumpStyleLoadAddress;
+
+ Process *process = NULL;
+ if (exe_scope)
+ process = exe_scope->CalculateProcess();
+ int addr_size = sizeof (addr_t);
+ if (process)
+ addr_size = process->GetAddressByteSize ();
+
+ lldb_private::Address so_addr;
+
+ switch (style)
+ {
+ case DumpStyleSectionNameOffset:
+ if (m_section != NULL)
+ {
+ m_section->DumpName(s);
+ s->Printf (" + %llu", m_offset);
+ }
+ else
+ {
+ s->Printf("0x%16.16llx", m_offset);
+ }
+ break;
+
+ case DumpStyleSectionPointerOffset:
+ s->Printf("(Section *)%.*p + 0x%16.16llx", (int)sizeof(void*) * 2, m_section, m_offset);
+ break;
+
+ case DumpStyleModuleWithFileAddress:
+ s->Printf("%s[", m_section->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);
+ return false;
+ }
+ s->Address (file_addr, addr_size);
+ if (style == DumpStyleModuleWithFileAddress)
+ s->PutChar(']');
+ }
+ break;
+
+ case DumpStyleLoadAddress:
+ {
+ addr_t load_addr = GetLoadAddress (process);
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style);
+ return false;
+ }
+ s->Address (load_addr, addr_size);
+ }
+ break;
+
+ case DumpStyleResolvedDescription:
+ if (IsSectionOffset())
+ {
+ lldb::AddressType addr_type = eAddressTypeLoad;
+ addr_t addr = GetLoadAddress (process);
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ addr = GetFileAddress();
+ addr_type = eAddressTypeFile;
+ }
+
+ uint32_t pointer_size = 4;
+ lldb_private::Module *module = GetModule();
+ if (process)
+ pointer_size = process->GetAddressByteSize();
+ else if (module)
+ pointer_size = module->GetArchitecture().GetAddressByteSize();
+
+ bool showed_info = false;
+ const Section *section = GetSection();
+ if (section)
+ {
+ SectionType sect_type = section->GetSectionType();
+ switch (sect_type)
+ {
+ 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 (so_addr.IsSectionOffset())
+ {
+ lldb_private::SymbolContext func_sc;
+ process->GetTarget().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, process, so_addr, true);
+ 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())
+ {
+ lldb_private::SymbolContext pointer_sc;
+ process->GetTarget().GetImages().ResolveSymbolContextForAddress (so_addr,
+ eSymbolContextEverything,
+ pointer_sc);
+ if (pointer_sc.function || pointer_sc.symbol)
+ {
+ s->PutCString(": ");
+ pointer_sc.DumpStopContext(s, process, so_addr, false);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (!showed_info)
+ {
+ if (module)
+ {
+ lldb_private::SymbolContext sc;
+ module->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc);
+ if (sc.function || sc.symbol)
+ {
+ bool show_stop_context = 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->GetAddressRangePtr())
+ {
+ if (sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetSection() != GetSection())
+ 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, process, *this, false);
+ }
+ 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);
+ return false;
+ }
+ break;
+ }
+
+ return true;
+}
+
+//Stream& operator << (Stream& s, const Address& so_addr)
+//{
+// so_addr.Dump(&s, Address::DumpStyleSectionNameOffset);
+// return s;
+//}
+//
+void
+Address::CalculateSymbolContext (SymbolContext *sc)
+{
+ sc->Clear();
+ // Absolute addresses don't have enough information to reconstruct even their target.
+ if (m_section == NULL)
+ return;
+
+ if (m_section->GetModule())
+ {
+ sc->module_sp = m_section->GetModule()->GetSP();
+ if (sc->module_sp)
+ sc->module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextEverything, *sc);
+ }
+}
+
+void
+Address::DumpSymbolContext (Stream *s)
+{
+ SymbolContext sc;
+ CalculateSymbolContext (&sc);
+ sc.Dump (s, NULL);
+}
+
+void
+Address::DumpDebug(Stream *s) const
+{
+ *s << (void *)this << ": " << "Address";
+ if (m_section != NULL)
+ {
+ *s << ", section = " << (void *)m_section << " (" << m_section->GetName() << "), offset = " << m_offset;
+ }
+ else
+ {
+ *s << ", vm_addr = " << m_offset;
+ }
+ s->EOL();
+}
+
+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, Process *process)
+{
+ assert (process != NULL);
+ addr_t a_load_addr = a.GetLoadAddress (process);
+ addr_t b_load_addr = b.GetLoadAddress (process);
+ 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)
+{
+ Module *a_module = a.GetModule ();
+ Module *b_module = b.GetModule ();
+ 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);
+}
+
+
+/// The only comparisons that make sense are the load addresses
+//bool
+//lldb::operator< (const Address& lhs, const Address& rhs)
+//{
+// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
+// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
+//
+// if (lhs_addr == rhs_addr)
+// {
+// lhs_addr = lhs.GetFileAddress();
+// rhs_addr = rhs.GetFileAddress();
+// }
+// return lhs_addr < rhs_addr;
+//}
+//
+//bool
+//lldb::operator<= (const Address& lhs, const Address& rhs)
+//{
+// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
+// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
+//
+// if (lhs_addr == rhs_addr)
+// {
+// lhs_addr = lhs.GetFileAddress();
+// rhs_addr = rhs.GetFileAddress();
+// }
+// return lhs_addr <= rhs_addr;
+//}
+//
+//bool
+//lldb::operator> (const Address& lhs, const Address& rhs)
+//{
+// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
+// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
+//
+// if (lhs_addr == rhs_addr)
+// {
+// lhs_addr = lhs.GetFileAddress();
+// rhs_addr = rhs.GetFileAddress();
+// }
+// return lhs_addr > rhs_addr;
+//}
+//
+//bool
+//lldb::operator>= (const Address& lhs, const Address& rhs)
+//{
+// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
+// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
+//
+// if (lhs_addr == rhs_addr)
+// {
+// lhs_addr = lhs.GetFileAddress();
+// rhs_addr = rhs.GetFileAddress();
+// }
+// return lhs_addr >= rhs_addr;
+//}
+//
+
+// The operator == checks for exact equality only (same section, same offset)
+bool
+lldb_private::operator== (const Address& a, const Address& rhs)
+{
+ return a.GetSection() == rhs.GetSection() &&
+ a.GetOffset() == rhs.GetOffset();
+}
+// The operator != checks for exact inequality only (differing section, or
+// different offset)
+bool
+lldb_private::operator!= (const Address& a, const Address& rhs)
+{
+ return a.GetSection() != rhs.GetSection() ||
+ a.GetOffset() != rhs.GetOffset();
+}
+
+bool
+Address::IsLinkedAddress () const
+{
+ return m_section && m_section->GetLinkedSection();
+}
+
+
+void
+Address::ResolveLinkedAddress ()
+{
+ if (m_section)
+ {
+ const Section *linked_section = m_section->GetLinkedSection();
+ if (linked_section)
+ {
+ m_offset += m_section->GetLinkedOffset();
+ m_section = linked_section;
+ }
+ }
+}
diff --git a/lldb/source/Core/AddressRange.cpp b/lldb/source/Core/AddressRange.cpp
new file mode 100644
index 00000000000..8c2997936fd
--- /dev/null
+++ b/lldb/source/Core/AddressRange.cpp
@@ -0,0 +1,222 @@
+//===-- 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/Stream.h"
+#include "lldb/Target/Process.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 Section* 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 ()
+{
+}
+
+Address &
+AddressRange::GetBaseAddress()
+{
+ return m_base_addr;
+}
+
+const Address &
+AddressRange::GetBaseAddress() const
+{
+ return m_base_addr;
+}
+
+addr_t
+AddressRange::GetByteSize() const
+{
+ return m_byte_size;
+}
+
+void
+AddressRange::SetByteSize(addr_t byte_size)
+{
+ m_byte_size = byte_size;
+}
+
+//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, Process *process) const
+{
+ if (addr.GetSection() == m_base_addr.GetSection())
+ return (addr.GetOffset() - m_base_addr.GetOffset()) < GetByteSize();
+ addr_t load_base_addr = GetBaseAddress().GetLoadAddress(process);
+ if (load_base_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ addr_t load_addr = addr.GetLoadAddress(process);
+ 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, Process *process) const
+{
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ addr_t load_base_addr = GetBaseAddress().GetLoadAddress(process);
+ 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, Process *process, Address::DumpStyle style, Address::DumpStyle fallback_style) const
+{
+ addr_t vmaddr = LLDB_INVALID_ADDRESS;
+ int addr_size = sizeof (addr_t);
+ if (process)
+ addr_size = process->GetAddressByteSize ();
+
+ switch (style)
+ {
+ case Address::DumpStyleSectionNameOffset:
+ case Address::DumpStyleSectionPointerOffset:
+ s->PutChar ('[');
+ m_base_addr.Dump(s, process, style, fallback_style);
+ s->PutChar ('-');
+ s->Address (m_base_addr.GetOffset() + GetByteSize(), addr_size);
+ s->PutChar (')');
+ return true;
+ break;
+
+ case Address::DumpStyleFileAddress:
+ vmaddr = m_base_addr.GetFileAddress();
+ break;
+
+ case Address::DumpStyleLoadAddress:
+ vmaddr = m_base_addr.GetLoadAddress(process);
+ break;
+ }
+
+ if (vmaddr != LLDB_INVALID_ADDRESS)
+ {
+ s->AddressRange(vmaddr, vmaddr + GetByteSize(), addr_size);
+ return true;
+ }
+
+ return false;
+}
+
+
+void
+AddressRange::DumpDebug (Stream *s) const
+{
+ s->Printf("%.*p: AddressRange section = %*p, offset = 0x%16.16llx, byte_size = 0x%16.16llx\n", (int)sizeof(void*) * 2, this, (int)sizeof(void*) * 2, m_base_addr.GetSection(), m_base_addr.GetOffset(), GetByteSize());
+}
+
+size_t
+AddressRange::MemorySize () const
+{
+ // Noting special for the memory size of a single AddressRange object,
+ // it is just the size of itself.
+ return sizeof(AddressRange);
+}
+//
+//bool
+//lldb::operator== (const AddressRange& lhs, const AddressRange& rhs)
+//{
+// if (lhs.GetBaseAddress() == rhs.GetBaseAddress())
+// return lhs.GetByteSize() == rhs.GetByteSize();
+// return false;
+//}
diff --git a/lldb/source/Core/AddressResolver.cpp b/lldb/source/Core/AddressResolver.cpp
new file mode 100644
index 00000000000..5369d960f25
--- /dev/null
+++ b/lldb/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/lldb/source/Core/AddressResolverFileLine.cpp b/lldb/source/Core/AddressResolverFileLine.cpp
new file mode 100644
index 00000000000..c4aadcca9c1
--- /dev/null
+++ b/lldb/source/Core/AddressResolverFileLine.cpp
@@ -0,0 +1,100 @@
+//===-- 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/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 (int 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%llx 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/lldb/source/Core/AddressResolverName.cpp b/lldb/source/Core/AddressResolverName.cpp
new file mode 100644
index 00000000000..9e154c6e703
--- /dev/null
+++ b/lldb/source/Core/AddressResolverName.cpp
@@ -0,0 +1,231 @@
+//===-- 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/StreamString.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;
+ }
+
+ 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, false, 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, true, 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->GetAddressRangePtr())
+ {
+ if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRangePtr()->GetBaseAddress())
+ {
+ 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->GetAddressRangePtr())
+ {
+ func_addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress();
+ addr_t byte_size = sc.symbol->GetAddressRangePtr()->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/lldb/source/Core/ArchSpec.cpp b/lldb/source/Core/ArchSpec.cpp
new file mode 100644
index 00000000000..3cc8232ac97
--- /dev/null
+++ b/lldb/source/Core/ArchSpec.cpp
@@ -0,0 +1,1681 @@
+//===-- 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 <mach/mach.h>
+#include <mach-o/nlist.h>
+
+#include <string>
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define ARCH_SPEC_SEPARATOR_CHAR '-'
+
+#ifndef CPU_TYPE_ARM
+#define CPU_TYPE_ARM ((cpu_type_t) 12)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_ALL
+#define CPU_SUBTYPE_ARM_ALL ((cpu_subtype_t) 0)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V4T
+#define CPU_SUBTYPE_ARM_V4T ((cpu_subtype_t) 5)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V6
+#define CPU_SUBTYPE_ARM_V6 ((cpu_subtype_t) 6)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V5TEJ
+#define CPU_SUBTYPE_ARM_V5TEJ ((cpu_subtype_t) 7)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_XSCALE
+#define CPU_SUBTYPE_ARM_XSCALE ((cpu_subtype_t) 8)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V7
+#define CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9)
+#endif
+
+//----------------------------------------------------------------------
+// A structure that describes all of the information we want to know
+// about each architecture.
+//----------------------------------------------------------------------
+struct ArchDefinition
+{
+ uint32_t cpu;
+ uint32_t sub;
+ const char *name;
+};
+
+//----------------------------------------------------------------------
+// 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 ArchDefinition g_arch_defs[] =
+{
+ { CPU_TYPE_ANY, CPU_TYPE_ANY , "all" },
+ { CPU_TYPE_ARM, CPU_TYPE_ANY , "arm" },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_ALL , "arm" },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V4T , "armv4" },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V5TEJ , "armv5" },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6 , "armv6" },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7 , "armv7" },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_XSCALE , "xscale" },
+ { CPU_TYPE_POWERPC, CPU_TYPE_ANY , "ppc" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL , "ppc" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_601 , "ppc601" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_602 , "ppc602" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_603 , "ppc603" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_603e , "ppc603e" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_603ev , "ppc603ev" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_604 , "ppc604" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_604e , "ppc604e" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_620 , "ppc620" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_750 , "ppc750" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_7400 , "ppc7400" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_7450 , "ppc7450" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_970 , "ppc970" },
+ { CPU_TYPE_POWERPC64, CPU_SUBTYPE_POWERPC_ALL , "ppc64" },
+ { CPU_TYPE_POWERPC64, CPU_SUBTYPE_POWERPC_970 , "ppc970-64" },
+ { CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL , "i386" },
+ { CPU_TYPE_I386, CPU_SUBTYPE_486 , "i486" },
+ { CPU_TYPE_I386, CPU_SUBTYPE_486SX , "i486sx" },
+ { CPU_TYPE_I386, CPU_TYPE_ANY , "i386" },
+ { CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL , "x86_64" },
+ { CPU_TYPE_X86_64, CPU_TYPE_ANY , "x86_64" },
+
+ // TODO: when we get a platform that knows more about the host OS we should
+ // let it call some accessor funcitons to set the default system arch for
+ // the default, 32 and 64 bit cases instead of hard coding it in this
+ // table.
+
+#if defined (__i386__) || defined(__x86_64__)
+ { CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL , LLDB_ARCH_DEFAULT },
+ { CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL , LLDB_ARCH_DEFAULT_32BIT },
+ { CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL , LLDB_ARCH_DEFAULT_64BIT },
+#elif defined (__arm__)
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6 , LLDB_ARCH_DEFAULT },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6 , LLDB_ARCH_DEFAULT_32BIT },
+#elif defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__)
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_7400 , LLDB_ARCH_DEFAULT },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_7400 , LLDB_ARCH_DEFAULT_32BIT },
+ { CPU_TYPE_POWERPC64, CPU_SUBTYPE_POWERPC_970 , LLDB_ARCH_DEFAULT_64BIT },
+#endif
+};
+
+//----------------------------------------------------------------------
+// Figure out how many architecture definitions we have
+//----------------------------------------------------------------------
+const size_t k_num_arch_defs = sizeof(g_arch_defs)/sizeof(ArchDefinition);
+
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+ArchSpec::ArchSpec() :
+ m_cpu (LLDB_INVALID_CPUTYPE),
+ m_sub (0)
+{
+}
+
+//----------------------------------------------------------------------
+// Constructor that initializes the object with supplied cpu and
+// subtypes.
+//----------------------------------------------------------------------
+ArchSpec::ArchSpec(uint32_t cpu, uint32_t sub) :
+ m_cpu (cpu),
+ m_sub (sub)
+{
+}
+
+//----------------------------------------------------------------------
+// Constructor that initializes the object with supplied
+// architecture name. There are also predefined values in
+// Defines.h:
+// liblldb_ARCH_DEFAULT
+// The arch the current system defaults to when a program is
+// launched without any extra attributes or settings.
+//
+// liblldb_ARCH_DEFAULT_32BIT
+// The 32 bit arch the current system defaults to (if any)
+//
+// liblldb_ARCH_DEFAULT_32BIT
+// The 64 bit arch the current system defaults to (if any)
+//----------------------------------------------------------------------
+ArchSpec::ArchSpec(const char *arch_name) :
+ m_cpu (LLDB_INVALID_CPUTYPE),
+ m_sub (0)
+{
+ if (arch_name)
+ SetArch(arch_name);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ArchSpec::~ArchSpec()
+{
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const ArchSpec&
+ArchSpec::operator= (const ArchSpec& rhs)
+{
+ if (this != &rhs)
+ {
+ m_cpu = rhs.m_cpu;
+ m_sub = rhs.m_sub;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Get a C string representation of the current architecture
+//----------------------------------------------------------------------
+const char *
+ArchSpec::AsCString() const
+{
+ return ArchSpec::AsCString(m_cpu, m_sub);
+}
+
+//----------------------------------------------------------------------
+// Class function to get a C string representation given a CPU type
+// and subtype.
+//----------------------------------------------------------------------
+const char *
+ArchSpec::AsCString(uint32_t cpu, uint32_t sub)
+{
+ for (uint32_t i=0; i<k_num_arch_defs; i++)
+ {
+ if (cpu == g_arch_defs[i].cpu)
+ {
+ if (sub == g_arch_defs[i].sub)
+ return g_arch_defs[i].name;
+ else if (sub != CPU_TYPE_ANY && sub != LLDB_INVALID_CPUTYPE)
+ {
+ if ((sub & ~CPU_SUBTYPE_MASK) == g_arch_defs[i].sub)
+ return g_arch_defs[i].name;
+ }
+ }
+ }
+ static char s_cpu_hex_str[64];
+ ::snprintf(s_cpu_hex_str, sizeof(s_cpu_hex_str), "%u%c%u", cpu, ARCH_SPEC_SEPARATOR_CHAR, sub);
+ return s_cpu_hex_str;
+}
+
+//----------------------------------------------------------------------
+// Clears the object contents back to a default invalid state.
+//----------------------------------------------------------------------
+void
+ArchSpec::Clear()
+{
+ m_cpu = LLDB_INVALID_CPUTYPE;
+ m_sub = 0;
+}
+
+
+//----------------------------------------------------------------------
+// CPU subtype get accessor.
+//----------------------------------------------------------------------
+uint32_t
+ArchSpec::GetCPUSubtype() const
+{
+ if (m_sub == CPU_TYPE_ANY || m_sub == LLDB_INVALID_CPUTYPE)
+ return m_sub;
+ return m_sub & ~CPU_SUBTYPE_MASK;
+}
+
+
+//----------------------------------------------------------------------
+// CPU type get accessor.
+//----------------------------------------------------------------------
+uint32_t
+ArchSpec::GetCPUType() const
+{
+ return m_cpu;
+}
+
+
+//----------------------------------------------------------------------
+// Feature flags get accessor.
+//----------------------------------------------------------------------
+uint32_t
+ArchSpec::GetFeatureFlags() const
+{
+ if (m_sub == CPU_TYPE_ANY || m_sub == LLDB_INVALID_CPUTYPE)
+ return 0;
+ return m_sub & CPU_SUBTYPE_MASK;
+}
+
+
+static const char * g_i386_dwarf_reg_names[] =
+{
+ "eax",
+ "ecx",
+ "edx",
+ "ebx",
+ "esp",
+ "ebp",
+ "esi",
+ "edi",
+ "eip",
+ "eflags"
+};
+
+static const char * g_i386_gcc_reg_names[] =
+{
+ "eax",
+ "ecx",
+ "edx",
+ "ebx",
+ "ebp",
+ "esp",
+ "esi",
+ "edi",
+ "eip",
+ "eflags"
+};
+
+static const char * g_x86_64_dwarf_and_gcc_reg_names[] = {
+ "rax",
+ "rdx",
+ "rcx",
+ "rbx",
+ "rsi",
+ "rdi",
+ "rbp",
+ "rsp",
+ "r8",
+ "r9",
+ "r10",
+ "r11",
+ "r12",
+ "r13",
+ "r14",
+ "r15",
+ "rip"
+};
+
+// Values take from:
+// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040a/IHI0040A_aadwarf.pdf
+
+enum
+{
+ eRegNumARM_DWARF_r0 = 0,
+ eRegNumARM_DWARF_r1 = 1,
+ eRegNumARM_DWARF_r2 = 2,
+ eRegNumARM_DWARF_r3 = 3,
+ eRegNumARM_DWARF_r4 = 4,
+ eRegNumARM_DWARF_r5 = 5,
+ eRegNumARM_DWARF_r6 = 6,
+ eRegNumARM_DWARF_r7 = 7,
+ eRegNumARM_DWARF_r8 = 8,
+ eRegNumARM_DWARF_r9 = 9,
+ eRegNumARM_DWARF_r10 = 10,
+ eRegNumARM_DWARF_r11 = 11,
+ eRegNumARM_DWARF_r12 = 12,
+ eRegNumARM_DWARF_r13 = 13, // SP
+ eRegNumARM_DWARF_r14 = 14, // LR
+ eRegNumARM_DWARF_r15 = 15, // PC
+
+ eRegNumARM_DWARF_f0_obsolete= 16,
+ eRegNumARM_DWARF_f1_obsolete,
+ eRegNumARM_DWARF_f2_obsolete,
+ eRegNumARM_DWARF_f3_obsolete,
+ eRegNumARM_DWARF_f4_obsolete,
+ eRegNumARM_DWARF_f5_obsolete,
+ eRegNumARM_DWARF_f6_obsolete,
+ eRegNumARM_DWARF_f7_obsolete,
+
+ eRegNumARM_DWARF_s0_obsolete = 16,
+ eRegNumARM_DWARF_s1_obsolete,
+ eRegNumARM_DWARF_s2_obsolete,
+ eRegNumARM_DWARF_s3_obsolete,
+ eRegNumARM_DWARF_s4_obsolete,
+ eRegNumARM_DWARF_s5_obsolete,
+ eRegNumARM_DWARF_s6_obsolete,
+ eRegNumARM_DWARF_s7_obsolete,
+ eRegNumARM_DWARF_s8_obsolete,
+ eRegNumARM_DWARF_s9_obsolete,
+ eRegNumARM_DWARF_s10_obsolete,
+ eRegNumARM_DWARF_s11_obsolete,
+ eRegNumARM_DWARF_s12_obsolete,
+ eRegNumARM_DWARF_s13_obsolete,
+ eRegNumARM_DWARF_s14_obsolete,
+ eRegNumARM_DWARF_s15_obsolete,
+ eRegNumARM_DWARF_s16_obsolete,
+ eRegNumARM_DWARF_s17_obsolete,
+ eRegNumARM_DWARF_s18_obsolete,
+ eRegNumARM_DWARF_s19_obsolete,
+ eRegNumARM_DWARF_s20_obsolete,
+ eRegNumARM_DWARF_s21_obsolete,
+ eRegNumARM_DWARF_s22_obsolete,
+ eRegNumARM_DWARF_s23_obsolete,
+ eRegNumARM_DWARF_s24_obsolete,
+ eRegNumARM_DWARF_s25_obsolete,
+ eRegNumARM_DWARF_s26_obsolete,
+ eRegNumARM_DWARF_s27_obsolete,
+ eRegNumARM_DWARF_s28_obsolete,
+ eRegNumARM_DWARF_s29_obsolete,
+ eRegNumARM_DWARF_s30_obsolete,
+ eRegNumARM_DWARF_s31_obsolete,
+
+ eRegNumARM_DWARF_s0 = 64,
+ eRegNumARM_DWARF_s1,
+ eRegNumARM_DWARF_s2,
+ eRegNumARM_DWARF_s3,
+ eRegNumARM_DWARF_s4,
+ eRegNumARM_DWARF_s5,
+ eRegNumARM_DWARF_s6,
+ eRegNumARM_DWARF_s7,
+ eRegNumARM_DWARF_s8,
+ eRegNumARM_DWARF_s9,
+ eRegNumARM_DWARF_s10,
+ eRegNumARM_DWARF_s11,
+ eRegNumARM_DWARF_s12,
+ eRegNumARM_DWARF_s13,
+ eRegNumARM_DWARF_s14,
+ eRegNumARM_DWARF_s15,
+ eRegNumARM_DWARF_s16,
+ eRegNumARM_DWARF_s17,
+ eRegNumARM_DWARF_s18,
+ eRegNumARM_DWARF_s19,
+ eRegNumARM_DWARF_s20,
+ eRegNumARM_DWARF_s21,
+ eRegNumARM_DWARF_s22,
+ eRegNumARM_DWARF_s23,
+ eRegNumARM_DWARF_s24,
+ eRegNumARM_DWARF_s25,
+ eRegNumARM_DWARF_s26,
+ eRegNumARM_DWARF_s27,
+ eRegNumARM_DWARF_s28,
+ eRegNumARM_DWARF_s29,
+ eRegNumARM_DWARF_s30,
+ eRegNumARM_DWARF_s31,
+
+ eRegNumARM_DWARF_f0 = 96,
+ eRegNumARM_DWARF_f1,
+ eRegNumARM_DWARF_f2,
+ eRegNumARM_DWARF_f3,
+ eRegNumARM_DWARF_f4,
+ eRegNumARM_DWARF_f5,
+ eRegNumARM_DWARF_f6,
+ eRegNumARM_DWARF_f7,
+
+ eRegNumARM_DWARF_ACC0 = 104,
+ eRegNumARM_DWARF_ACC1,
+ eRegNumARM_DWARF_ACC2,
+ eRegNumARM_DWARF_ACC3,
+ eRegNumARM_DWARF_ACC4,
+ eRegNumARM_DWARF_ACC5,
+ eRegNumARM_DWARF_ACC6,
+ eRegNumARM_DWARF_ACC7,
+
+ eRegNumARM_DWARF_wCGR0 = 104, // These overlap with ACC0-ACC7
+ eRegNumARM_DWARF_wCGR1,
+ eRegNumARM_DWARF_wCGR2,
+ eRegNumARM_DWARF_wCGR3,
+ eRegNumARM_DWARF_wCGR4,
+ eRegNumARM_DWARF_wCGR5,
+ eRegNumARM_DWARF_wCGR6,
+ eRegNumARM_DWARF_wCGR7,
+
+ eRegNumARM_DWARF_wR0 = 112,
+ eRegNumARM_DWARF_wR1,
+ eRegNumARM_DWARF_wR2,
+ eRegNumARM_DWARF_wR3,
+ eRegNumARM_DWARF_wR4,
+ eRegNumARM_DWARF_wR5,
+ eRegNumARM_DWARF_wR6,
+ eRegNumARM_DWARF_wR7,
+ eRegNumARM_DWARF_wR8,
+ eRegNumARM_DWARF_wR9,
+ eRegNumARM_DWARF_wR10,
+ eRegNumARM_DWARF_wR11,
+ eRegNumARM_DWARF_wR12,
+ eRegNumARM_DWARF_wR13,
+ eRegNumARM_DWARF_wR14,
+ eRegNumARM_DWARF_wR15,
+
+ eRegNumARM_DWARF_spsr = 128,
+ eRegNumARM_DWARF_spsr_fiq,
+ eRegNumARM_DWARF_spsr_irq,
+ eRegNumARM_DWARF_spsr_abt,
+ eRegNumARM_DWARF_spsr_und,
+ eRegNumARM_DWARF_spsr_svc,
+
+ eRegNumARM_DWARF_r8_usr = 144,
+ eRegNumARM_DWARF_r9_usr,
+ eRegNumARM_DWARF_r10_usr,
+ eRegNumARM_DWARF_r11_usr,
+ eRegNumARM_DWARF_r12_usr,
+ eRegNumARM_DWARF_r13_usr,
+ eRegNumARM_DWARF_r14_usr,
+
+ eRegNumARM_DWARF_r8_fiq = 151,
+ eRegNumARM_DWARF_r9_fiq,
+ eRegNumARM_DWARF_r10_fiq,
+ eRegNumARM_DWARF_r11_fiq,
+ eRegNumARM_DWARF_r12_fiq,
+ eRegNumARM_DWARF_r13_fiq,
+ eRegNumARM_DWARF_r14_fiq,
+
+ eRegNumARM_DWARF_r13_irq,
+ eRegNumARM_DWARF_r14_irq,
+
+ eRegNumARM_DWARF_r13_abt,
+ eRegNumARM_DWARF_r14_abt,
+
+ eRegNumARM_DWARF_r13_und,
+ eRegNumARM_DWARF_r14_und,
+
+ eRegNumARM_DWARF_r13_svc,
+ eRegNumARM_DWARF_r14_svc,
+
+ eRegNumARM_DWARF_wC0 = 192,
+ eRegNumARM_DWARF_wC1,
+ eRegNumARM_DWARF_wC2,
+ eRegNumARM_DWARF_wC3,
+ eRegNumARM_DWARF_wC4,
+ eRegNumARM_DWARF_wC5,
+ eRegNumARM_DWARF_wC6,
+ eRegNumARM_DWARF_wC7,
+
+ eRegNumARM_DWARF_d0 = 256, // VFP-v3/NEON D0-D31 (32 64 bit registers)
+ eRegNumARM_DWARF_d1,
+ eRegNumARM_DWARF_d2,
+ eRegNumARM_DWARF_d3,
+ eRegNumARM_DWARF_d4,
+ eRegNumARM_DWARF_d5,
+ eRegNumARM_DWARF_d6,
+ eRegNumARM_DWARF_d7,
+ eRegNumARM_DWARF_d8,
+ eRegNumARM_DWARF_d9,
+ eRegNumARM_DWARF_d10,
+ eRegNumARM_DWARF_d11,
+ eRegNumARM_DWARF_d12,
+ eRegNumARM_DWARF_d13,
+ eRegNumARM_DWARF_d14,
+ eRegNumARM_DWARF_d15,
+ eRegNumARM_DWARF_d16,
+ eRegNumARM_DWARF_d17,
+ eRegNumARM_DWARF_d18,
+ eRegNumARM_DWARF_d19,
+ eRegNumARM_DWARF_d20,
+ eRegNumARM_DWARF_d21,
+ eRegNumARM_DWARF_d22,
+ eRegNumARM_DWARF_d23,
+ eRegNumARM_DWARF_d24,
+ eRegNumARM_DWARF_d25,
+ eRegNumARM_DWARF_d26,
+ eRegNumARM_DWARF_d27,
+ eRegNumARM_DWARF_d28,
+ eRegNumARM_DWARF_d29,
+ eRegNumARM_DWARF_d30,
+ eRegNumARM_DWARF_d31
+};
+
+// Register numbering definitions for 32 and 64 bit ppc for RegisterNumberingType::Dwarf
+enum
+{
+ eRegNumPPC_DWARF_r0 = 0,
+ eRegNumPPC_DWARF_r1 = 1,
+ eRegNumPPC_DWARF_r2 = 2,
+ eRegNumPPC_DWARF_r3 = 3,
+ eRegNumPPC_DWARF_r4 = 4,
+ eRegNumPPC_DWARF_r5 = 5,
+ eRegNumPPC_DWARF_r6 = 6,
+ eRegNumPPC_DWARF_r7 = 7,
+ eRegNumPPC_DWARF_r8 = 8,
+ eRegNumPPC_DWARF_r9 = 9,
+ eRegNumPPC_DWARF_r10 = 10,
+ eRegNumPPC_DWARF_r11 = 11,
+ eRegNumPPC_DWARF_r12 = 12,
+ eRegNumPPC_DWARF_r13 = 13,
+ eRegNumPPC_DWARF_r14 = 14,
+ eRegNumPPC_DWARF_r15 = 15,
+ eRegNumPPC_DWARF_r16 = 16,
+ eRegNumPPC_DWARF_r17 = 17,
+ eRegNumPPC_DWARF_r18 = 18,
+ eRegNumPPC_DWARF_r19 = 19,
+ eRegNumPPC_DWARF_r20 = 20,
+ eRegNumPPC_DWARF_r21 = 21,
+ eRegNumPPC_DWARF_r22 = 22,
+ eRegNumPPC_DWARF_r23 = 23,
+ eRegNumPPC_DWARF_r24 = 24,
+ eRegNumPPC_DWARF_r25 = 25,
+ eRegNumPPC_DWARF_r26 = 26,
+ eRegNumPPC_DWARF_r27 = 27,
+ eRegNumPPC_DWARF_r28 = 28,
+ eRegNumPPC_DWARF_r29 = 29,
+ eRegNumPPC_DWARF_r30 = 30,
+ eRegNumPPC_DWARF_r31 = 31,
+
+ eRegNumPPC_DWARF_fr0 = 32,
+ eRegNumPPC_DWARF_fr1 = 33,
+ eRegNumPPC_DWARF_fr2 = 34,
+ eRegNumPPC_DWARF_fr3 = 35,
+ eRegNumPPC_DWARF_fr4 = 36,
+ eRegNumPPC_DWARF_fr5 = 37,
+ eRegNumPPC_DWARF_fr6 = 38,
+ eRegNumPPC_DWARF_fr7 = 39,
+ eRegNumPPC_DWARF_fr8 = 40,
+ eRegNumPPC_DWARF_fr9 = 41,
+ eRegNumPPC_DWARF_fr10 = 42,
+ eRegNumPPC_DWARF_fr11 = 43,
+ eRegNumPPC_DWARF_fr12 = 44,
+ eRegNumPPC_DWARF_fr13 = 45,
+ eRegNumPPC_DWARF_fr14 = 46,
+ eRegNumPPC_DWARF_fr15 = 47,
+ eRegNumPPC_DWARF_fr16 = 48,
+ eRegNumPPC_DWARF_fr17 = 49,
+ eRegNumPPC_DWARF_fr18 = 50,
+ eRegNumPPC_DWARF_fr19 = 51,
+ eRegNumPPC_DWARF_fr20 = 52,
+ eRegNumPPC_DWARF_fr21 = 53,
+ eRegNumPPC_DWARF_fr22 = 54,
+ eRegNumPPC_DWARF_fr23 = 55,
+ eRegNumPPC_DWARF_fr24 = 56,
+ eRegNumPPC_DWARF_fr25 = 57,
+ eRegNumPPC_DWARF_fr26 = 58,
+ eRegNumPPC_DWARF_fr27 = 59,
+ eRegNumPPC_DWARF_fr28 = 60,
+ eRegNumPPC_DWARF_fr29 = 61,
+ eRegNumPPC_DWARF_fr30 = 62,
+ eRegNumPPC_DWARF_fr31 = 63,
+
+ eRegNumPPC_DWARF_cr = 64,
+ eRegNumPPC_DWARF_fpscr = 65,
+ eRegNumPPC_DWARF_msr = 66,
+ eRegNumPPC_DWARF_vscr = 67,
+
+ eRegNumPPC_DWARF_sr0 = 70,
+ eRegNumPPC_DWARF_sr1,
+ eRegNumPPC_DWARF_sr2,
+ eRegNumPPC_DWARF_sr3,
+ eRegNumPPC_DWARF_sr4,
+ eRegNumPPC_DWARF_sr5,
+ eRegNumPPC_DWARF_sr6,
+ eRegNumPPC_DWARF_sr7,
+ eRegNumPPC_DWARF_sr8,
+ eRegNumPPC_DWARF_sr9,
+ eRegNumPPC_DWARF_sr10,
+ eRegNumPPC_DWARF_sr11,
+ eRegNumPPC_DWARF_sr12,
+ eRegNumPPC_DWARF_sr13,
+ eRegNumPPC_DWARF_sr14,
+ eRegNumPPC_DWARF_sr15,
+
+
+ eRegNumPPC_DWARF_acc = 99,
+ eRegNumPPC_DWARF_mq = 100,
+ eRegNumPPC_DWARF_xer = 101,
+ eRegNumPPC_DWARF_rtcu = 104,
+ eRegNumPPC_DWARF_rtcl = 105,
+
+ eRegNumPPC_DWARF_lr = 108,
+ eRegNumPPC_DWARF_ctr = 109,
+
+ eRegNumPPC_DWARF_dsisr = 118,
+ eRegNumPPC_DWARF_dar = 119,
+ eRegNumPPC_DWARF_dec = 122,
+ eRegNumPPC_DWARF_sdr1 = 125,
+ eRegNumPPC_DWARF_srr0 = 126,
+ eRegNumPPC_DWARF_srr1 = 127,
+
+ eRegNumPPC_DWARF_vrsave = 356,
+ eRegNumPPC_DWARF_sprg0 = 372,
+ eRegNumPPC_DWARF_sprg1,
+ eRegNumPPC_DWARF_sprg2,
+ eRegNumPPC_DWARF_sprg3,
+
+ eRegNumPPC_DWARF_asr = 380,
+ eRegNumPPC_DWARF_ear = 382,
+ eRegNumPPC_DWARF_tb = 384,
+ eRegNumPPC_DWARF_tbu = 385,
+ eRegNumPPC_DWARF_pvr = 387,
+
+ eRegNumPPC_DWARF_spefscr = 612,
+
+ eRegNumPPC_DWARF_ibat0u = 628,
+ eRegNumPPC_DWARF_ibat0l = 629,
+ eRegNumPPC_DWARF_ibat1u = 630,
+ eRegNumPPC_DWARF_ibat1l = 631,
+ eRegNumPPC_DWARF_ibat2u = 632,
+ eRegNumPPC_DWARF_ibat2l = 633,
+ eRegNumPPC_DWARF_ibat3u = 634,
+ eRegNumPPC_DWARF_ibat3l = 635,
+ eRegNumPPC_DWARF_dbat0u = 636,
+ eRegNumPPC_DWARF_dbat0l = 637,
+ eRegNumPPC_DWARF_dbat1u = 638,
+ eRegNumPPC_DWARF_dbat1l = 639,
+ eRegNumPPC_DWARF_dbat2u = 640,
+ eRegNumPPC_DWARF_dbat2l = 641,
+ eRegNumPPC_DWARF_dbat3u = 642,
+ eRegNumPPC_DWARF_dbat3l = 643,
+
+ eRegNumPPC_DWARF_hid0 = 1108,
+ eRegNumPPC_DWARF_hid1,
+ eRegNumPPC_DWARF_hid2,
+ eRegNumPPC_DWARF_hid3,
+ eRegNumPPC_DWARF_hid4,
+ eRegNumPPC_DWARF_hid5,
+ eRegNumPPC_DWARF_hid6,
+ eRegNumPPC_DWARF_hid7,
+ eRegNumPPC_DWARF_hid8,
+ eRegNumPPC_DWARF_hid9,
+ eRegNumPPC_DWARF_hid10,
+ eRegNumPPC_DWARF_hid11,
+ eRegNumPPC_DWARF_hid12,
+ eRegNumPPC_DWARF_hid13,
+ eRegNumPPC_DWARF_hid14,
+ eRegNumPPC_DWARF_hid15,
+
+ eRegNumPPC_DWARF_vr0 = 1124,
+ eRegNumPPC_DWARF_vr1,
+ eRegNumPPC_DWARF_vr2,
+ eRegNumPPC_DWARF_vr3,
+ eRegNumPPC_DWARF_vr4,
+ eRegNumPPC_DWARF_vr5,
+ eRegNumPPC_DWARF_vr6,
+ eRegNumPPC_DWARF_vr7,
+ eRegNumPPC_DWARF_vr8,
+ eRegNumPPC_DWARF_vr9,
+ eRegNumPPC_DWARF_vr10,
+ eRegNumPPC_DWARF_vr11,
+ eRegNumPPC_DWARF_vr12,
+ eRegNumPPC_DWARF_vr13,
+ eRegNumPPC_DWARF_vr14,
+ eRegNumPPC_DWARF_vr15,
+ eRegNumPPC_DWARF_vr16,
+ eRegNumPPC_DWARF_vr17,
+ eRegNumPPC_DWARF_vr18,
+ eRegNumPPC_DWARF_vr19,
+ eRegNumPPC_DWARF_vr20,
+ eRegNumPPC_DWARF_vr21,
+ eRegNumPPC_DWARF_vr22,
+ eRegNumPPC_DWARF_vr23,
+ eRegNumPPC_DWARF_vr24,
+ eRegNumPPC_DWARF_vr25,
+ eRegNumPPC_DWARF_vr26,
+ eRegNumPPC_DWARF_vr27,
+ eRegNumPPC_DWARF_vr28,
+ eRegNumPPC_DWARF_vr29,
+ eRegNumPPC_DWARF_vr30,
+ eRegNumPPC_DWARF_vr31,
+
+ eRegNumPPC_DWARF_ev0 = 1200,
+ eRegNumPPC_DWARF_ev1,
+ eRegNumPPC_DWARF_ev2,
+ eRegNumPPC_DWARF_ev3,
+ eRegNumPPC_DWARF_ev4,
+ eRegNumPPC_DWARF_ev5,
+ eRegNumPPC_DWARF_ev6,
+ eRegNumPPC_DWARF_ev7,
+ eRegNumPPC_DWARF_ev8,
+ eRegNumPPC_DWARF_ev9,
+ eRegNumPPC_DWARF_ev10,
+ eRegNumPPC_DWARF_ev11,
+ eRegNumPPC_DWARF_ev12,
+ eRegNumPPC_DWARF_ev13,
+ eRegNumPPC_DWARF_ev14,
+ eRegNumPPC_DWARF_ev15,
+ eRegNumPPC_DWARF_ev16,
+ eRegNumPPC_DWARF_ev17,
+ eRegNumPPC_DWARF_ev18,
+ eRegNumPPC_DWARF_ev19,
+ eRegNumPPC_DWARF_ev20,
+ eRegNumPPC_DWARF_ev21,
+ eRegNumPPC_DWARF_ev22,
+ eRegNumPPC_DWARF_ev23,
+ eRegNumPPC_DWARF_ev24,
+ eRegNumPPC_DWARF_ev25,
+ eRegNumPPC_DWARF_ev26,
+ eRegNumPPC_DWARF_ev27,
+ eRegNumPPC_DWARF_ev28,
+ eRegNumPPC_DWARF_ev29,
+ eRegNumPPC_DWARF_ev30,
+ eRegNumPPC_DWARF_ev31
+};
+
+// Register numbering definitions for 32 and 64 bit ppc for RegisterNumberingType::GCC
+enum
+{
+ eRegNumPPC_GCC_r0 = 0,
+ eRegNumPPC_GCC_r1 = 1,
+ eRegNumPPC_GCC_r2 = 2,
+ eRegNumPPC_GCC_r3 = 3,
+ eRegNumPPC_GCC_r4 = 4,
+ eRegNumPPC_GCC_r5 = 5,
+ eRegNumPPC_GCC_r6 = 6,
+ eRegNumPPC_GCC_r7 = 7,
+ eRegNumPPC_GCC_r8 = 8,
+ eRegNumPPC_GCC_r9 = 9,
+ eRegNumPPC_GCC_r10 = 10,
+ eRegNumPPC_GCC_r11 = 11,
+ eRegNumPPC_GCC_r12 = 12,
+ eRegNumPPC_GCC_r13 = 13,
+ eRegNumPPC_GCC_r14 = 14,
+ eRegNumPPC_GCC_r15 = 15,
+ eRegNumPPC_GCC_r16 = 16,
+ eRegNumPPC_GCC_r17 = 17,
+ eRegNumPPC_GCC_r18 = 18,
+ eRegNumPPC_GCC_r19 = 19,
+ eRegNumPPC_GCC_r20 = 20,
+ eRegNumPPC_GCC_r21 = 21,
+ eRegNumPPC_GCC_r22 = 22,
+ eRegNumPPC_GCC_r23 = 23,
+ eRegNumPPC_GCC_r24 = 24,
+ eRegNumPPC_GCC_r25 = 25,
+ eRegNumPPC_GCC_r26 = 26,
+ eRegNumPPC_GCC_r27 = 27,
+ eRegNumPPC_GCC_r28 = 28,
+ eRegNumPPC_GCC_r29 = 29,
+ eRegNumPPC_GCC_r30 = 30,
+ eRegNumPPC_GCC_r31 = 31,
+ eRegNumPPC_GCC_fr0 = 32,
+ eRegNumPPC_GCC_fr1 = 33,
+ eRegNumPPC_GCC_fr2 = 34,
+ eRegNumPPC_GCC_fr3 = 35,
+ eRegNumPPC_GCC_fr4 = 36,
+ eRegNumPPC_GCC_fr5 = 37,
+ eRegNumPPC_GCC_fr6 = 38,
+ eRegNumPPC_GCC_fr7 = 39,
+ eRegNumPPC_GCC_fr8 = 40,
+ eRegNumPPC_GCC_fr9 = 41,
+ eRegNumPPC_GCC_fr10 = 42,
+ eRegNumPPC_GCC_fr11 = 43,
+ eRegNumPPC_GCC_fr12 = 44,
+ eRegNumPPC_GCC_fr13 = 45,
+ eRegNumPPC_GCC_fr14 = 46,
+ eRegNumPPC_GCC_fr15 = 47,
+ eRegNumPPC_GCC_fr16 = 48,
+ eRegNumPPC_GCC_fr17 = 49,
+ eRegNumPPC_GCC_fr18 = 50,
+ eRegNumPPC_GCC_fr19 = 51,
+ eRegNumPPC_GCC_fr20 = 52,
+ eRegNumPPC_GCC_fr21 = 53,
+ eRegNumPPC_GCC_fr22 = 54,
+ eRegNumPPC_GCC_fr23 = 55,
+ eRegNumPPC_GCC_fr24 = 56,
+ eRegNumPPC_GCC_fr25 = 57,
+ eRegNumPPC_GCC_fr26 = 58,
+ eRegNumPPC_GCC_fr27 = 59,
+ eRegNumPPC_GCC_fr28 = 60,
+ eRegNumPPC_GCC_fr29 = 61,
+ eRegNumPPC_GCC_fr30 = 62,
+ eRegNumPPC_GCC_fr31 = 63,
+ eRegNumPPC_GCC_mq = 64,
+ eRegNumPPC_GCC_lr = 65,
+ eRegNumPPC_GCC_ctr = 66,
+ eRegNumPPC_GCC_ap = 67,
+ eRegNumPPC_GCC_cr0 = 68,
+ eRegNumPPC_GCC_cr1 = 69,
+ eRegNumPPC_GCC_cr2 = 70,
+ eRegNumPPC_GCC_cr3 = 71,
+ eRegNumPPC_GCC_cr4 = 72,
+ eRegNumPPC_GCC_cr5 = 73,
+ eRegNumPPC_GCC_cr6 = 74,
+ eRegNumPPC_GCC_cr7 = 75,
+ eRegNumPPC_GCC_xer = 76,
+ eRegNumPPC_GCC_v0 = 77,
+ eRegNumPPC_GCC_v1 = 78,
+ eRegNumPPC_GCC_v2 = 79,
+ eRegNumPPC_GCC_v3 = 80,
+ eRegNumPPC_GCC_v4 = 81,
+ eRegNumPPC_GCC_v5 = 82,
+ eRegNumPPC_GCC_v6 = 83,
+ eRegNumPPC_GCC_v7 = 84,
+ eRegNumPPC_GCC_v8 = 85,
+ eRegNumPPC_GCC_v9 = 86,
+ eRegNumPPC_GCC_v10 = 87,
+ eRegNumPPC_GCC_v11 = 88,
+ eRegNumPPC_GCC_v12 = 89,
+ eRegNumPPC_GCC_v13 = 90,
+ eRegNumPPC_GCC_v14 = 91,
+ eRegNumPPC_GCC_v15 = 92,
+ eRegNumPPC_GCC_v16 = 93,
+ eRegNumPPC_GCC_v17 = 94,
+ eRegNumPPC_GCC_v18 = 95,
+ eRegNumPPC_GCC_v19 = 96,
+ eRegNumPPC_GCC_v20 = 97,
+ eRegNumPPC_GCC_v21 = 98,
+ eRegNumPPC_GCC_v22 = 99,
+ eRegNumPPC_GCC_v23 = 100,
+ eRegNumPPC_GCC_v24 = 101,
+ eRegNumPPC_GCC_v25 = 102,
+ eRegNumPPC_GCC_v26 = 103,
+ eRegNumPPC_GCC_v27 = 104,
+ eRegNumPPC_GCC_v28 = 105,
+ eRegNumPPC_GCC_v29 = 106,
+ eRegNumPPC_GCC_v30 = 107,
+ eRegNumPPC_GCC_v31 = 108,
+ eRegNumPPC_GCC_vrsave = 109,
+ eRegNumPPC_GCC_vscr = 110,
+ eRegNumPPC_GCC_spe_acc = 111,
+ eRegNumPPC_GCC_spefscr = 112,
+ eRegNumPPC_GCC_sfp = 113,
+};
+
+static const char * g_arm_gcc_reg_names[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "cc", "sfp", "afp",
+ "mv0", "mv1", "mv2", "mv3", "mv4", "mv5", "mv6", "mv7",
+ "mv8", "mv9", "mv10", "mv11", "mv12", "mv13", "mv14", "mv15",
+ "wcgr0","wcgr1","wcgr2","wcgr3",
+ "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7",
+ "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
+ "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
+ "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
+ "vfpcc"
+};
+
+//----------------------------------------------------------------------
+// Get register names for the current object architecture given
+// a register number, and a reg_kind for that register number.
+//----------------------------------------------------------------------
+const char *
+ArchSpec::GetRegisterName(uint32_t reg_num, uint32_t reg_kind) const
+{
+ return ArchSpec::GetRegisterName(m_cpu, m_sub, reg_num, reg_kind);
+}
+
+
+//----------------------------------------------------------------------
+// Get register names for the specified CPU type and subtype given
+// a register number, and a reg_kind for that register number.
+//----------------------------------------------------------------------
+const char *
+ArchSpec::GetRegisterName(uint32_t cpu, uint32_t subtype, uint32_t reg_num, uint32_t reg_kind)
+{
+ if (cpu == CPU_TYPE_I386)
+ {
+ switch (reg_kind)
+ {
+ case eRegisterKindGCC:
+ if (reg_num < sizeof(g_i386_gcc_reg_names)/sizeof(const char *))
+ return g_i386_gcc_reg_names[reg_num];
+ break;
+ case eRegisterKindDWARF:
+ if (reg_num < sizeof(g_i386_dwarf_reg_names)/sizeof(const char *))
+ return g_i386_dwarf_reg_names[reg_num];
+ break;
+ default:
+ break;
+ }
+ }
+ else if (cpu == CPU_TYPE_X86_64)
+ {
+ switch (reg_kind)
+ {
+ case eRegisterKindGCC:
+ case eRegisterKindDWARF:
+ if (reg_num < sizeof(g_x86_64_dwarf_and_gcc_reg_names)/sizeof(const char *))
+ return g_x86_64_dwarf_and_gcc_reg_names[reg_num];
+ break;
+ default:
+ break;
+ }
+ }
+ else if (cpu == CPU_TYPE_ARM)
+ {
+ switch (reg_kind)
+ {
+ case eRegisterKindGCC:
+ if (reg_num < sizeof(g_arm_gcc_reg_names)/sizeof(const char *))
+ return g_arm_gcc_reg_names[reg_num];
+ break;
+
+ case eRegisterKindDWARF:
+ switch (reg_num)
+ {
+ case eRegNumARM_DWARF_r0: return "r0";
+ case eRegNumARM_DWARF_r1: return "r1";
+ case eRegNumARM_DWARF_r2: return "r2";
+ case eRegNumARM_DWARF_r3: return "r3";
+ case eRegNumARM_DWARF_r4: return "r4";
+ case eRegNumARM_DWARF_r5: return "r5";
+ case eRegNumARM_DWARF_r6: return "r6";
+ case eRegNumARM_DWARF_r7: return "r7";
+ case eRegNumARM_DWARF_r8: return "r8";
+ case eRegNumARM_DWARF_r9: return "r9";
+ case eRegNumARM_DWARF_r10: return "r10";
+ case eRegNumARM_DWARF_r11: return "r11";
+ case eRegNumARM_DWARF_r12: return "r12";
+ case eRegNumARM_DWARF_r13: return "sp";
+ case eRegNumARM_DWARF_r14: return "lr";
+ case eRegNumARM_DWARF_r15: return "pc";
+ case eRegNumARM_DWARF_s0_obsolete: case eRegNumARM_DWARF_s0: return "s0";
+ case eRegNumARM_DWARF_s1_obsolete: case eRegNumARM_DWARF_s1: return "s1";
+ case eRegNumARM_DWARF_s2_obsolete: case eRegNumARM_DWARF_s2: return "s2";
+ case eRegNumARM_DWARF_s3_obsolete: case eRegNumARM_DWARF_s3: return "s3";
+ case eRegNumARM_DWARF_s4_obsolete: case eRegNumARM_DWARF_s4: return "s4";
+ case eRegNumARM_DWARF_s5_obsolete: case eRegNumARM_DWARF_s5: return "s5";
+ case eRegNumARM_DWARF_s6_obsolete: case eRegNumARM_DWARF_s6: return "s6";
+ case eRegNumARM_DWARF_s7_obsolete: case eRegNumARM_DWARF_s7: return "s7";
+ case eRegNumARM_DWARF_s8_obsolete: case eRegNumARM_DWARF_s8: return "s8";
+ case eRegNumARM_DWARF_s9_obsolete: case eRegNumARM_DWARF_s9: return "s9";
+ case eRegNumARM_DWARF_s10_obsolete: case eRegNumARM_DWARF_s10: return "s10";
+ case eRegNumARM_DWARF_s11_obsolete: case eRegNumARM_DWARF_s11: return "s11";
+ case eRegNumARM_DWARF_s12_obsolete: case eRegNumARM_DWARF_s12: return "s12";
+ case eRegNumARM_DWARF_s13_obsolete: case eRegNumARM_DWARF_s13: return "s13";
+ case eRegNumARM_DWARF_s14_obsolete: case eRegNumARM_DWARF_s14: return "s14";
+ case eRegNumARM_DWARF_s15_obsolete: case eRegNumARM_DWARF_s15: return "s15";
+ case eRegNumARM_DWARF_s16_obsolete: case eRegNumARM_DWARF_s16: return "s16";
+ case eRegNumARM_DWARF_s17_obsolete: case eRegNumARM_DWARF_s17: return "s17";
+ case eRegNumARM_DWARF_s18_obsolete: case eRegNumARM_DWARF_s18: return "s18";
+ case eRegNumARM_DWARF_s19_obsolete: case eRegNumARM_DWARF_s19: return "s19";
+ case eRegNumARM_DWARF_s20_obsolete: case eRegNumARM_DWARF_s20: return "s20";
+ case eRegNumARM_DWARF_s21_obsolete: case eRegNumARM_DWARF_s21: return "s21";
+ case eRegNumARM_DWARF_s22_obsolete: case eRegNumARM_DWARF_s22: return "s22";
+ case eRegNumARM_DWARF_s23_obsolete: case eRegNumARM_DWARF_s23: return "s23";
+ case eRegNumARM_DWARF_s24_obsolete: case eRegNumARM_DWARF_s24: return "s24";
+ case eRegNumARM_DWARF_s25_obsolete: case eRegNumARM_DWARF_s25: return "s25";
+ case eRegNumARM_DWARF_s26_obsolete: case eRegNumARM_DWARF_s26: return "s26";
+ case eRegNumARM_DWARF_s27_obsolete: case eRegNumARM_DWARF_s27: return "s27";
+ case eRegNumARM_DWARF_s28_obsolete: case eRegNumARM_DWARF_s28: return "s28";
+ case eRegNumARM_DWARF_s29_obsolete: case eRegNumARM_DWARF_s29: return "s29";
+ case eRegNumARM_DWARF_s30_obsolete: case eRegNumARM_DWARF_s30: return "s30";
+ case eRegNumARM_DWARF_s31_obsolete: case eRegNumARM_DWARF_s31: return "s31";
+ case eRegNumARM_DWARF_f0: return "f0";
+ case eRegNumARM_DWARF_f1: return "f1";
+ case eRegNumARM_DWARF_f2: return "f2";
+ case eRegNumARM_DWARF_f3: return "f3";
+ case eRegNumARM_DWARF_f4: return "f4";
+ case eRegNumARM_DWARF_f5: return "f5";
+ case eRegNumARM_DWARF_f6: return "f6";
+ case eRegNumARM_DWARF_f7: return "f7";
+ case eRegNumARM_DWARF_wCGR0: return "wCGR0/ACC0";
+ case eRegNumARM_DWARF_wCGR1: return "wCGR1/ACC1";
+ case eRegNumARM_DWARF_wCGR2: return "wCGR2/ACC2";
+ case eRegNumARM_DWARF_wCGR3: return "wCGR3/ACC3";
+ case eRegNumARM_DWARF_wCGR4: return "wCGR4/ACC4";
+ case eRegNumARM_DWARF_wCGR5: return "wCGR5/ACC5";
+ case eRegNumARM_DWARF_wCGR6: return "wCGR6/ACC6";
+ case eRegNumARM_DWARF_wCGR7: return "wCGR7/ACC7";
+ case eRegNumARM_DWARF_wR0: return "wR0";
+ case eRegNumARM_DWARF_wR1: return "wR1";
+ case eRegNumARM_DWARF_wR2: return "wR2";
+ case eRegNumARM_DWARF_wR3: return "wR3";
+ case eRegNumARM_DWARF_wR4: return "wR4";
+ case eRegNumARM_DWARF_wR5: return "wR5";
+ case eRegNumARM_DWARF_wR6: return "wR6";
+ case eRegNumARM_DWARF_wR7: return "wR7";
+ case eRegNumARM_DWARF_wR8: return "wR8";
+ case eRegNumARM_DWARF_wR9: return "wR9";
+ case eRegNumARM_DWARF_wR10: return "wR10";
+ case eRegNumARM_DWARF_wR11: return "wR11";
+ case eRegNumARM_DWARF_wR12: return "wR12";
+ case eRegNumARM_DWARF_wR13: return "wR13";
+ case eRegNumARM_DWARF_wR14: return "wR14";
+ case eRegNumARM_DWARF_wR15: return "wR15";
+ case eRegNumARM_DWARF_spsr: return "spsr";
+ case eRegNumARM_DWARF_spsr_fiq: return "spsr_fiq";
+ case eRegNumARM_DWARF_spsr_irq: return "spsr_irq";
+ case eRegNumARM_DWARF_spsr_abt: return "spsr_abt";
+ case eRegNumARM_DWARF_spsr_und: return "spsr_und";
+ case eRegNumARM_DWARF_spsr_svc: return "spsr_svc";
+ case eRegNumARM_DWARF_r8_usr: return "r8_usr";
+ case eRegNumARM_DWARF_r9_usr: return "r9_usr";
+ case eRegNumARM_DWARF_r10_usr: return "r10_usr";
+ case eRegNumARM_DWARF_r11_usr: return "r11_usr";
+ case eRegNumARM_DWARF_r12_usr: return "r12_usr";
+ case eRegNumARM_DWARF_r13_usr: return "sp_usr";
+ case eRegNumARM_DWARF_r14_usr: return "lr_usr";
+ case eRegNumARM_DWARF_r8_fiq: return "r8_fiq";
+ case eRegNumARM_DWARF_r9_fiq: return "r9_fiq";
+ case eRegNumARM_DWARF_r10_fiq: return "r10_fiq";
+ case eRegNumARM_DWARF_r11_fiq: return "r11_fiq";
+ case eRegNumARM_DWARF_r12_fiq: return "r12_fiq";
+ case eRegNumARM_DWARF_r13_fiq: return "sp_fiq";
+ case eRegNumARM_DWARF_r14_fiq: return "lr_fiq";
+ case eRegNumARM_DWARF_r13_irq: return "sp_irq";
+ case eRegNumARM_DWARF_r14_irq: return "lr_irq";
+ case eRegNumARM_DWARF_r13_abt: return "sp_abt";
+ case eRegNumARM_DWARF_r14_abt: return "lr_abt";
+ case eRegNumARM_DWARF_r13_und: return "sp_und";
+ case eRegNumARM_DWARF_r14_und: return "lr_und";
+ case eRegNumARM_DWARF_r13_svc: return "sp_svc";
+ case eRegNumARM_DWARF_r14_svc: return "lr_svc";
+ case eRegNumARM_DWARF_wC0: return "wC0";
+ case eRegNumARM_DWARF_wC1: return "wC1";
+ case eRegNumARM_DWARF_wC2: return "wC2";
+ case eRegNumARM_DWARF_wC3: return "wC3";
+ case eRegNumARM_DWARF_wC4: return "wC4";
+ case eRegNumARM_DWARF_wC5: return "wC5";
+ case eRegNumARM_DWARF_wC6: return "wC6";
+ case eRegNumARM_DWARF_wC7: return "wC7";
+ case eRegNumARM_DWARF_d0: return "d0";
+ case eRegNumARM_DWARF_d1: return "d1";
+ case eRegNumARM_DWARF_d2: return "d2";
+ case eRegNumARM_DWARF_d3: return "d3";
+ case eRegNumARM_DWARF_d4: return "d4";
+ case eRegNumARM_DWARF_d5: return "d5";
+ case eRegNumARM_DWARF_d6: return "d6";
+ case eRegNumARM_DWARF_d7: return "d7";
+ case eRegNumARM_DWARF_d8: return "d8";
+ case eRegNumARM_DWARF_d9: return "d9";
+ case eRegNumARM_DWARF_d10: return "d10";
+ case eRegNumARM_DWARF_d11: return "d11";
+ case eRegNumARM_DWARF_d12: return "d12";
+ case eRegNumARM_DWARF_d13: return "d13";
+ case eRegNumARM_DWARF_d14: return "d14";
+ case eRegNumARM_DWARF_d15: return "d15";
+ case eRegNumARM_DWARF_d16: return "d16";
+ case eRegNumARM_DWARF_d17: return "d17";
+ case eRegNumARM_DWARF_d18: return "d18";
+ case eRegNumARM_DWARF_d19: return "d19";
+ case eRegNumARM_DWARF_d20: return "d20";
+ case eRegNumARM_DWARF_d21: return "d21";
+ case eRegNumARM_DWARF_d22: return "d22";
+ case eRegNumARM_DWARF_d23: return "d23";
+ case eRegNumARM_DWARF_d24: return "d24";
+ case eRegNumARM_DWARF_d25: return "d25";
+ case eRegNumARM_DWARF_d26: return "d26";
+ case eRegNumARM_DWARF_d27: return "d27";
+ case eRegNumARM_DWARF_d28: return "d28";
+ case eRegNumARM_DWARF_d29: return "d29";
+ case eRegNumARM_DWARF_d30: return "d30";
+ case eRegNumARM_DWARF_d31: return "d31";
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else if (cpu == CPU_TYPE_POWERPC || cpu == CPU_TYPE_POWERPC64)
+ {
+ switch (reg_kind)
+ {
+ case eRegisterKindGCC:
+ switch (reg_num)
+ {
+ case eRegNumPPC_GCC_r0: return "r0";
+ case eRegNumPPC_GCC_r1: return "r1";
+ case eRegNumPPC_GCC_r2: return "r2";
+ case eRegNumPPC_GCC_r3: return "r3";
+ case eRegNumPPC_GCC_r4: return "r4";
+ case eRegNumPPC_GCC_r5: return "r5";
+ case eRegNumPPC_GCC_r6: return "r6";
+ case eRegNumPPC_GCC_r7: return "r7";
+ case eRegNumPPC_GCC_r8: return "r8";
+ case eRegNumPPC_GCC_r9: return "r9";
+ case eRegNumPPC_GCC_r10: return "r10";
+ case eRegNumPPC_GCC_r11: return "r11";
+ case eRegNumPPC_GCC_r12: return "r12";
+ case eRegNumPPC_GCC_r13: return "r13";
+ case eRegNumPPC_GCC_r14: return "r14";
+ case eRegNumPPC_GCC_r15: return "r15";
+ case eRegNumPPC_GCC_r16: return "r16";
+ case eRegNumPPC_GCC_r17: return "r17";
+ case eRegNumPPC_GCC_r18: return "r18";
+ case eRegNumPPC_GCC_r19: return "r19";
+ case eRegNumPPC_GCC_r20: return "r20";
+ case eRegNumPPC_GCC_r21: return "r21";
+ case eRegNumPPC_GCC_r22: return "r22";
+ case eRegNumPPC_GCC_r23: return "r23";
+ case eRegNumPPC_GCC_r24: return "r24";
+ case eRegNumPPC_GCC_r25: return "r25";
+ case eRegNumPPC_GCC_r26: return "r26";
+ case eRegNumPPC_GCC_r27: return "r27";
+ case eRegNumPPC_GCC_r28: return "r28";
+ case eRegNumPPC_GCC_r29: return "r29";
+ case eRegNumPPC_GCC_r30: return "r30";
+ case eRegNumPPC_GCC_r31: return "r31";
+ case eRegNumPPC_GCC_fr0: return "fr0";
+ case eRegNumPPC_GCC_fr1: return "fr1";
+ case eRegNumPPC_GCC_fr2: return "fr2";
+ case eRegNumPPC_GCC_fr3: return "fr3";
+ case eRegNumPPC_GCC_fr4: return "fr4";
+ case eRegNumPPC_GCC_fr5: return "fr5";
+ case eRegNumPPC_GCC_fr6: return "fr6";
+ case eRegNumPPC_GCC_fr7: return "fr7";
+ case eRegNumPPC_GCC_fr8: return "fr8";
+ case eRegNumPPC_GCC_fr9: return "fr9";
+ case eRegNumPPC_GCC_fr10: return "fr10";
+ case eRegNumPPC_GCC_fr11: return "fr11";
+ case eRegNumPPC_GCC_fr12: return "fr12";
+ case eRegNumPPC_GCC_fr13: return "fr13";
+ case eRegNumPPC_GCC_fr14: return "fr14";
+ case eRegNumPPC_GCC_fr15: return "fr15";
+ case eRegNumPPC_GCC_fr16: return "fr16";
+ case eRegNumPPC_GCC_fr17: return "fr17";
+ case eRegNumPPC_GCC_fr18: return "fr18";
+ case eRegNumPPC_GCC_fr19: return "fr19";
+ case eRegNumPPC_GCC_fr20: return "fr20";
+ case eRegNumPPC_GCC_fr21: return "fr21";
+ case eRegNumPPC_GCC_fr22: return "fr22";
+ case eRegNumPPC_GCC_fr23: return "fr23";
+ case eRegNumPPC_GCC_fr24: return "fr24";
+ case eRegNumPPC_GCC_fr25: return "fr25";
+ case eRegNumPPC_GCC_fr26: return "fr26";
+ case eRegNumPPC_GCC_fr27: return "fr27";
+ case eRegNumPPC_GCC_fr28: return "fr28";
+ case eRegNumPPC_GCC_fr29: return "fr29";
+ case eRegNumPPC_GCC_fr30: return "fr30";
+ case eRegNumPPC_GCC_fr31: return "fr31";
+ case eRegNumPPC_GCC_mq: return "mq";
+ case eRegNumPPC_GCC_lr: return "lr";
+ case eRegNumPPC_GCC_ctr: return "ctr";
+ case eRegNumPPC_GCC_ap: return "ap";
+ case eRegNumPPC_GCC_cr0: return "cr0";
+ case eRegNumPPC_GCC_cr1: return "cr1";
+ case eRegNumPPC_GCC_cr2: return "cr2";
+ case eRegNumPPC_GCC_cr3: return "cr3";
+ case eRegNumPPC_GCC_cr4: return "cr4";
+ case eRegNumPPC_GCC_cr5: return "cr5";
+ case eRegNumPPC_GCC_cr6: return "cr6";
+ case eRegNumPPC_GCC_cr7: return "cr7";
+ case eRegNumPPC_GCC_xer: return "xer";
+ case eRegNumPPC_GCC_v0: return "v0";
+ case eRegNumPPC_GCC_v1: return "v1";
+ case eRegNumPPC_GCC_v2: return "v2";
+ case eRegNumPPC_GCC_v3: return "v3";
+ case eRegNumPPC_GCC_v4: return "v4";
+ case eRegNumPPC_GCC_v5: return "v5";
+ case eRegNumPPC_GCC_v6: return "v6";
+ case eRegNumPPC_GCC_v7: return "v7";
+ case eRegNumPPC_GCC_v8: return "v8";
+ case eRegNumPPC_GCC_v9: return "v9";
+ case eRegNumPPC_GCC_v10: return "v10";
+ case eRegNumPPC_GCC_v11: return "v11";
+ case eRegNumPPC_GCC_v12: return "v12";
+ case eRegNumPPC_GCC_v13: return "v13";
+ case eRegNumPPC_GCC_v14: return "v14";
+ case eRegNumPPC_GCC_v15: return "v15";
+ case eRegNumPPC_GCC_v16: return "v16";
+ case eRegNumPPC_GCC_v17: return "v17";
+ case eRegNumPPC_GCC_v18: return "v18";
+ case eRegNumPPC_GCC_v19: return "v19";
+ case eRegNumPPC_GCC_v20: return "v20";
+ case eRegNumPPC_GCC_v21: return "v21";
+ case eRegNumPPC_GCC_v22: return "v22";
+ case eRegNumPPC_GCC_v23: return "v23";
+ case eRegNumPPC_GCC_v24: return "v24";
+ case eRegNumPPC_GCC_v25: return "v25";
+ case eRegNumPPC_GCC_v26: return "v26";
+ case eRegNumPPC_GCC_v27: return "v27";
+ case eRegNumPPC_GCC_v28: return "v28";
+ case eRegNumPPC_GCC_v29: return "v29";
+ case eRegNumPPC_GCC_v30: return "v30";
+ case eRegNumPPC_GCC_v31: return "v31";
+ case eRegNumPPC_GCC_vrsave: return "vrsave";
+ case eRegNumPPC_GCC_vscr: return "vscr";
+ case eRegNumPPC_GCC_spe_acc: return "spe_acc";
+ case eRegNumPPC_GCC_spefscr: return "spefscr";
+ case eRegNumPPC_GCC_sfp: return "sfp";
+ default:
+ break;
+ }
+ break;
+
+ case eRegisterKindDWARF:
+ switch (reg_num)
+ {
+ case eRegNumPPC_DWARF_r0: return "r0";
+ case eRegNumPPC_DWARF_r1: return "r1";
+ case eRegNumPPC_DWARF_r2: return "r2";
+ case eRegNumPPC_DWARF_r3: return "r3";
+ case eRegNumPPC_DWARF_r4: return "r4";
+ case eRegNumPPC_DWARF_r5: return "r5";
+ case eRegNumPPC_DWARF_r6: return "r6";
+ case eRegNumPPC_DWARF_r7: return "r7";
+ case eRegNumPPC_DWARF_r8: return "r8";
+ case eRegNumPPC_DWARF_r9: return "r9";
+ case eRegNumPPC_DWARF_r10: return "r10";
+ case eRegNumPPC_DWARF_r11: return "r11";
+ case eRegNumPPC_DWARF_r12: return "r12";
+ case eRegNumPPC_DWARF_r13: return "r13";
+ case eRegNumPPC_DWARF_r14: return "r14";
+ case eRegNumPPC_DWARF_r15: return "r15";
+ case eRegNumPPC_DWARF_r16: return "r16";
+ case eRegNumPPC_DWARF_r17: return "r17";
+ case eRegNumPPC_DWARF_r18: return "r18";
+ case eRegNumPPC_DWARF_r19: return "r19";
+ case eRegNumPPC_DWARF_r20: return "r20";
+ case eRegNumPPC_DWARF_r21: return "r21";
+ case eRegNumPPC_DWARF_r22: return "r22";
+ case eRegNumPPC_DWARF_r23: return "r23";
+ case eRegNumPPC_DWARF_r24: return "r24";
+ case eRegNumPPC_DWARF_r25: return "r25";
+ case eRegNumPPC_DWARF_r26: return "r26";
+ case eRegNumPPC_DWARF_r27: return "r27";
+ case eRegNumPPC_DWARF_r28: return "r28";
+ case eRegNumPPC_DWARF_r29: return "r29";
+ case eRegNumPPC_DWARF_r30: return "r30";
+ case eRegNumPPC_DWARF_r31: return "r31";
+
+ case eRegNumPPC_DWARF_fr0: return "fr0";
+ case eRegNumPPC_DWARF_fr1: return "fr1";
+ case eRegNumPPC_DWARF_fr2: return "fr2";
+ case eRegNumPPC_DWARF_fr3: return "fr3";
+ case eRegNumPPC_DWARF_fr4: return "fr4";
+ case eRegNumPPC_DWARF_fr5: return "fr5";
+ case eRegNumPPC_DWARF_fr6: return "fr6";
+ case eRegNumPPC_DWARF_fr7: return "fr7";
+ case eRegNumPPC_DWARF_fr8: return "fr8";
+ case eRegNumPPC_DWARF_fr9: return "fr9";
+ case eRegNumPPC_DWARF_fr10: return "fr10";
+ case eRegNumPPC_DWARF_fr11: return "fr11";
+ case eRegNumPPC_DWARF_fr12: return "fr12";
+ case eRegNumPPC_DWARF_fr13: return "fr13";
+ case eRegNumPPC_DWARF_fr14: return "fr14";
+ case eRegNumPPC_DWARF_fr15: return "fr15";
+ case eRegNumPPC_DWARF_fr16: return "fr16";
+ case eRegNumPPC_DWARF_fr17: return "fr17";
+ case eRegNumPPC_DWARF_fr18: return "fr18";
+ case eRegNumPPC_DWARF_fr19: return "fr19";
+ case eRegNumPPC_DWARF_fr20: return "fr20";
+ case eRegNumPPC_DWARF_fr21: return "fr21";
+ case eRegNumPPC_DWARF_fr22: return "fr22";
+ case eRegNumPPC_DWARF_fr23: return "fr23";
+ case eRegNumPPC_DWARF_fr24: return "fr24";
+ case eRegNumPPC_DWARF_fr25: return "fr25";
+ case eRegNumPPC_DWARF_fr26: return "fr26";
+ case eRegNumPPC_DWARF_fr27: return "fr27";
+ case eRegNumPPC_DWARF_fr28: return "fr28";
+ case eRegNumPPC_DWARF_fr29: return "fr29";
+ case eRegNumPPC_DWARF_fr30: return "fr30";
+ case eRegNumPPC_DWARF_fr31: return "fr31";
+
+ case eRegNumPPC_DWARF_cr: return "cr";
+ case eRegNumPPC_DWARF_fpscr: return "fpscr";
+ case eRegNumPPC_DWARF_msr: return "msr";
+ case eRegNumPPC_DWARF_vscr: return "vscr";
+
+ case eRegNumPPC_DWARF_sr0: return "sr0";
+ case eRegNumPPC_DWARF_sr1: return "sr1";
+ case eRegNumPPC_DWARF_sr2: return "sr2";
+ case eRegNumPPC_DWARF_sr3: return "sr3";
+ case eRegNumPPC_DWARF_sr4: return "sr4";
+ case eRegNumPPC_DWARF_sr5: return "sr5";
+ case eRegNumPPC_DWARF_sr6: return "sr6";
+ case eRegNumPPC_DWARF_sr7: return "sr7";
+ case eRegNumPPC_DWARF_sr8: return "sr8";
+ case eRegNumPPC_DWARF_sr9: return "sr9";
+ case eRegNumPPC_DWARF_sr10: return "sr10";
+ case eRegNumPPC_DWARF_sr11: return "sr11";
+ case eRegNumPPC_DWARF_sr12: return "sr12";
+ case eRegNumPPC_DWARF_sr13: return "sr13";
+ case eRegNumPPC_DWARF_sr14: return "sr14";
+ case eRegNumPPC_DWARF_sr15: return "sr15";
+
+ case eRegNumPPC_DWARF_acc: return "acc";
+ case eRegNumPPC_DWARF_mq: return "mq";
+ case eRegNumPPC_DWARF_xer: return "xer";
+ case eRegNumPPC_DWARF_rtcu: return "rtcu";
+ case eRegNumPPC_DWARF_rtcl: return "rtcl";
+
+ case eRegNumPPC_DWARF_lr: return "lr";
+ case eRegNumPPC_DWARF_ctr: return "ctr";
+
+ case eRegNumPPC_DWARF_dsisr: return "dsisr";
+ case eRegNumPPC_DWARF_dar: return "dar";
+ case eRegNumPPC_DWARF_dec: return "dec";
+ case eRegNumPPC_DWARF_sdr1: return "sdr1";
+ case eRegNumPPC_DWARF_srr0: return "srr0";
+ case eRegNumPPC_DWARF_srr1: return "srr1";
+
+ case eRegNumPPC_DWARF_vrsave: return "vrsave";
+
+ case eRegNumPPC_DWARF_sprg0: return "sprg0";
+ case eRegNumPPC_DWARF_sprg1: return "sprg1";
+ case eRegNumPPC_DWARF_sprg2: return "sprg2";
+ case eRegNumPPC_DWARF_sprg3: return "sprg3";
+
+ case eRegNumPPC_DWARF_asr: return "asr";
+ case eRegNumPPC_DWARF_ear: return "ear";
+ case eRegNumPPC_DWARF_tb: return "tb";
+ case eRegNumPPC_DWARF_tbu: return "tbu";
+ case eRegNumPPC_DWARF_pvr: return "pvr";
+
+ case eRegNumPPC_DWARF_spefscr: return "spefscr";
+
+ case eRegNumPPC_DWARF_ibat0u: return "ibat0u";
+ case eRegNumPPC_DWARF_ibat0l: return "ibat0l";
+ case eRegNumPPC_DWARF_ibat1u: return "ibat1u";
+ case eRegNumPPC_DWARF_ibat1l: return "ibat1l";
+ case eRegNumPPC_DWARF_ibat2u: return "ibat2u";
+ case eRegNumPPC_DWARF_ibat2l: return "ibat2l";
+ case eRegNumPPC_DWARF_ibat3u: return "ibat3u";
+ case eRegNumPPC_DWARF_ibat3l: return "ibat3l";
+ case eRegNumPPC_DWARF_dbat0u: return "dbat0u";
+ case eRegNumPPC_DWARF_dbat0l: return "dbat0l";
+ case eRegNumPPC_DWARF_dbat1u: return "dbat1u";
+ case eRegNumPPC_DWARF_dbat1l: return "dbat1l";
+ case eRegNumPPC_DWARF_dbat2u: return "dbat2u";
+ case eRegNumPPC_DWARF_dbat2l: return "dbat2l";
+ case eRegNumPPC_DWARF_dbat3u: return "dbat3u";
+ case eRegNumPPC_DWARF_dbat3l: return "dbat3l";
+
+ case eRegNumPPC_DWARF_hid0: return "hid0";
+ case eRegNumPPC_DWARF_hid1: return "hid1";
+ case eRegNumPPC_DWARF_hid2: return "hid2";
+ case eRegNumPPC_DWARF_hid3: return "hid3";
+ case eRegNumPPC_DWARF_hid4: return "hid4";
+ case eRegNumPPC_DWARF_hid5: return "hid5";
+ case eRegNumPPC_DWARF_hid6: return "hid6";
+ case eRegNumPPC_DWARF_hid7: return "hid7";
+ case eRegNumPPC_DWARF_hid8: return "hid8";
+ case eRegNumPPC_DWARF_hid9: return "hid9";
+ case eRegNumPPC_DWARF_hid10: return "hid10";
+ case eRegNumPPC_DWARF_hid11: return "hid11";
+ case eRegNumPPC_DWARF_hid12: return "hid12";
+ case eRegNumPPC_DWARF_hid13: return "hid13";
+ case eRegNumPPC_DWARF_hid14: return "hid14";
+ case eRegNumPPC_DWARF_hid15: return "hid15";
+
+ case eRegNumPPC_DWARF_vr0: return "vr0";
+ case eRegNumPPC_DWARF_vr1: return "vr1";
+ case eRegNumPPC_DWARF_vr2: return "vr2";
+ case eRegNumPPC_DWARF_vr3: return "vr3";
+ case eRegNumPPC_DWARF_vr4: return "vr4";
+ case eRegNumPPC_DWARF_vr5: return "vr5";
+ case eRegNumPPC_DWARF_vr6: return "vr6";
+ case eRegNumPPC_DWARF_vr7: return "vr7";
+ case eRegNumPPC_DWARF_vr8: return "vr8";
+ case eRegNumPPC_DWARF_vr9: return "vr9";
+ case eRegNumPPC_DWARF_vr10: return "vr10";
+ case eRegNumPPC_DWARF_vr11: return "vr11";
+ case eRegNumPPC_DWARF_vr12: return "vr12";
+ case eRegNumPPC_DWARF_vr13: return "vr13";
+ case eRegNumPPC_DWARF_vr14: return "vr14";
+ case eRegNumPPC_DWARF_vr15: return "vr15";
+ case eRegNumPPC_DWARF_vr16: return "vr16";
+ case eRegNumPPC_DWARF_vr17: return "vr17";
+ case eRegNumPPC_DWARF_vr18: return "vr18";
+ case eRegNumPPC_DWARF_vr19: return "vr19";
+ case eRegNumPPC_DWARF_vr20: return "vr20";
+ case eRegNumPPC_DWARF_vr21: return "vr21";
+ case eRegNumPPC_DWARF_vr22: return "vr22";
+ case eRegNumPPC_DWARF_vr23: return "vr23";
+ case eRegNumPPC_DWARF_vr24: return "vr24";
+ case eRegNumPPC_DWARF_vr25: return "vr25";
+ case eRegNumPPC_DWARF_vr26: return "vr26";
+ case eRegNumPPC_DWARF_vr27: return "vr27";
+ case eRegNumPPC_DWARF_vr28: return "vr28";
+ case eRegNumPPC_DWARF_vr29: return "vr29";
+ case eRegNumPPC_DWARF_vr30: return "vr30";
+ case eRegNumPPC_DWARF_vr31: return "vr31";
+
+ case eRegNumPPC_DWARF_ev0: return "ev0";
+ case eRegNumPPC_DWARF_ev1: return "ev1";
+ case eRegNumPPC_DWARF_ev2: return "ev2";
+ case eRegNumPPC_DWARF_ev3: return "ev3";
+ case eRegNumPPC_DWARF_ev4: return "ev4";
+ case eRegNumPPC_DWARF_ev5: return "ev5";
+ case eRegNumPPC_DWARF_ev6: return "ev6";
+ case eRegNumPPC_DWARF_ev7: return "ev7";
+ case eRegNumPPC_DWARF_ev8: return "ev8";
+ case eRegNumPPC_DWARF_ev9: return "ev9";
+ case eRegNumPPC_DWARF_ev10: return "ev10";
+ case eRegNumPPC_DWARF_ev11: return "ev11";
+ case eRegNumPPC_DWARF_ev12: return "ev12";
+ case eRegNumPPC_DWARF_ev13: return "ev13";
+ case eRegNumPPC_DWARF_ev14: return "ev14";
+ case eRegNumPPC_DWARF_ev15: return "ev15";
+ case eRegNumPPC_DWARF_ev16: return "ev16";
+ case eRegNumPPC_DWARF_ev17: return "ev17";
+ case eRegNumPPC_DWARF_ev18: return "ev18";
+ case eRegNumPPC_DWARF_ev19: return "ev19";
+ case eRegNumPPC_DWARF_ev20: return "ev20";
+ case eRegNumPPC_DWARF_ev21: return "ev21";
+ case eRegNumPPC_DWARF_ev22: return "ev22";
+ case eRegNumPPC_DWARF_ev23: return "ev23";
+ case eRegNumPPC_DWARF_ev24: return "ev24";
+ case eRegNumPPC_DWARF_ev25: return "ev25";
+ case eRegNumPPC_DWARF_ev26: return "ev26";
+ case eRegNumPPC_DWARF_ev27: return "ev27";
+ case eRegNumPPC_DWARF_ev28: return "ev28";
+ case eRegNumPPC_DWARF_ev29: return "ev29";
+ case eRegNumPPC_DWARF_ev30: return "ev30";
+ case eRegNumPPC_DWARF_ev31: return "ev31";
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Returns true if this object contains a valid architecture, false
+// otherwise.
+//----------------------------------------------------------------------
+bool
+ArchSpec::IsValid() const
+{
+ return !(m_cpu == LLDB_INVALID_CPUTYPE);
+}
+
+//----------------------------------------------------------------------
+// Returns true if this architecture is 64 bit, otherwise 32 bit is
+// assumed and false is returned.
+//----------------------------------------------------------------------
+uint32_t
+ArchSpec::GetAddressByteSize() const
+{
+ if (GetCPUType() & CPU_ARCH_ABI64)
+ return 8;
+ return 4;
+}
+
+//----------------------------------------------------------------------
+// Returns the number of bytes that this object takes when an
+// instance exists in memory.
+//----------------------------------------------------------------------
+size_t
+ArchSpec::MemorySize() const
+{
+ return sizeof(ArchSpec);
+}
+
+bool
+ArchSpec::SetArchFromTargetTriple (const char *target_triple)
+{
+ if (target_triple)
+ {
+ const char *hyphen = strchr(target_triple, '-');
+ if (hyphen)
+ {
+ std::string arch_only (target_triple, hyphen);
+ return SetArch (arch_only.c_str());
+ }
+ }
+ return SetArch (target_triple);
+}
+
+//----------------------------------------------------------------------
+// Change the CPU type and subtype given an architecture name.
+//----------------------------------------------------------------------
+bool
+ArchSpec::SetArch(const char *arch_name)
+{
+ if (arch_name && arch_name[0] != '\0')
+ {
+ size_t i;
+ // Search for ARCH_NAME in our architecture definitions structure
+ for (i=0; i<k_num_arch_defs; ++i)
+ {
+ if (strcasecmp(arch_name, g_arch_defs[i].name) == 0)
+ {
+ // we found a match
+ m_cpu = g_arch_defs[i].cpu;
+ m_sub = g_arch_defs[i].sub;
+ return true;
+ }
+ }
+
+
+ const char *str = arch_name;
+ char *end = NULL;
+ // Check for a numeric cpu followed by an optional '.' and numeric subtype.
+ // This allows for support of new cpu type/subtypes without having to have
+ // a recompiled debug core.
+ // Examples:
+ // "12.6" is armv6
+ // "0x0000000c.0x00000006" is also armv6
+ m_cpu = strtoul(str, &end, 0);
+ if (str != end)
+ {
+ if (*end == '.')
+ {
+ // We have a cputype.cpusubtype format
+ str = end + 1;
+ if (*str != '\0')
+ {
+ m_sub = strtoul(str, &end, 0);
+ if (*end == '\0')
+ {
+ // We consumed the entire string and got a cpu type and subtype
+ return true;
+ }
+ }
+ }
+
+ // If we reach this point we have a valid cpu type, but no cpu subtype.
+ // Search for the first matching cpu type and use the corresponding cpu
+ // subtype. This setting should typically be the _ALL variant and should
+ // appear first in the list for each cpu type in the g_arch_defs
+ // structure.
+ for (i=0; i<k_num_arch_defs; ++i)
+ {
+ if (m_cpu == g_arch_defs[i].cpu)
+ {
+ m_sub = g_arch_defs[i].sub;
+ return true;
+ }
+ }
+
+ // Default the cpu subtype to zero when we don't have a matching
+ // cpu type in our architecture defs structure (g_arch_defs).
+ m_sub = 0;
+ return true;
+
+ }
+ }
+ m_cpu = LLDB_INVALID_CPUTYPE;
+ m_sub = 0;
+ return false;
+}
+
+//----------------------------------------------------------------------
+// CPU type and subtype set accessor.
+//----------------------------------------------------------------------
+void
+ArchSpec::SetArch (uint32_t cpu_type, uint32_t cpu_subtype)
+{
+ m_cpu = cpu_type;
+ m_sub = cpu_subtype;
+}
+
+//----------------------------------------------------------------------
+// CPU type set accessor.
+//----------------------------------------------------------------------
+void
+ArchSpec::SetCPUType (uint32_t cpu)
+{
+ m_cpu = cpu;
+}
+
+//----------------------------------------------------------------------
+// CPU subtype set accessor.
+//----------------------------------------------------------------------
+void
+ArchSpec::SetCPUSubtype (uint32_t subtype)
+{
+ m_sub = subtype;
+}
+
+ByteOrder
+ArchSpec::GetDefaultEndian () const
+{
+ switch (m_cpu)
+ {
+ case CPU_TYPE_POWERPC:
+ case CPU_TYPE_POWERPC64:
+ return eByteOrderBig;
+
+ case CPU_TYPE_ARM:
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ return eByteOrderLittle;
+
+ default:
+ break;
+ }
+ return eByteOrderInvalid;
+}
+
+//----------------------------------------------------------------------
+// Equal operator
+//----------------------------------------------------------------------
+bool
+lldb_private::operator== (const ArchSpec& lhs, const ArchSpec& rhs)
+{
+ uint32_t lhs_cpu = lhs.GetCPUType();
+ uint32_t rhs_cpu = rhs.GetCPUType();
+
+ if (lhs_cpu == CPU_TYPE_ANY || rhs_cpu == CPU_TYPE_ANY)
+ return true;
+
+ else if (lhs_cpu == rhs_cpu)
+ {
+ uint32_t lhs_subtype = lhs.GetCPUSubtype();
+ uint32_t rhs_subtype = rhs.GetCPUSubtype();
+ if (lhs_subtype == CPU_TYPE_ANY || rhs_subtype == CPU_TYPE_ANY)
+ return true;
+ return lhs_subtype == rhs_subtype;
+ }
+ return false;
+}
+
+
+//----------------------------------------------------------------------
+// Not Equal operator
+//----------------------------------------------------------------------
+bool
+lldb_private::operator!= (const ArchSpec& lhs, const ArchSpec& rhs)
+{
+ return !(lhs == rhs);
+}
+
+//----------------------------------------------------------------------
+// Less than operator
+//----------------------------------------------------------------------
+bool
+lldb_private::operator<(const ArchSpec& lhs, const ArchSpec& rhs)
+{
+ uint32_t lhs_cpu = lhs.GetCPUType();
+ uint32_t rhs_cpu = rhs.GetCPUType();
+
+ if (lhs_cpu == rhs_cpu)
+ return lhs.GetCPUSubtype() < rhs.GetCPUSubtype();
+
+ return lhs_cpu < rhs_cpu;
+}
+
diff --git a/lldb/source/Core/Args.cpp b/lldb/source/Core/Args.cpp
new file mode 100644
index 00000000000..7cb137555d1
--- /dev/null
+++ b/lldb/source/Core/Args.cpp
@@ -0,0 +1,1179 @@
+//===-- Args.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 <getopt.h>
+#include <histedit.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Options.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+namespace lldb_private {
+
+class Tokenizer
+{
+public:
+ Tokenizer (const char *separator_chars = NULL) :
+ m_tokenizer(NULL)
+ {
+ m_tokenizer = ::tok_init (separator_chars);
+ }
+
+ ~Tokenizer ()
+ {
+ if (m_tokenizer)
+ {
+ ::tok_end (m_tokenizer);
+ m_tokenizer = NULL;
+ }
+ }
+
+ void
+ Reset ()
+ {
+ assert (m_tokenizer);
+ ::tok_reset (m_tokenizer);
+ }
+
+ int
+ TokenizeLineInfo (const ::LineInfo *line_info)
+ {
+ assert (m_tokenizer);
+ return ::tok_line (m_tokenizer,
+ line_info,
+ &m_argc,
+ &m_argv,
+ &m_cursor_arg_index,
+ &m_cursor_arg_offset);
+ }
+
+ int
+ TokenizeCString (const char *cstr)
+ {
+ assert (m_tokenizer);
+ m_cursor_arg_index = -1;
+ m_cursor_arg_offset = -1;
+ return ::tok_str (m_tokenizer,
+ cstr,
+ &m_argc,
+ &m_argv);
+ }
+
+
+ int
+ GetArgCount () const
+ {
+ return m_argc;
+ }
+
+ const char **
+ GetArgVector () const
+ {
+ return m_argv;
+ }
+
+ int
+ GetCursoreArgIndex () const
+ {
+ return m_cursor_arg_index;
+ }
+
+ int
+ GetCursoreArgOffset () const
+ {
+ return m_cursor_arg_offset;
+ }
+
+
+protected:
+ struct tokenizer* m_tokenizer;
+ const char **m_argv;
+ int m_argc;
+ int m_cursor_arg_index;
+ int m_cursor_arg_offset;
+};
+
+} // namespace lldb_private
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const char *k_space_characters = "\t\n\v\f\r ";
+static const char *k_space_characters_with_slash = "\t\n\v\f\r \\";
+
+
+//----------------------------------------------------------------------
+// Args constructor
+//----------------------------------------------------------------------
+Args::Args (const char *command) :
+ m_args(),
+ m_argv()
+{
+ SetCommandString (command);
+}
+
+
+Args::Args (const char *command, size_t len) :
+ m_args(),
+ m_argv()
+{
+ SetCommandString (command, len);
+}
+
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Args::~Args ()
+{
+}
+
+void
+Args::Dump (Stream *s)
+{
+// int argc = GetArgumentCount();
+//
+// arg_sstr_collection::const_iterator pos, begin = m_args.begin(), end = m_args.end();
+// for (pos = m_args.begin(); pos != end; ++pos)
+// {
+// s->Indent();
+// s->Printf("args[%zu]=%s\n", std::distance(begin, pos), pos->c_str());
+// }
+// s->EOL();
+ const int argc = m_argv.size();
+ for (int i=0; i<argc; ++i)
+ {
+ s->Indent();
+ const char *arg_cstr = m_argv[i];
+ if (arg_cstr)
+ s->Printf("argv[%i]=\"%s\"\n", i, arg_cstr);
+ else
+ s->Printf("argv[%i]=NULL\n", i);
+ }
+ s->EOL();
+}
+
+bool
+Args::GetCommandString (std::string &command)
+{
+ command.clear();
+ int argc = GetArgumentCount();
+ for (int i=0; i<argc; ++i)
+ {
+ if (i > 0)
+ command += ' ';
+ command += m_argv[i];
+ }
+ return argc > 0;
+}
+
+void
+Args::SetCommandString (const char *command, size_t len)
+{
+ // Use std::string to make sure we get a NULL terminated string we can use
+ // as "command" could point to a string within a large string....
+ std::string null_terminated_command(command, len);
+ SetCommandString(null_terminated_command.c_str());
+}
+
+void
+Args::SetCommandString (const char *command)
+{
+ m_args.clear();
+ m_argv.clear();
+ if (command && command[0])
+ {
+ const char *arg_start;
+ const char *next_arg_start;
+ for (arg_start = command, next_arg_start = NULL;
+ arg_start && arg_start[0];
+ arg_start = next_arg_start, next_arg_start = NULL)
+ {
+ // Skip any leading space characters
+ arg_start = ::strspn (arg_start, k_space_characters) + arg_start;
+
+ // If there were only space characters to the end of the line, then
+ // we're done.
+ if (*arg_start == '\0')
+ break;
+
+ std::string arg;
+ const char *arg_end = NULL;
+
+ switch (*arg_start)
+ {
+ case '\'':
+ case '"':
+ case '`':
+ {
+ // Look for either a quote character, or the backslash
+ // character
+ const char quote_char = *arg_start;
+ char find_chars[3] = { quote_char, '\\' , '\0'};
+ bool is_backtick = (quote_char == '`');
+ if (quote_char == '"' || quote_char == '`')
+ m_args_quote_char.push_back(quote_char);
+ else
+ m_args_quote_char.push_back('\0');
+
+ while (*arg_start != '\0')
+ {
+ arg_end = ::strcspn (arg_start + 1, find_chars) + arg_start + 1;
+
+ if (*arg_end == '\0')
+ {
+ arg.append (arg_start);
+ break;
+ }
+
+ // Watch out for quote characters prefixed with '\'
+ if (*arg_end == '\\')
+ {
+ if (arg_end[1] == quote_char)
+ {
+ // The character following the '\' is our quote
+ // character so strip the backslash character
+ arg.append (arg_start, arg_end);
+ }
+ else
+ {
+ // The character following the '\' is NOT our
+ // quote character, so include the backslash
+ // and continue
+ arg.append (arg_start, arg_end + 1);
+ }
+ arg_start = arg_end + 1;
+ continue;
+ }
+ else
+ {
+ arg.append (arg_start, arg_end + 1);
+ next_arg_start = arg_end + 1;
+ break;
+ }
+ }
+
+ // Skip single and double quotes, but leave backtick quotes
+ if (!is_backtick)
+ {
+ char first_c = arg[0];
+ arg.erase(0,1);
+ // Only erase the last character if it is the same as the first.
+ // Otherwise, we're parsing an incomplete command line, and we
+ // would be stripping off the last character of that string.
+ if (arg[arg.size() - 1] == first_c)
+ arg.erase(arg.size() - 1, 1);
+ }
+ }
+ break;
+ default:
+ {
+ m_args_quote_char.push_back('\0');
+ // Look for the next non-escaped space character
+ while (*arg_start != '\0')
+ {
+ arg_end = ::strcspn (arg_start, k_space_characters_with_slash) + arg_start;
+
+ if (arg_end == NULL)
+ {
+ arg.append(arg_start);
+ break;
+ }
+
+ if (*arg_end == '\\')
+ {
+ // Append up to the '\' char
+ arg.append (arg_start, arg_end);
+
+ if (arg_end[1] == '\0')
+ break;
+
+ // Append the character following the '\' if it isn't
+ // the end of the string
+ arg.append (1, arg_end[1]);
+ arg_start = arg_end + 2;
+ continue;
+ }
+ else
+ {
+ arg.append (arg_start, arg_end);
+ next_arg_start = arg_end;
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ m_args.push_back(arg);
+ }
+ }
+ UpdateArgvFromArgs();
+}
+
+void
+Args::UpdateArgsAfterOptionParsing()
+{
+ // Now m_argv might be out of date with m_args, so we need to fix that
+ arg_cstr_collection::const_iterator argv_pos, argv_end = m_argv.end();
+ arg_sstr_collection::iterator args_pos;
+ arg_quote_char_collection::iterator quotes_pos;
+
+ for (argv_pos = m_argv.begin(), args_pos = m_args.begin(), quotes_pos = m_args_quote_char.begin();
+ argv_pos != argv_end && args_pos != m_args.end();
+ ++argv_pos)
+ {
+ const char *argv_cstr = *argv_pos;
+ if (argv_cstr == NULL)
+ break;
+
+ while (args_pos != m_args.end())
+ {
+ const char *args_cstr = args_pos->c_str();
+ if (args_cstr == argv_cstr)
+ {
+ // We found the argument that matches the C string in the
+ // vector, so we can now look for the next one
+ ++args_pos;
+ ++quotes_pos;
+ break;
+ }
+ else
+ {
+ quotes_pos = m_args_quote_char.erase (quotes_pos);
+ args_pos = m_args.erase (args_pos);
+ }
+ }
+ }
+
+ if (args_pos != m_args.end())
+ m_args.erase (args_pos, m_args.end());
+
+ if (quotes_pos != m_args_quote_char.end())
+ m_args_quote_char.erase (quotes_pos, m_args_quote_char.end());
+}
+
+void
+Args::UpdateArgvFromArgs()
+{
+ m_argv.clear();
+ arg_sstr_collection::const_iterator pos, end = m_args.end();
+ for (pos = m_args.begin(); pos != end; ++pos)
+ m_argv.push_back(pos->c_str());
+ m_argv.push_back(NULL);
+}
+
+size_t
+Args::GetArgumentCount() const
+{
+ if (m_argv.empty())
+ return 0;
+ return m_argv.size() - 1;
+}
+
+const char *
+Args::GetArgumentAtIndex (size_t idx) const
+{
+ if (idx < m_argv.size())
+ return m_argv[idx];
+ return NULL;
+}
+
+char
+Args::GetArgumentQuoteCharAtIndex (size_t idx) const
+{
+ if (idx < m_args_quote_char.size())
+ return m_args_quote_char[idx];
+ return '\0';
+}
+
+char **
+Args::GetArgumentVector()
+{
+ if (!m_argv.empty())
+ return (char **)&m_argv[0];
+ return NULL;
+}
+
+const char **
+Args::GetConstArgumentVector() const
+{
+ if (!m_argv.empty())
+ return (const char **)&m_argv[0];
+ return NULL;
+}
+
+void
+Args::Shift ()
+{
+ // Don't pop the last NULL terminator from the argv array
+ if (m_argv.size() > 1)
+ {
+ m_argv.erase(m_argv.begin());
+ m_args.pop_front();
+ m_args_quote_char.erase(m_args_quote_char.begin());
+ }
+}
+
+const char *
+Args::Unshift (const char *arg_cstr, char quote_char)
+{
+ m_args.push_front(arg_cstr);
+ m_argv.insert(m_argv.begin(), m_args.front().c_str());
+ m_args_quote_char.insert(m_args_quote_char.begin(), quote_char);
+ return GetArgumentAtIndex (0);
+}
+
+void
+Args::AppendArguments (const Args &rhs)
+{
+ const size_t rhs_argc = rhs.GetArgumentCount();
+ for (size_t i=0; i<rhs_argc; ++i)
+ AppendArgument(rhs.GetArgumentAtIndex(i));
+}
+
+const char *
+Args::AppendArgument (const char *arg_cstr, char quote_char)
+{
+ return InsertArgumentAtIndex (GetArgumentCount(), arg_cstr, quote_char);
+}
+
+const char *
+Args::InsertArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char)
+{
+ // Since we are using a std::list to hold onto the copied C string and
+ // we don't have direct access to the elements, we have to iterate to
+ // find the value.
+ arg_sstr_collection::iterator pos, end = m_args.end();
+ size_t i = idx;
+ for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
+ --i;
+
+ pos = m_args.insert(pos, arg_cstr);
+
+
+ m_args_quote_char.insert(m_args_quote_char.begin() + idx, quote_char);
+
+ UpdateArgvFromArgs();
+ return GetArgumentAtIndex(idx);
+}
+
+const char *
+Args::ReplaceArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char)
+{
+ // Since we are using a std::list to hold onto the copied C string and
+ // we don't have direct access to the elements, we have to iterate to
+ // find the value.
+ arg_sstr_collection::iterator pos, end = m_args.end();
+ size_t i = idx;
+ for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
+ --i;
+
+ if (pos != end)
+ {
+ pos->assign(arg_cstr);
+ assert(idx < m_argv.size() - 1);
+ m_argv[idx] = pos->c_str();
+ m_args_quote_char[idx] = quote_char;
+ return GetArgumentAtIndex(idx);
+ }
+ return NULL;
+}
+
+void
+Args::DeleteArgumentAtIndex (size_t idx)
+{
+ // Since we are using a std::list to hold onto the copied C string and
+ // we don't have direct access to the elements, we have to iterate to
+ // find the value.
+ arg_sstr_collection::iterator pos, end = m_args.end();
+ size_t i = idx;
+ for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
+ --i;
+
+ if (pos != end)
+ {
+ m_args.erase (pos);
+ assert(idx < m_argv.size() - 1);
+ m_argv.erase(m_argv.begin() + idx);
+ m_args_quote_char.erase(m_args_quote_char.begin() + idx);
+ }
+}
+
+void
+Args::SetArguments (int argc, const char **argv)
+{
+ // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is
+ // no need to clear it here.
+ m_args.clear();
+ m_args_quote_char.clear();
+
+ // Make a copy of the arguments in our internal buffer
+ size_t i;
+ // First copy each string
+ for (i=0; i<argc; ++i)
+ {
+ m_args.push_back (argv[i]);
+ if ((argv[i][0] == '"') || (argv[i][0] == '`'))
+ m_args_quote_char.push_back (argv[i][0]);
+ else
+ m_args_quote_char.push_back ('\0');
+ }
+
+ UpdateArgvFromArgs();
+}
+
+
+Error
+Args::ParseOptions (Options &options)
+{
+ StreamString sstr;
+ int i;
+ Error error;
+ struct option *long_options = options.GetLongOptions();
+ if (long_options == NULL)
+ {
+ error.SetErrorStringWithFormat("Invalid long options.\n");
+ return error;
+ }
+
+ for (i=0; long_options[i].name != NULL; ++i)
+ {
+ if (long_options[i].flag == NULL)
+ {
+ sstr << (char)long_options[i].val;
+ switch (long_options[i].has_arg)
+ {
+ default:
+ case no_argument: break;
+ case required_argument: sstr << ':'; break;
+ case optional_argument: sstr << "::"; break;
+ }
+ }
+ }
+ optreset = 1;
+ optind = 1;
+ int val;
+ while (1)
+ {
+ int long_options_index = -1;
+ val = ::getopt_long(GetArgumentCount(), GetArgumentVector(), sstr.GetData(), long_options,
+ &long_options_index);
+ if (val == -1)
+ break;
+
+ // Did we get an error?
+ if (val == '?')
+ {
+ error.SetErrorStringWithFormat("Unknown or ambiguous option.\n");
+ break;
+ }
+ // The option auto-set itself
+ if (val == 0)
+ continue;
+
+ ((Options *) &options)->OptionSeen (val);
+
+ // Lookup the long option index
+ if (long_options_index == -1)
+ {
+ for (int i=0;
+ long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val;
+ ++i)
+ {
+ if (long_options[i].val == val)
+ {
+ long_options_index = i;
+ break;
+ }
+ }
+ }
+ // Call the callback with the option
+ if (long_options_index >= 0)
+ {
+ error = options.SetOptionValue(long_options_index,
+ long_options[long_options_index].has_arg == no_argument ? NULL : optarg);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("Invalid option with value '%i'.\n", val);
+ }
+ if (error.Fail())
+ break;
+ }
+
+ // Update our ARGV now that get options has consumed all the options
+ m_argv.erase(m_argv.begin(), m_argv.begin() + optind);
+ UpdateArgsAfterOptionParsing ();
+ return error;
+}
+
+void
+Args::Clear ()
+{
+ m_args.clear ();
+ m_argv.clear ();
+ m_args_quote_char.clear();
+}
+
+int32_t
+Args::StringToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ char *end = NULL;
+ int32_t uval = ::strtol (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr) *success_ptr = true;
+ return uval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+uint32_t
+Args::StringToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ char *end = NULL;
+ uint32_t uval = ::strtoul (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr) *success_ptr = true;
+ return uval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+
+int64_t
+Args::StringToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ char *end = NULL;
+ int64_t uval = ::strtoll (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr) *success_ptr = true;
+ return uval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+uint64_t
+Args::StringToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ char *end = NULL;
+ uint64_t uval = ::strtoull (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr) *success_ptr = true;
+ return uval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+lldb::addr_t
+Args::StringToAddress (const char *s, lldb::addr_t fail_value, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ char *end = NULL;
+ lldb::addr_t addr = ::strtoull (s, &end, 0);
+ if (*end == '\0')
+ {
+ if (success_ptr) *success_ptr = true;
+ return addr; // All characters were used, return the result
+ }
+ // Try base 16 with no prefix...
+ addr = ::strtoull (s, &end, 16);
+ if (*end == '\0')
+ {
+ if (success_ptr) *success_ptr = true;
+ return addr; // All characters were used, return the result
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+bool
+Args::StringToBoolean (const char *s, bool fail_value, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ if (::strcasecmp (s, "false") == 0 ||
+ ::strcasecmp (s, "off") == 0 ||
+ ::strcasecmp (s, "no") == 0 ||
+ ::strcmp (s, "0") == 0)
+ {
+ if (success_ptr)
+ *success_ptr = true;
+ return false;
+ }
+ else
+ if (::strcasecmp (s, "true") == 0 ||
+ ::strcasecmp (s, "on") == 0 ||
+ ::strcasecmp (s, "yes") == 0 ||
+ ::strcmp (s, "1") == 0)
+ {
+ if (success_ptr) *success_ptr = true;
+ return true;
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+int32_t
+Args::StringToOptionEnum (const char *s, lldb::OptionEnumValueElement *enum_values, int32_t fail_value, bool *success_ptr)
+{
+ if (enum_values && s && s[0])
+ {
+ for (int i = 0; enum_values[i].string_value != NULL ; i++)
+ {
+ if (strstr(enum_values[i].string_value, s) == enum_values[i].string_value)
+ {
+ if (success_ptr) *success_ptr = true;
+ return enum_values[i].value;
+ }
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+
+ return fail_value;
+}
+
+ScriptLanguage
+Args::StringToScriptLanguage (const char *s, ScriptLanguage fail_value, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ if ((::strcasecmp (s, "python") == 0) ||
+ (::strcasecmp (s, "default") == 0 && eScriptLanguagePython == eScriptLanguageDefault))
+ {
+ if (success_ptr) *success_ptr = true;
+ return eScriptLanguagePython;
+ }
+ if (::strcasecmp (s, "none"))
+ {
+ if (success_ptr) *success_ptr = true;
+ return eScriptLanguageNone;
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+Error
+Args::StringToFormat
+(
+ const char *s,
+ lldb::Format &format
+)
+{
+ format = eFormatInvalid;
+ Error error;
+
+ if (s && s[0])
+ {
+ switch (s[0])
+ {
+ case 'y': format = eFormatBytes; break;
+ case 'Y': format = eFormatBytesWithASCII; break;
+ case 'b': format = eFormatBinary; break;
+ case 'B': format = eFormatBoolean; break;
+ case 'c': format = eFormatChar; break;
+ case 'C': format = eFormatCharPrintable; break;
+ case 'o': format = eFormatOctal; break;
+ case 'i':
+ case 'd': format = eFormatDecimal; break;
+ case 'u': format = eFormatUnsigned; break;
+ case 'x': format = eFormatHex; break;
+ case 'f':
+ case 'e':
+ case 'g': format = eFormatFloat; break;
+ case 'p': format = eFormatPointer; break;
+ case 's': format = eFormatCString; break;
+ default:
+ error.SetErrorStringWithFormat("Invalid format character '%c'. Valid values are:\n"
+ " b - binary\n"
+ " B - boolean\n"
+ " c - char\n"
+ " C - printable char\n"
+ " d - signed decimal\n"
+ " e - float\n"
+ " f - float\n"
+ " g - float\n"
+ " i - signed decimal\n"
+ " o - octal\n"
+ " s - c-string\n"
+ " u - unsigned decimal\n"
+ " x - hex\n"
+ " y - bytes\n"
+ " Y - bytes with ASCII\n", s[0]);
+ break;
+ }
+
+ if (error.Fail())
+ return error;
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("%s option string.\n", s ? "empty" : "invalid");
+ }
+ return error;
+}
+
+void
+Args::LongestCommonPrefix (std::string &common_prefix)
+{
+ arg_sstr_collection::iterator pos, end = m_args.end();
+ pos = m_args.begin();
+ if (pos == end)
+ common_prefix.clear();
+ else
+ common_prefix = (*pos);
+
+ for (++pos; pos != end; ++pos)
+ {
+ int new_size = (*pos).size();
+
+ // 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 (int i = 0; i < common_prefix.size(); i++)
+ {
+ if ((*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
+Args::ParseAliasOptions
+(
+ Options &options,
+ CommandReturnObject &result,
+ OptionArgVector *option_arg_vector
+)
+{
+ StreamString sstr;
+ int i;
+ struct option *long_options = options.GetLongOptions();
+
+ if (long_options == NULL)
+ {
+ result.AppendError ("invalid long options");
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+
+ for (i = 0; long_options[i].name != NULL; ++i)
+ {
+ if (long_options[i].flag == NULL)
+ {
+ sstr << (char) long_options[i].val;
+ switch (long_options[i].has_arg)
+ {
+ default:
+ case no_argument:
+ break;
+ case required_argument:
+ sstr << ":";
+ break;
+ case optional_argument:
+ sstr << "::";
+ break;
+ }
+ }
+ }
+
+ optreset = 1;
+ optind = 1;
+ int val;
+ while (1)
+ {
+ int long_options_index = -1;
+ val = ::getopt_long (GetArgumentCount(), GetArgumentVector(), sstr.GetData(), long_options,
+ &long_options_index);
+
+ if (val == -1)
+ break;
+
+ if (val == '?')
+ {
+ result.AppendError ("unknown or ambiguous option");
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+
+ if (val == 0)
+ continue;
+
+ ((Options *) &options)->OptionSeen (val);
+
+ // Look up the long option index
+ if (long_options_index == -1)
+ {
+ for (int j = 0;
+ long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val;
+ ++j)
+ {
+ if (long_options[j].val == val)
+ {
+ long_options_index = j;
+ break;
+ }
+ }
+ }
+
+ // See if the option takes an argument, and see if one was supplied.
+ if (long_options_index >= 0)
+ {
+ StreamString option_str;
+ option_str.Printf ("-%c", (char) val);
+
+ switch (long_options[long_options_index].has_arg)
+ {
+ case no_argument:
+ option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), "<no-argument>"));
+ break;
+ case required_argument:
+ if (optarg != NULL)
+ {
+ option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
+ std::string (optarg)));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Option '%s' is missing argument specifier.\n",
+ option_str.GetData());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ break;
+ case optional_argument:
+ if (optarg != NULL)
+ {
+ option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
+ std::string (optarg)));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
+ "<no-argument>"));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ break;
+ default:
+ result.AppendErrorWithFormat
+ ("error with options table; invalid value in has_arg field for option '%c'.\n",
+ (char) val);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid option with value '%c'.\n", (char) val);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ if (!result.Succeeded())
+ break;
+ }
+}
+
+void
+Args::ParseArgsForCompletion
+(
+ Options &options,
+ OptionElementVector &option_element_vector
+)
+{
+ StreamString sstr;
+ int i;
+ struct option *long_options = options.GetLongOptions();
+ option_element_vector.clear();
+
+ if (long_options == NULL)
+ {
+ return;
+ }
+
+ // Leading : tells getopt to return a : for a missing option argument AND
+ // to suppress error messages.
+
+ sstr << ":";
+ for (i = 0; long_options[i].name != NULL; ++i)
+ {
+ if (long_options[i].flag == NULL)
+ {
+ sstr << (char) long_options[i].val;
+ switch (long_options[i].has_arg)
+ {
+ default:
+ case no_argument:
+ break;
+ case required_argument:
+ sstr << ":";
+ break;
+ case optional_argument:
+ sstr << "::";
+ break;
+ }
+ }
+ }
+
+ optreset = 1;
+ optind = 1;
+ opterr = 0;
+
+ int val;
+ const OptionDefinition *opt_defs = options.GetDefinitions();
+
+ // Fooey... getopt_long permutes the GetArgumentVector for no apparent reason.
+ // So we have to build another Arg and pass that to getopt_long so it doesn't
+ // screw up the one we have.
+
+ std::vector<const char *> dummy_vec(GetArgumentVector(), GetArgumentVector() + GetArgumentCount() + 1);
+
+ while (1)
+ {
+ bool missing_argument = false;
+ int parse_start = optind;
+ int long_options_index = -1;
+ val = ::getopt_long (dummy_vec.size() - 1,(char *const *) dummy_vec.data(), sstr.GetData(), long_options,
+ &long_options_index);
+
+ if (val == -1)
+ break;
+
+ else if (val == '?')
+ {
+ option_element_vector.push_back (OptionArgElement (-1, parse_start, -1));
+ continue;
+ }
+ else if (val == 0)
+ {
+ continue;
+ }
+ else if (val == ':')
+ {
+ // This is a missing argument.
+ val = optopt;
+ missing_argument = true;
+ }
+
+ ((Options *) &options)->OptionSeen (val);
+
+ // Look up the long option index
+ if (long_options_index == -1)
+ {
+ for (int j = 0;
+ long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val;
+ ++j)
+ {
+ if (long_options[j].val == val)
+ {
+ long_options_index = j;
+ break;
+ }
+ }
+ }
+
+ // See if the option takes an argument, and see if one was supplied.
+ if (long_options_index >= 0)
+ {
+ int opt_defs_index = -1;
+ for (int i = 0; ; i++)
+ {
+ if (opt_defs[i].short_option == 0)
+ break;
+ else if (opt_defs[i].short_option == val)
+ {
+ opt_defs_index = i;
+ break;
+ }
+ }
+
+ switch (long_options[long_options_index].has_arg)
+ {
+ case no_argument:
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, 0));
+ break;
+ case required_argument:
+ if (optarg != NULL)
+ {
+ int arg_index;
+ if (missing_argument)
+ arg_index = -1;
+ else
+ arg_index = parse_start + 1;
+
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, arg_index));
+ }
+ else
+ {
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, -1));
+ }
+ break;
+ case optional_argument:
+ if (optarg != NULL)
+ {
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, 0));
+ }
+ else
+ {
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, parse_start + 1));
+ }
+ break;
+ default:
+ // The options table is messed up. Here we'll just continue
+ option_element_vector.push_back (OptionArgElement (-1, parse_start, -1));
+ break;
+ }
+ }
+ else
+ {
+ option_element_vector.push_back (OptionArgElement (-1, parse_start, -1));
+ }
+ }
+}
diff --git a/lldb/source/Core/Baton.cpp b/lldb/source/Core/Baton.cpp
new file mode 100644
index 00000000000..103e2e0ef0c
--- /dev/null
+++ b/lldb/source/Core/Baton.cpp
@@ -0,0 +1,25 @@
+//===-- 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
+{
+ s->Printf("baton: %p", m_data);
+}
diff --git a/lldb/source/Core/Broadcaster.cpp b/lldb/source/Core/Broadcaster.cpp
new file mode 100644
index 00000000000..b311a8b3eed
--- /dev/null
+++ b/lldb/source/Core/Broadcaster.cpp
@@ -0,0 +1,219 @@
+//===-- 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 (const char *name) :
+ m_broadcaster_name (name),
+ m_broadcaster_listeners (),
+ m_broadcaster_listeners_mutex (Mutex::eMutexTypeRecursive)
+{
+ 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());
+
+ // Scope for "listeners_locker"
+ {
+ Mutex::Locker listeners_locker(m_broadcaster_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_broadcaster_listeners.end();
+ for (pos = m_broadcaster_listeners.begin(); pos != end; ++pos)
+ pos->first->BroadcasterWillDestruct (this);
+
+ m_broadcaster_listeners.clear();
+ }
+}
+
+const ConstString &
+Broadcaster::GetBroadcasterName ()
+{
+ return m_broadcaster_name;
+}
+
+void
+Broadcaster::AddInitialEventsToListener (Listener *listener, uint32_t requested_events)
+{
+
+}
+
+uint32_t
+Broadcaster::AddListener (Listener* listener, uint32_t event_mask)
+{
+ Mutex::Locker locker(m_broadcaster_listeners_mutex);
+ collection::iterator pos, end = m_broadcaster_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_broadcaster_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_broadcaster_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_broadcaster_listeners_mutex);
+ if (m_broadcaster_listeners.empty())
+ return false;
+
+ collection::iterator pos, end = m_broadcaster_listeners.end();
+ for (pos = m_broadcaster_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_broadcaster_listeners_mutex);
+ collection::iterator pos, end = m_broadcaster_listeners.end();
+ // See if we already have this listener, and if so, update its mask
+ for (pos = m_broadcaster_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_broadcaster_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();
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS);
+ if (log)
+ {
+ StreamString event_description;
+ event_sp->Dump (&event_description);
+ log->Printf ("%p Broadcaster(\"%s\")::BroadcastEvent (event_sp = {%s}, unique =%i)",
+ this,
+ m_broadcaster_name.AsCString(""),
+ event_description.GetData(),
+ unique);
+ }
+
+ Mutex::Locker event_types_locker(m_broadcaster_listeners_mutex);
+ collection::iterator pos, end = m_broadcaster_listeners.end();
+
+
+ // Iterate through all listener/mask pairs
+ for (pos = m_broadcaster_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);
+}
+
diff --git a/lldb/source/Core/Communication.cpp b/lldb/source/Core/Communication.cpp
new file mode 100644
index 00000000000..3ec3e0f41d9
--- /dev/null
+++ b/lldb/source/Core/Communication.cpp
@@ -0,0 +1,363 @@
+//===-- 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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+Communication::Communication(const char *name) :
+ Broadcaster (name),
+ m_connection_ap (),
+ m_read_thread (NULL),
+ m_read_thread_enabled (false),
+ m_bytes(),
+ m_bytes_mutex (Mutex::eMutexTypeRecursive),
+ m_callback (NULL),
+ m_callback_baton (NULL)
+
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::Communication (name = %s)",
+ this, name);
+}
+
+//----------------------------------------------------------------------
+// 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()
+{
+ StopReadThread (NULL);
+ Disconnect (NULL);
+}
+
+ConnectionStatus
+Communication::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
+
+ if (m_connection_ap.get())
+ return m_connection_ap->BytesAvailable (timeout_usec, error_ptr);
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid connection.");
+ return eConnectionStatusNoConnection;
+}
+
+ConnectionStatus
+Communication::Connect (const char *url, Error *error_ptr)
+{
+ Clear();
+
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::Connect (url = %s)", this, url);
+
+ if (m_connection_ap.get())
+ return m_connection_ap->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);
+
+ if (m_connection_ap.get())
+ {
+ ConnectionStatus status = m_connection_ap->Disconnect (error_ptr);
+ m_connection_ap.reset();
+ return status;
+ }
+ return eConnectionStatusNoConnection;
+}
+
+bool
+Communication::IsConnected () const
+{
+ if (m_connection_ap.get())
+ return m_connection_ap->IsConnected ();
+ return false;
+}
+
+bool
+Communication::HasConnection () const
+{
+ return m_connection_ap.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::Write (dst = %p, dst_len = %zu, timeout_usec = %u) connection = %p",
+ this, dst, dst_len, timeout_usec, m_connection_ap.get());
+
+ if (m_read_thread != NULL)
+ {
+ // 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_ap.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.
+ if (m_connection_ap.get())
+ {
+ status = m_connection_ap->BytesAvailable (timeout_usec, error_ptr);
+ if (status == eConnectionStatusSuccess)
+ return m_connection_ap->Read (dst, dst_len, 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_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::Write (src = %p, src_len = %zu) connection = %p",
+ this, src, src_len, m_connection_ap.get());
+
+ if (m_connection_ap.get())
+ return m_connection_ap->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 (m_read_thread != LLDB_INVALID_HOST_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);
+ return m_read_thread != LLDB_INVALID_HOST_THREAD;
+}
+
+bool
+Communication::StopReadThread (Error *error_ptr)
+{
+ if (m_read_thread == NULL)
+ 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);
+
+ return Host::ThreadJoin (m_read_thread, NULL, error_ptr);
+}
+
+
+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.data(), 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)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::AppendBytesToCache (src = %p, src_len = %zu, broadcast = %i)",
+ this, bytes, len, broadcast);
+ if (bytes == NULL || len == 0)
+ 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
+ {
+ 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, ConnectionStatus &status, Error *error_ptr)
+{
+ if (m_connection_ap.get())
+ return m_connection_ap->Read (dst, dst_len, status, error_ptr);
+ return 0;
+}
+
+
+bool
+Communication::ReadThreadIsRunning ()
+{
+ return m_read_thread != NULL;
+}
+
+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)
+ {
+ status = comm->BytesAvailable (UINT32_MAX, &error);
+
+ if (status == eConnectionStatusSuccess)
+ {
+ size_t bytes_read = comm->ReadFromConnection (buf, sizeof(buf), status, &error);
+ if (bytes_read > 0)
+ comm->AppendBytesToCache (buf, bytes_read, true);
+ }
+
+ switch (status)
+ {
+ case eConnectionStatusSuccess:
+ break;
+
+ case eConnectionStatusNoConnection: // No connection
+ case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
+ done = true;
+ // Fall through...
+ default:
+ case eConnectionStatusError: // Check GetError() for details
+ case eConnectionStatusTimedOut: // Request timed out
+ error.LogIfError(log, "%p Communication::BytesAvailable () => status = %i", p, status);
+ break;
+ }
+ }
+ if (log)
+ log->Printf ("%p Communication::ReadThread () thread exiting...", p);
+
+ // Let clients know that this thread is exiting
+ comm->m_read_thread = LLDB_INVALID_HOST_THREAD;
+ 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)
+{
+ StopReadThread(NULL);
+ Disconnect (NULL);
+ m_connection_ap.reset(connection);
+}
diff --git a/lldb/source/Core/Connection.cpp b/lldb/source/Core/Connection.cpp
new file mode 100644
index 00000000000..3c9bb8b1b7e
--- /dev/null
+++ b/lldb/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/lldb/source/Core/ConnectionFileDescriptor.cpp b/lldb/source/Core/ConnectionFileDescriptor.cpp
new file mode 100644
index 00000000000..b22f5ffa36d
--- /dev/null
+++ b/lldb/source/Core/ConnectionFileDescriptor.cpp
@@ -0,0 +1,563 @@
+//===-- ConnectionFileDescriptor.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/ConnectionFileDescriptor.h"
+
+// C Includes
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/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;
+
+ConnectionFileDescriptor::ConnectionFileDescriptor () :
+ Connection(),
+ m_fd (-1),
+ m_should_close_fd (false)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT,
+ "%p ConnectionFileDescriptor::ConnectionFileDescriptor ()",
+ this);
+}
+
+ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) :
+ Connection(),
+ m_fd (fd),
+ m_should_close_fd (owns_fd)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT,
+ "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)",
+ this, fd, owns_fd);
+}
+
+
+ConnectionFileDescriptor::~ConnectionFileDescriptor ()
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT,
+ "%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",
+ this);
+ Disconnect (NULL);
+}
+
+bool
+ConnectionFileDescriptor::IsConnected () const
+{
+ return m_fd >= 0;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
+ "%p ConnectionFileDescriptor::Connect (url = '%s')",
+ this, s);
+
+ 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, "connect://"))
+ {
+ return SocketConnect (s + strlen("connect://"), error_ptr);
+ }
+ else if (strstr(s, "file://"))
+ {
+ // file:///PATH
+ const char *path = s + strlen("file://");
+ m_fd = ::open (path, O_RDWR);
+ if (m_fd == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ int flags = ::fcntl (m_fd, F_GETFL, 0);
+ if (flags >= 0)
+ {
+ if ((flags & O_NONBLOCK) == 0)
+ {
+ flags |= O_NONBLOCK;
+ ::fcntl (m_fd, F_SETFL, flags);
+ }
+ }
+ m_should_close_fd = true;
+ return eConnectionStatusSuccess;
+ }
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Unsupported connection URL: '%s'.\n", s);
+ return eConnectionStatusError;
+ }
+ if (error_ptr)
+ error_ptr->SetErrorString("NULL connection URL.");
+ return eConnectionStatusError;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::Disconnect (Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
+ "%p ConnectionFileDescriptor::Disconnect ()",
+ this);
+ if (m_should_close_fd == false)
+ {
+ m_fd = -1;
+ return eConnectionStatusSuccess;
+ }
+ return Close (m_fd, error_ptr);
+}
+
+size_t
+ConnectionFileDescriptor::Read (void *dst, size_t dst_len, 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 = %zu)...",
+ this, m_fd, dst, dst_len);
+
+ Error error;
+ ssize_t bytes_read = ::read (m_fd, dst, dst_len);
+ if (bytes_read == 0)
+ {
+ error.SetErrorStringWithFormat("End-of-file.\n");
+ status = eConnectionStatusLostConnection;
+ }
+ else if (bytes_read < 0)
+ {
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ error.Clear();
+ }
+
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %zu) => %zi, error = %s",
+ this,
+ m_fd,
+ dst,
+ dst_len,
+ 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.
+ status = eConnectionStatusSuccess;
+ return 0;
+
+ case EBADF: // fildes is not a valid file or socket descriptor open for reading.
+ 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 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;
+ }
+
+// if (log)
+// error->Log(log, "::read ( %i, %p, %zu ) => %i", m_fd, dst, dst_len, bytesread);
+ Close (m_fd, NULL);
+ 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 = %zu)", this, src, src_len);
+
+ if (!IsConnected ())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Not connected.");
+ status = eConnectionStatusNoConnection;
+ return 0;
+ }
+
+
+ Error error;
+
+ ssize_t bytes_sent = 0;
+
+ if (m_is_socket)
+ bytes_sent = ::send (m_fd, src, src_len, 0);
+ else
+ bytes_sent = ::write (m_fd, src, src_len);
+
+ if (bytes_sent < 0)
+ error.SetErrorToErrno ();
+ else
+ error.Clear ();
+
+ if (log)
+ {
+ if (m_is_socket)
+ log->Printf ("%p ConnectionFileDescriptor::Write() ::send (socket = %i, src = %p, src_len = %zu, flags = 0) => %zi (error = %s)",
+ this, m_fd, src, src_len, bytes_sent, error.AsCString());
+ else
+ log->Printf ("%p ConnectionFileDescriptor::Write() ::write (fd = %i, src = %p, src_len = %zu) => %zi (error = %s)",
+ this, m_fd, src, src_len, bytes_sent, error.AsCString());
+ }
+
+ 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....
+ }
+
+ Close (m_fd, NULL);
+ return 0;
+ }
+
+ status = eConnectionStatusSuccess;
+ return bytes_sent;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ 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;
+ }
+
+ while (IsConnected())
+ {
+ fd_set read_fds;
+ FD_ZERO (&read_fds);
+ FD_SET (m_fd, &read_fds);
+ int nfds = m_fd + 1;
+
+ Error error;
+
+
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::Write() ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p)...",
+ this, nfds, m_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)
+ log->Printf("%p ConnectionFileDescriptor::Write() ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p) => %d, error = %s",
+ this, nfds, m_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.
+ 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)
+ {
+ return eConnectionStatusSuccess;
+ }
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorString("Not connected.");
+ return eConnectionStatusLostConnection;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::Close (int& fd, Error *error_ptr)
+{
+ if (error_ptr)
+ error_ptr->Clear();
+ bool success = true;
+ if (fd >= 0)
+ {
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
+ "%p ConnectionFileDescriptor::Close (fd = %i)",
+ this,
+ fd);
+
+ success = ::close (fd) == 0;
+ 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();
+ }
+ fd = -1;
+ }
+ m_is_socket = false;
+ if (success)
+ return eConnectionStatusSuccess;
+ else
+ return eConnectionStatusError;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
+ "%p ConnectionFileDescriptor::SocketListen (port = %i)",
+ this, listen_port_num);
+
+ Close (m_fd, false);
+ m_is_socket = true;
+ 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);
+
+ struct sockaddr_in sa;
+ ::memset (&sa, 0, sizeof sa);
+ sa.sin_len = sizeof sa;
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons (listen_port_num);
+ sa.sin_addr.s_addr = htonl (INADDR_ANY);
+
+ int err = ::bind (listen_port, (struct sockaddr *) &sa, sizeof(sa));
+ 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 = ::accept (listen_port, NULL, 0);
+ if (m_fd == -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, IPPROTO_TCP, TCP_NODELAY, 1);
+ if (error_ptr)
+ error_ptr->Clear();
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::SocketConnect (const char *host_and_port, Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
+ "%p ConnectionFileDescriptor::SocketConnect (host/port = %s)",
+ this, host_and_port);
+ Close (m_fd, false);
+ m_is_socket = true;
+
+ RegularExpression regex ("([^:]+):([0-9]+)");
+ if (regex.Execute (host_and_port, 2) == false)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Invalid host:port specification: '%s'.\n", host_and_port);
+ return eConnectionStatusError;
+ }
+ std::string host_str;
+ std::string port_str;
+ if (regex.GetMatchAtIndex (host_and_port, 1, host_str) == false ||
+ regex.GetMatchAtIndex (host_and_port, 2, port_str) == false)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Invalid host:port specification '%s'.\n", host_and_port);
+ return eConnectionStatusError;
+ }
+
+ int32_t port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN);
+ if (port == INT32_MIN)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Invalid port '%s'.\n", port_str.c_str());
+ return eConnectionStatusError;
+ }
+ // Create the socket
+ m_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (m_fd == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ m_should_close_fd = true;
+
+ // Enable local address reuse
+ SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ struct sockaddr_in sa;
+ ::bzero (&sa, sizeof (sa));
+ sa.sin_len = 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'.\n", host_str.c_str());
+ }
+ Close (m_fd, false);
+ return eConnectionStatusError;
+ }
+ }
+
+ if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa)))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Close (m_fd, false);
+ return eConnectionStatusError;
+ }
+
+ // Keep our TCP packets coming without any delays.
+ SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
+ if (error_ptr)
+ error_ptr->Clear();
+ return eConnectionStatusSuccess;
+}
+
+int
+ConnectionFileDescriptor::SetSocketOption(int fd, int level, int option_name, int option_value)
+{
+ return ::setsockopt(fd, level, option_name, &option_value, sizeof(option_value));
+}
+
+
diff --git a/lldb/source/Core/ConstString.cpp b/lldb/source/Core/ConstString.cpp
new file mode 100644
index 00000000000..c2d09c76461
--- /dev/null
+++ b/lldb/source/Core/ConstString.cpp
@@ -0,0 +1,480 @@
+//===-- 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;
+
+
+//----------------------------------------------------------------------
+// The global string pool is implemented as a hash_map that maps
+// std::string objects to a uint32_t reference count.
+//
+// In debug builds the value that is stored in the ConstString objects is
+// a C string that is owned by one of the std::string objects in the
+// hash map. This was done for visibility purposes when debugging as
+// gcc was often generating insufficient debug info for the
+// iterator objects.
+//
+// In release builds, the value that is stored in the ConstString objects
+// is the iterator into the ConstString::HashMap. This is much faster when
+// it comes to modifying the reference count, and removing strings from
+// the pool.
+//----------------------------------------------------------------------
+class Pool
+{
+public:
+ //------------------------------------------------------------------
+ // Default constructor
+ //
+ // Initialize the member variables and create the empty string.
+ //------------------------------------------------------------------
+ Pool () :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_string_map ()
+ {
+ }
+
+ //------------------------------------------------------------------
+ // Destructor
+ //------------------------------------------------------------------
+ ~Pool ()
+ {
+ }
+
+
+ static llvm::StringMapEntry<uint32_t> &
+ GetStringMapEntryFromKeyData (const char *keyData)
+ {
+ char *ptr = const_cast<char*>(keyData) - sizeof (llvm::StringMapEntry<uint32_t>);
+ return *reinterpret_cast<llvm::StringMapEntry<uint32_t>*>(ptr);
+ }
+
+ size_t
+ GetConstCStringLength (const char *ccstr)
+ {
+ if (ccstr)
+ {
+ llvm::StringMapEntry<uint32_t>&entry = GetStringMapEntryFromKeyData (ccstr);
+ return entry.getKey().size();
+ }
+ return 0;
+ }
+
+ const char *
+ GetConstCString (const char *cstr)
+ {
+ if (cstr)
+ {
+ Mutex::Locker locker (m_mutex);
+ llvm::StringRef string_ref (cstr);
+ llvm::StringMapEntry<uint32_t>& entry = m_string_map.GetOrCreateValue (string_ref);
+ const char *ccstr = entry.getKeyData();
+ llvm::StringMapEntry<uint32_t>&reconstituted_entry = GetStringMapEntryFromKeyData (ccstr);
+ assert (&entry == &reconstituted_entry);
+ return ccstr;
+ }
+ return NULL;
+ }
+
+ const char *
+ GetConstCStringWithLength (const char *cstr, int cstr_len)
+ {
+ if (cstr)
+ {
+ Mutex::Locker locker (m_mutex);
+ llvm::StringRef string_ref (cstr, cstr_len);
+ llvm::StringMapEntry<uint32_t>& entry = m_string_map.GetOrCreateValue (string_ref);
+ const char *ccstr = entry.getKeyData();
+ llvm::StringMapEntry<uint32_t>&reconstituted_entry = GetStringMapEntryFromKeyData (ccstr);
+ assert (&entry == &reconstituted_entry);
+ return ccstr;
+ }
+ return NULL;
+ }
+
+ const char *
+ GetConstTrimmedCStringWithLength (const char *cstr, int cstr_len)
+ {
+ if (cstr)
+ {
+ Mutex::Locker locker (m_mutex);
+ int actual_cstr_len = strlen (cstr);
+ llvm::StringRef string_ref (cstr, std::min<int>(actual_cstr_len, cstr_len));
+ llvm::StringMapEntry<uint32_t>& entry = m_string_map.GetOrCreateValue (string_ref);
+ const char *ccstr = entry.getKeyData();
+ llvm::StringMapEntry<uint32_t>&reconstituted_entry = GetStringMapEntryFromKeyData (ccstr);
+ assert (&entry == &reconstituted_entry);
+ return ccstr;
+ }
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ // Return the size in bytes that this object and any items in its
+ // collection of uniqued strings + reference 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(llvm::StringMapEntry<uint32_t>) + pos->getKey().size();
+ }
+ return mem_size;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Typedefs
+ //------------------------------------------------------------------
+ typedef llvm::StringMap<uint32_t, llvm::BumpPtrAllocator> StringPool;
+ 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.
+//----------------------------------------------------------------------
+static Pool &
+StringPool()
+{
+ static Pool string_pool;
+ return string_pool;
+}
+
+//----------------------------------------------------------------------
+// Default constructor
+//
+// Initializes the string to an empty string.
+//----------------------------------------------------------------------
+ConstString::ConstString () :
+ m_string (NULL)
+{
+}
+
+//----------------------------------------------------------------------
+// Copy constructor
+//
+// Copies the string value in "rhs" and retains an extra reference
+// to the string value in the string pool.
+//----------------------------------------------------------------------
+ConstString::ConstString (const ConstString& rhs) :
+ m_string (rhs.m_string)
+{
+}
+
+//----------------------------------------------------------------------
+// Construct with C String value
+//
+// Constructs this object with a C string by looking to see if the
+// C string already exists in the global string pool. If it does
+// exist, it retains an extra reference to the string in the string
+// pool. If it doesn't exist, it is added to the string pool with
+// a reference count of 1.
+//----------------------------------------------------------------------
+ConstString::ConstString (const char *cstr) :
+ m_string (StringPool().GetConstCString (cstr))
+{
+}
+
+//----------------------------------------------------------------------
+// Construct with C String value with max length
+//
+// Constructs this object with a C string with a length. If
+// the length of the string is greather than "cstr_len", the
+// string length will be truncated. This allows substrings to be
+// created without the need to NULL terminate the string as it
+// is passed into this function.
+//
+// If the C string already exists in the global string pool, it
+// retains an extra reference to the string in the string
+// pool. If it doesn't exist, it is added to the string pool with
+// a reference count of 1.
+//----------------------------------------------------------------------
+ConstString::ConstString (const char *cstr, size_t cstr_len) :
+ m_string (StringPool().GetConstCStringWithLength (cstr, cstr_len))
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//
+// Decrements the reference count on the contained string, and if
+// the resulting reference count is zero, then the string is removed
+// from the string pool. If the reference count is still greater
+// than zero, the string will remain in the string pool
+//----------------------------------------------------------------------
+ConstString::~ConstString ()
+{
+}
+
+//----------------------------------------------------------------------
+// Convert to pointer operator. This allows code to check any
+// ConstString objects to see if they contain anything (not empty)
+// valid using code such as:
+//
+// ConstString str(...);
+// if (str)
+// { ...
+//----------------------------------------------------------------------
+ConstString::operator void*() const
+{
+ return IsEmpty() ? NULL : const_cast<ConstString*>(this);
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//
+// Assigns the string in this object with the value from "rhs"
+// and increments the reference count of that string.
+//
+// The previously contained string will be get its reference count
+// decremented and removed from the string pool if its reference
+// count reaches zero.
+//----------------------------------------------------------------------
+const ConstString&
+ConstString::operator=(const ConstString& rhs)
+{
+ m_string = rhs.m_string;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Equal to operator
+//
+// Returns true if this string is equal to that in "rhs". This is
+// very fast as it results in a pointer comparison since all strings
+// are in a uniqued and reference counted string pool.
+//------------------------------------------------------------------
+bool
+ConstString::operator == (const ConstString& rhs) const
+{
+ // We can do a pointer compare to compare these strings since they
+ // must come from the same pool in order to be equal.
+ return m_string == rhs.m_string;
+}
+
+bool
+ConstString::operator != (const ConstString& rhs) const
+{
+ return m_string != rhs.m_string;
+}
+
+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 the string value "str" to the stream "s"
+//----------------------------------------------------------------------
+Stream&
+lldb_private::operator << (Stream& s, const ConstString& str)
+{
+ const char *cstr = str.GetCString();
+ if (cstr)
+ s << cstr;
+
+ return s;
+}
+
+//----------------------------------------------------------------------
+// Get the value of the contained string as a NULL terminated C
+// string value. Return "fail_value" if the string is empty.
+//----------------------------------------------------------------------
+const char *
+ConstString::AsCString(const char *fail_value) const
+{
+ if (m_string == NULL)
+ return fail_value;
+ return m_string;
+}
+
+const char *
+ConstString::GetCString () const
+{
+ return m_string;
+}
+
+size_t
+ConstString::GetLength () const
+{
+ return StringPool().GetConstCStringLength (m_string);
+}
+
+
+//----------------------------------------------------------------------
+// Clear any contained string and reset the value to the an empty
+// string value.
+//
+// The previously contained string will be get its reference count
+// decremented and removed from the string pool if its reference
+// count reaches zero.
+//----------------------------------------------------------------------
+void
+ConstString::Clear ()
+{
+ m_string = NULL;
+}
+
+//----------------------------------------------------------------------
+// Compare two string objects.
+//
+// Returns:
+// -1 if a < b
+// 0 if a == b
+// 1 if a > b
+//----------------------------------------------------------------------
+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
+}
+
+//----------------------------------------------------------------------
+// Dump the string value to the stream "s". If the contained string
+// is empty, print "fail_value" to the stream instead. If
+// "fail_value" is NULL, then nothing will be dumped to the
+// stream.
+//----------------------------------------------------------------------
+void
+ConstString::Dump(Stream *s, const char *fail_value) const
+{
+ const char *cstr = AsCString (fail_value);
+ if (cstr)
+ s->PutCString (cstr);
+}
+
+//----------------------------------------------------------------------
+// Dump extra debug information to the stream "s".
+//----------------------------------------------------------------------
+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 = %zu", (int)sizeof(void*) * 2, this, parens, cstr, parens, cstr_len);
+}
+
+//----------------------------------------------------------------------
+// Returns true if the contained string is empty.
+//----------------------------------------------------------------------
+bool
+ConstString::IsEmpty() const
+{
+ return m_string == NULL || m_string[0] == '\0';
+}
+
+//----------------------------------------------------------------------
+// Set the string value in the object by uniquing the "cstr" string
+// value in our global string pool.
+//
+// If the C string already exists in the global string pool, it
+// retains an extra reference to the string in the string
+// pool. If it doesn't exist, it is added to the string pool with
+// a reference count of 1.
+//----------------------------------------------------------------------
+void
+ConstString::SetCString (const char *cstr)
+{
+ m_string = StringPool().GetConstCString (cstr);
+}
+
+//----------------------------------------------------------------------
+// Set the string value in the object by uniquing "cstr_len" bytes
+// starting at the "cstr" string value in our global string pool.
+// If trim is true, then "cstr_len" indicates a maximum length of
+// the CString and if the actual length of the string is less, then
+// it will be trimmed. If trim is false, then this allows strings
+// with NULL characters ('\0') to be added to the string pool.
+//
+// If the C string already exists in the global string pool, it
+// retains an extra reference to the string in the string
+// pool. If it doesn't exist, it is added to the string pool with
+// a reference count of 1.
+//----------------------------------------------------------------------
+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);
+}
+
+//----------------------------------------------------------------------
+// Return the size in bytes that this object takes in memory. The
+// resulting size will not include any of the C string values from
+// the global string pool (see StaticMemorySize ()).
+//----------------------------------------------------------------------
+size_t
+ConstString::MemorySize() const
+{
+ return sizeof(ConstString);
+}
+
+//----------------------------------------------------------------------
+// Reports the the size in bytes of all shared C string values,
+// containers and reference count values as a byte size for the
+// entire string pool.
+//----------------------------------------------------------------------
+size_t
+ConstString::StaticMemorySize()
+{
+ // Get the size of the static string pool
+ return StringPool().MemorySize();
+}
diff --git a/lldb/source/Core/DataBufferHeap.cpp b/lldb/source/Core/DataBufferHeap.cpp
new file mode 100644
index 00000000000..a93427ff858
--- /dev/null
+++ b/lldb/source/Core/DataBufferHeap.cpp
@@ -0,0 +1,105 @@
+//===-- 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 (size_t n, uint8_t ch) :
+ m_data(n, ch)
+{
+}
+
+//----------------------------------------------------------------------
+// Initialize this class with a copy of the "n" bytes from the "bytes"
+// buffer.
+//----------------------------------------------------------------------
+DataBufferHeap::DataBufferHeap (const void *src, size_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.
+//----------------------------------------------------------------------
+size_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.
+//----------------------------------------------------------------------
+size_t
+DataBufferHeap::SetByteSize (size_t new_size)
+{
+ m_data.resize(new_size);
+ return m_data.size();
+}
+
+void
+DataBufferHeap::CopyData (const void *src, size_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();
+}
+
+
+
diff --git a/lldb/source/Core/DataBufferMemoryMap.cpp b/lldb/source/Core/DataBufferMemoryMap.cpp
new file mode 100644
index 00000000000..c8ad5492f51
--- /dev/null
+++ b/lldb/source/Core/DataBufferMemoryMap.cpp
@@ -0,0 +1,214 @@
+//===-- 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 <sys/stat.h>
+#include <sys/mman.h>
+
+#include "lldb/Core/DataBufferMemoryMap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Host/Host.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default Constructor
+//----------------------------------------------------------------------
+DataBufferMemoryMap::DataBufferMemoryMap() :
+ m_mmap_addr(NULL),
+ m_mmap_size(0),
+ m_data(NULL),
+ m_size(0),
+ m_error()
+{
+}
+
+//----------------------------------------------------------------------
+// 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.
+//----------------------------------------------------------------------
+size_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)
+ {
+ ::munmap((void *)m_mmap_addr, m_mmap_size);
+ m_mmap_addr = NULL;
+ m_mmap_size = 0;
+ m_data = NULL;
+ m_size = 0;
+ }
+ m_error.Clear();
+}
+
+
+const Error &
+DataBufferMemoryMap::GetError() const
+{
+ return m_error;
+}
+
+//----------------------------------------------------------------------
+// Memory map "length" bytes from "file" starting "offset"
+// bytes into the file. If "length" is set to SIZE_T_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* file, off_t offset, size_t length)
+{
+ if (file != NULL)
+ {
+ char path[PATH_MAX];
+ if (file->GetPath(path, sizeof(path)))
+ {
+ int fd = ::open(path, O_RDONLY, 0);
+ if (fd >= 0)
+ {
+ MemoryMapFromFileDescriptor (fd, offset, length);
+ ::close(fd);
+ return GetByteSize();
+ }
+ else
+ {
+ m_error.SetErrorToErrno();
+ return 0;
+ }
+ }
+ }
+ // 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_T_MAX, then map as many bytes
+// as possible.
+//
+// RETURNS
+// Number of bytes mapped starting from the requested offset.
+//----------------------------------------------------------------------
+size_t
+DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, off_t offset, size_t length)
+{
+ Clear();
+ if (fd >= 0)
+ {
+ struct stat stat;
+ if (::fstat(fd, &stat) == 0)
+ {
+ if ((stat.st_mode & S_IFREG) && (stat.st_size > offset))
+ {
+ if (length == SIZE_T_MAX)
+ length = stat.st_size - offset;
+
+ // Cap the length if too much data was requested
+ if (length > stat.st_size - offset)
+ length = stat.st_size - offset;
+
+ if (length > 0)
+ {
+ m_mmap_addr = (uint8_t *)::mmap(NULL, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, offset);
+
+ if (m_mmap_addr == (void*)-1)
+ {
+ m_error.SetErrorToErrno ();
+ if (m_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_READ, MAP_FILE | MAP_SHARED, 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
+ m_error.Clear ();
+
+ // 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;
+ }
+ }
+ }
+ }
+ 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;
+ }
+ }
+ }
+ }
+
+ ::close (fd);
+ }
+ return GetByteSize ();
+}
diff --git a/lldb/source/Core/DataExtractor.cpp b/lldb/source/Core/DataExtractor.cpp
new file mode 100644
index 00000000000..236ec187f5f
--- /dev/null
+++ b/lldb/source/Core/DataExtractor.cpp
@@ -0,0 +1,1517 @@
+//===-- 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 <libkern/OSByteOrder.h>
+#include <stddef.h>
+
+#include <bitset>
+#include <string>
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/DataBuffer.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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define NON_PRINTABLE_CHAR '.'
+//----------------------------------------------------------------------
+// Default constructor.
+//----------------------------------------------------------------------
+DataExtractor::DataExtractor () :
+ m_start (NULL),
+ m_end (NULL),
+ m_byte_order(eByteOrderHost),
+ 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, 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 DataExtractor objects exist that have a reference to
+// this data.
+//----------------------------------------------------------------------
+DataExtractor::DataExtractor (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);
+}
+
+//----------------------------------------------------------------------
+// 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, uint32_t offset, uint32_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))
+ {
+ uint32_t bytes_available = data.GetByteSize() - offset;
+ if (length > bytes_available)
+ length = bytes_available;
+ SetData(data, offset, length);
+ }
+}
+
+//----------------------------------------------------------------------
+// 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 = eByteOrderHost;
+ m_addr_size = 4;
+ m_data_sp.reset();
+}
+
+//------------------------------------------------------------------
+// Returns the total number of bytes that this object refers to
+//------------------------------------------------------------------
+size_t
+DataExtractor::GetByteSize () const
+{
+ return m_end - m_start;
+}
+
+//------------------------------------------------------------------
+// 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;
+}
+
+//------------------------------------------------------------------
+// Returns true if OFFSET is a valid offset into the data in this
+// object.
+//------------------------------------------------------------------
+bool
+DataExtractor::ValidOffset (uint32_t offset) const
+{
+ return offset < GetByteSize();
+}
+
+//------------------------------------------------------------------
+// Returns true if there are LENGTH bytes availabe starting OFFSET
+// into the data that is in this object.
+//------------------------------------------------------------------
+bool
+DataExtractor::ValidOffsetForDataOfSize (uint32_t offset, uint32_t length) const
+{
+ size_t size = GetByteSize();
+ if (offset >= size)
+ return false; // offset isn't valid
+
+ if (length == 0)
+ return true; // No bytes requested at this offset, return true
+
+ // If we flip the bits in offset we can figure out how
+ // many bytes we have left before "offset + length"
+ // could overflow when doing unsigned arithmetic.
+ if (length > ~offset)
+ return false; // unsigned overflow
+
+ // Make sure "offset + length" is a valid offset as well.
+ // length must be greater than zero for this to be a
+ // valid expression, and we have already checked for this.
+ return ((offset + length) <= size);
+}
+
+//------------------------------------------------------------------
+// Returns a pointer to the first byte contained in this object's
+// data, or NULL of there is no data in this object.
+//------------------------------------------------------------------
+const uint8_t *
+DataExtractor::GetDataStart () const
+{
+ return m_start;
+}
+//------------------------------------------------------------------
+// Returns a pointer to the byte past the last byte contained in
+// this object's data, or NULL of there is no data in this object.
+//------------------------------------------------------------------
+const uint8_t *
+DataExtractor::GetDataEnd () const
+{
+ return m_end;
+}
+
+//------------------------------------------------------------------
+// Returns true if this object will endian swap values as it
+// extracts data.
+//------------------------------------------------------------------
+ByteOrder
+DataExtractor::GetByteOrder () const
+{
+ return m_byte_order;
+}
+//------------------------------------------------------------------
+// Set wether this object will endian swap values as it extracts
+// data.
+//------------------------------------------------------------------
+void
+DataExtractor::SetByteOrder (ByteOrder endian)
+{
+ m_byte_order = endian;
+}
+
+
+//------------------------------------------------------------------
+// Return the size in bytes of any address values this object will
+// extract
+//------------------------------------------------------------------
+uint8_t
+DataExtractor::GetAddressByteSize () const
+{
+ return m_addr_size;
+}
+
+//------------------------------------------------------------------
+// Set the size in bytes that will be used when extracting any
+// address values from data contained in this object.
+//------------------------------------------------------------------
+void
+DataExtractor::SetAddressByteSize (uint8_t addr_size)
+{
+ m_addr_size = addr_size;
+}
+
+//----------------------------------------------------------------------
+// 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
+DataExtractor::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 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".
+//----------------------------------------------------------------------
+uint32_t
+DataExtractor::SetData (const DataExtractor& data, uint32_t data_offset, uint32_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.
+//----------------------------------------------------------------------
+uint32_t
+DataExtractor::SetData (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.
+//----------------------------------------------------------------------
+uint8_t
+DataExtractor::GetU8 (uint32_t *offset_ptr) const
+{
+ uint8_t val = 0;
+ if ( m_start < m_end )
+ {
+ val = m_start[*offset_ptr];
+ *offset_ptr += sizeof(val);
+ }
+ return val;
+}
+
+//----------------------------------------------------------------------
+// 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 (uint32_t *offset_ptr, void *dst, uint32_t count) const
+{
+ register uint32_t offset = *offset_ptr;
+
+ if ((count > 0) && ValidOffsetForDataOfSize(offset, count) )
+ {
+ // Copy the data into the buffer
+ memcpy (dst, m_start + offset, count);
+ // Advance the offset
+ *offset_ptr += 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 (uint32_t *offset_ptr) const
+{
+ uint16_t val = 0;
+ register uint32_t offset = *offset_ptr;
+ if ( ValidOffsetForDataOfSize(offset, sizeof(val)) )
+ {
+ if (m_byte_order != eByteOrderHost)
+ val = OSReadSwapInt16(m_start, offset);
+ else
+ val = _OSReadInt16 (m_start, offset);
+
+ // Advance the offset
+ *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 (uint32_t *offset_ptr, void *void_dst, uint32_t count) const
+{
+ uint16_t *dst = (uint16_t *)void_dst;
+ const size_t value_size = sizeof(*dst);
+ register uint32_t offset = *offset_ptr;
+
+ if ((count > 0) && ValidOffsetForDataOfSize(offset, value_size * count) )
+ {
+ uint16_t *value_ptr;
+ uint16_t *end = dst + count;
+ if (m_byte_order != eByteOrderHost)
+ {
+ for (value_ptr = dst; value_ptr < end; ++value_ptr, offset += value_size)
+ *value_ptr = OSReadSwapInt16 (m_start, offset);
+ }
+ else
+ {
+ for (value_ptr = dst; value_ptr < end; ++value_ptr, offset += value_size)
+ *value_ptr = _OSReadInt16 (m_start, offset);
+ }
+
+ // Advance the offset
+ *offset_ptr = offset;
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return 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 (uint32_t *offset_ptr) const
+{
+ uint32_t val = 0;
+ register uint32_t offset = *offset_ptr;
+
+ if ( ValidOffsetForDataOfSize(offset, sizeof(val)) )
+ {
+ if (m_byte_order != eByteOrderHost)
+ val = OSReadSwapInt32 (m_start, offset);
+ else
+ val = _OSReadInt32 (m_start, offset);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
+ }
+ 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 (uint32_t *offset_ptr, void *void_dst, uint32_t count) const
+{
+ uint32_t *dst = (uint32_t *)void_dst;
+ const size_t value_size = sizeof(*dst);
+ register uint32_t offset = *offset_ptr;
+
+ if ((count > 0) && ValidOffsetForDataOfSize(offset, value_size * count))
+ {
+ uint32_t *value_ptr;
+ uint32_t *end = dst + count;
+ if (m_byte_order != eByteOrderHost)
+ {
+ for (value_ptr = dst; value_ptr < end; ++value_ptr, offset += value_size)
+ *value_ptr = OSReadSwapInt32 (m_start, offset);
+
+ }
+ else
+ {
+ for (value_ptr = dst; value_ptr < end; ++value_ptr, offset += value_size)
+ *value_ptr = _OSReadInt32 (m_start, offset);
+ }
+
+ // Advance the offset
+ *offset_ptr = offset;
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return 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 (uint32_t *offset_ptr) const
+{
+ uint64_t val = 0;
+ register uint32_t offset = *offset_ptr;
+ if ( ValidOffsetForDataOfSize(offset, sizeof(val)) )
+ {
+ if (m_byte_order != eByteOrderHost)
+ val = OSReadSwapInt64 (m_start, offset);
+ else
+ val = _OSReadInt64 (m_start, offset);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
+ }
+ 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 (uint32_t *offset_ptr, void *void_dst, uint32_t count) const
+{
+ uint64_t *dst = (uint64_t *)void_dst;
+ const size_t value_size = sizeof(uint64_t);
+ register uint32_t offset = *offset_ptr;
+
+ if ((count > 0) && ValidOffsetForDataOfSize(offset, value_size * count))
+ {
+ uint64_t *value_ptr;
+ uint64_t *end = dst + count;
+ if (m_byte_order != eByteOrderHost)
+ {
+ for (value_ptr = dst; value_ptr < end; ++value_ptr, offset += value_size)
+ *value_ptr = OSReadSwapInt64 (m_start, offset);
+
+ }
+ else
+ {
+ for (value_ptr = dst; value_ptr < end; ++value_ptr, offset += value_size)
+ *value_ptr = _OSReadInt64 (m_start, offset);
+ }
+
+ // Advance the offset
+ *offset_ptr = offset;
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return 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 (uint32_t *offset_ptr, uint32_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!");
+ 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 (uint32_t *offset_ptr, uint32_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!");
+ break;
+ }
+ return 0;
+}
+
+int64_t
+DataExtractor::GetMaxS64 (uint32_t *offset_ptr, uint32_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!");
+ break;
+ }
+ return 0;
+}
+
+uint64_t
+DataExtractor::GetMaxU64Bitfield (uint32_t *offset_ptr, uint32_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 = ((1 << bitfield_bit_size) - 1);
+ uval64 &= bitfield_mask;
+ }
+ return uval64;
+}
+
+int64_t
+DataExtractor::GetMaxS64Bitfield (uint32_t *offset_ptr, uint32_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 = ((1 << bitfield_bit_size) - 1);
+ sval64 &= bitfield_mask;
+ // sign extend if needed
+ if (sval64 & (1 << (bitfield_bit_size - 1)))
+ sval64 |= ~bitfield_mask;
+ }
+ return sval64;
+}
+
+
+float
+DataExtractor::GetFloat (uint32_t *offset_ptr) const
+{
+ uint32_t val = 0;
+ register uint32_t offset = *offset_ptr;
+
+ if ( ValidOffsetForDataOfSize(offset, sizeof(val)) )
+ {
+ if (m_byte_order != eByteOrderHost)
+ val = OSReadSwapInt32 (m_start, offset);
+ else
+ val = _OSReadInt32 (m_start, offset);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
+ }
+ return *((float *)&val);
+}
+
+double
+DataExtractor::GetDouble (uint32_t *offset_ptr) const
+{
+ uint64_t val = 0;
+ register uint32_t offset = *offset_ptr;
+ if ( ValidOffsetForDataOfSize(offset, sizeof(val)) )
+ {
+ if (m_byte_order != eByteOrderHost)
+ val = OSReadSwapInt64 (m_start, offset);
+ else
+ val = _OSReadInt64 (m_start, offset);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
+ }
+ return *((double *)&val);
+
+}
+
+
+long double
+DataExtractor::GetLongDouble (uint32_t *offset_ptr) const
+{
+ if (sizeof(long double) == sizeof(uint64_t))
+ {
+ uint64_t val = 0;
+ register uint32_t offset = *offset_ptr;
+ if ( ValidOffsetForDataOfSize(offset, sizeof(val)) )
+ {
+ if (m_byte_order != eByteOrderHost)
+ val = OSReadSwapInt64 (m_start, offset);
+ else
+ val = _OSReadInt64 (m_start, offset);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
+ }
+ return *((long double *)&val);
+ }
+ return 0.0;
+}
+
+
+//------------------------------------------------------------------
+// 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 (uint32_t *offset_ptr) const
+{
+ return GetMaxU64 (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 (uint32_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 (uint32_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_GNU_EH_PE_omit)
+ return ULONG_LONG_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_GNU_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_GNU_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_GNU_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_GNU_EH_PE_funcrel:
+ signExtendValue = true;
+ break;
+
+ case DW_GNU_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_GNU_EH_PE_MASK_ENCODING)
+ {
+ case DW_GNU_EH_PE_absptr :
+ {
+ addressValue = GetAddress (offset_ptr);
+// if (data_relocs)
+// addressValue = data_relocs->Relocate(*offset_ptr - addr_size, *this, addressValue);
+ }
+ break;
+ case DW_GNU_EH_PE_uleb128 : addressValue = GetULEB128(offset_ptr); break;
+ case DW_GNU_EH_PE_udata2 : addressValue = GetU16(offset_ptr); break;
+ case DW_GNU_EH_PE_udata4 : addressValue = GetU32(offset_ptr); break;
+ case DW_GNU_EH_PE_udata8 : addressValue = GetU64(offset_ptr); break;
+ case DW_GNU_EH_PE_sleb128 : addressValue = GetSLEB128(offset_ptr); break;
+ case DW_GNU_EH_PE_sdata2 : addressValue = (int16_t)GetU16(offset_ptr); break;
+ case DW_GNU_EH_PE_sdata4 : addressValue = (int32_t)GetU32(offset_ptr); break;
+ case DW_GNU_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 (uint32_t offset, uint32_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;
+}
+//----------------------------------------------------------------------
+// Peeks at bytes in the contained data.
+//
+// Returns a valid pointer to bytes if "offset" is a valid offset in
+// and there are "length" bytes available, else NULL is returned.
+//----------------------------------------------------------------------
+const uint8_t*
+DataExtractor::PeekData (uint32_t offset, uint32_t length) const
+{
+ if ( length > 0 && ValidOffsetForDataOfSize(offset, length) )
+ return m_start + offset;
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Returns a pointer to a bytes in this object's data at the offset
+// pointed to by "offset_ptr". If "length" is zero or too large,
+// then the offset pointed to by "offset_ptr" will not be updated
+// and NULL will be returned.
+//
+// Returns a pointer to the data if the offset and length are valid,
+// or NULL otherwise.
+//----------------------------------------------------------------------
+const void*
+DataExtractor::GetData (uint32_t *offset_ptr, uint32_t length) const
+{
+ const uint8_t* bytes = NULL;
+ register uint32_t offset = *offset_ptr;
+ if ( length > 0 && ValidOffsetForDataOfSize(offset, length) )
+ {
+ bytes = m_start + offset;
+ *offset_ptr = offset + length;
+ }
+ return bytes;
+}
+
+//----------------------------------------------------------------------
+// Extracts a AsCString (fixed length, or variable length) from
+// the data at the offset pointed to by "offset_ptr". If
+// "length" is zero, then a variable length NULL terminated C
+// string will be extracted from the data the "offset_ptr" will be
+// updated with the offset of the byte that follows the NULL
+// terminator byte. If "length" is greater than zero, then
+// the function will make sure there are "length" bytes
+// available in the current data and if so, return a valid pointer.
+//
+// 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 (uint32_t *offset_ptr) const
+{
+ const char *s = NULL;
+ if ( m_start < m_end )
+ {
+ s = (char*)m_start + *offset_ptr;
+
+ size_t length = strlen(s) + 1;
+
+ if (!ValidOffsetForDataOfSize(*offset_ptr, length))
+ return NULL;
+
+ // Advance the offset
+ *offset_ptr += length;
+ }
+ return s;
+}
+
+//------------------------------------------------------------------
+// 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 (uint32_t offset) const
+{
+ if (ValidOffset (offset))
+ return (const char*)m_start + offset;
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// 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 (uint32_t *offset_ptr) const
+{
+ uint64_t result = 0;
+ if ( m_start < m_end )
+ {
+ int shift = 0;
+ const uint8_t *src = m_start + *offset_ptr;
+ uint8_t byte;
+ int bytecount = 0;
+
+ while (src < m_end)
+ {
+ bytecount++;
+ byte = *src++;
+ result |= (byte & 0x7f) << shift;
+ shift += 7;
+ if ((byte & 0x80) == 0)
+ break;
+ }
+
+ *offset_ptr += bytecount;
+ }
+ return result;
+}
+
+//----------------------------------------------------------------------
+// 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 (uint32_t *offset_ptr) const
+{
+ int64_t result = 0;
+
+ if ( m_start < m_end )
+ {
+ int shift = 0;
+ int size = sizeof (uint32_t) * 8;
+ const uint8_t *src = m_start + *offset_ptr;
+
+ uint8_t byte;
+ int bytecount = 0;
+
+ while (src < m_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;
+}
+
+//----------------------------------------------------------------------
+// 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 (uint32_t *offset_ptr) const
+{
+ uint32_t bytes_consumed = 0;
+ if ( m_start < m_end )
+ {
+ const uint8_t *start = m_start + *offset_ptr;
+ const uint8_t *src = start;
+
+ while ((src < m_end) && (*src++ & 0x80))
+ ++bytes_consumed;
+
+ *offset_ptr += src - start;
+ }
+ return bytes_consumed;
+}
+
+uint32_t
+DataExtractor::Dump
+(
+ Stream *s,
+ uint32_t start_offset,
+ lldb::Format item_format,
+ uint32_t item_byte_size,
+ uint32_t item_count,
+ uint32_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
+) const
+{
+ if (s == NULL)
+ return start_offset;
+
+ uint32_t offset;
+ uint32_t count;
+ uint32_t line_start_offset;
+
+ if (item_format == eFormatPointer)
+ {
+ if (item_byte_size != 4 && item_byte_size != 8)
+ item_byte_size = s->GetAddressByteSize();
+ }
+
+ for (offset = start_offset, line_start_offset = start_offset, 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", (num_per_line - (offset - line_start_offset)) * 3 + 2, "");
+ Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0);
+ }
+ s->EOL();
+ }
+ if (base_addr != LLDB_INVALID_ADDRESS)
+ s->Printf ("0x%8.8llx: ", (uint64_t)(base_addr + (offset - start_offset)));
+ line_start_offset = offset;
+ }
+ else
+ if (item_format != eFormatChar &&
+ item_format != eFormatCharPrintable &&
+ count > 0)
+ {
+ s->PutChar(' ');
+ }
+
+ uint32_t i;
+ switch (item_format)
+ {
+ case eFormatBoolean:
+ s->Printf ("%s", GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset) ? "true" : "false");
+ break;
+
+ case eFormatBinary:
+ {
+ uint64_t uval64 = GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset);
+ std::string binary_value(std::bitset<64>(uval64).to_string());
+ 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);
+ }
+ 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:
+ {
+ // If we are only printing one character surround it with single
+ // quotes
+ if (item_count == 1 && item_format == eFormatChar)
+ s->PutChar('\'');
+
+ uint8_t ch = GetU8(&offset);
+ if (isprint(ch))
+ s->Printf ("%c", ch);
+ else if (item_format == eFormatChar)
+ {
+ switch (ch)
+ {
+ case '\e': s->Printf ("\\e", (uint8_t)ch); break;
+ case '\a': s->Printf ("\\a", ch); break;
+ case '\b': s->Printf ("\\b", ch); break;
+ case '\f': s->Printf ("\\f", ch); break;
+ case '\n': s->Printf ("\\n", ch); break;
+ case '\r': s->Printf ("\\r", ch); break;
+ case '\t': s->Printf ("\\t", ch); break;
+ case '\v': s->Printf ("\\v", ch); break;
+ case '\0': s->Printf ("\\0", ch); break;
+ default: s->Printf ("\\x%2.2x", 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 eFormatComplex:
+ if (sizeof(float) * 2 == item_byte_size)
+ {
+ uint32_t a32 = GetU32(&offset);
+ uint32_t b32 = GetU32(&offset);
+
+ s->Printf ("%g + %gi", a32, b32);
+ }
+ else if (sizeof(double) * 2 == item_byte_size)
+ {
+ uint64_t a64 = GetU64(&offset);
+ uint64_t b64 = GetU64(&offset);
+
+ s->Printf ("%lg + %lgi", a64, b64);
+ }
+ else if (sizeof(long double) * 2 == item_byte_size && sizeof(long double) <= sizeof(uint64_t))
+ {
+ uint64_t a64 = GetU64(&offset);
+ uint64_t b64 = GetU64(&offset);
+ s->Printf ("%Lg + %Lgi", a64, b64);
+ }
+ break;
+
+ case eFormatDecimal:
+ if (item_byte_size <= 8);
+ s->Printf ("%lld", GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ break;
+
+ case eFormatUnsigned:
+ if (item_byte_size <= 8);
+ s->Printf ("%llu", GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ break;
+
+ case eFormatOctal:
+ if (item_byte_size <= 8);
+ s->Printf ("0%llo", GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ break;
+
+ case eFormatEnum:
+ // Print enum value as a signed integer when we don't get the enum type
+ s->Printf ("%lld", GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ break;
+
+ case eFormatCString:
+ {
+ const char *cstr = GetCStr(&offset);
+ if (cstr)
+ s->Printf("\"%s\"", cstr);
+ else
+ {
+ s->Printf("NULL", cstr);
+ offset = UINT32_MAX;
+ }
+ }
+ break;
+
+
+ case eFormatPointer:
+ s->Address(GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset), sizeof (addr_t));
+ break;
+
+ case eFormatHex:
+ if (item_byte_size <= 8)
+ {
+ s->Printf("0x%*.*llx", 2 * item_byte_size, 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");
+ int32_t start_idx, end_idx, delta;
+ if (m_byte_order == eByteOrderBig)
+ {
+ start_idx = offset;
+ end_idx = offset + item_byte_size;
+ delta = 1;
+ }
+ else
+ {
+ start_idx = offset + item_byte_size - 1;
+ end_idx = -1;
+ delta = -1;
+ }
+ const uint8_t *bytes = (const uint8_t* )GetData(&offset, item_byte_size);
+ if (bytes)
+ {
+ for (int32_t idx = start_idx; idx != end_idx; idx += delta)
+ s->Printf("%2.2x", bytes[idx]);
+ }
+ }
+ break;
+
+ case eFormatFloat:
+ if (sizeof(float) == item_byte_size)
+ {
+ uint32_t a32 = GetU32(&offset);
+ s->Printf ("%g", (double)(*((float *)&a32)));
+ }
+ else if (sizeof(double) == item_byte_size)
+ {
+ uint64_t a64 = GetU64(&offset);
+ s->Printf ("%lg", (*((double *)&a64)));
+ }
+ else if (sizeof(long double) == item_byte_size && sizeof(long double) <= sizeof(uint64_t))
+ {
+ uint64_t a64 = GetU64(&offset);
+ s->Printf ("%Lg", (*((long double *)&a64)));
+ }
+ break;
+
+ case eFormatUnicode16:
+ s->Printf("0x%4.4x", GetU16 (&offset));
+ break;
+
+ case eFormatUnicode32:
+ s->Printf("0x%8.8x", GetU32 (&offset));
+ break;
+
+ case eFormatVectorOfChar:
+ s->PutChar('{');
+ offset = Dump (s, start_offset, eFormatChar, 1, item_byte_size, item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt8:
+ s->PutChar('{');
+ offset = Dump (s, start_offset, eFormatDecimal, 1, item_byte_size, item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt8:
+ s->PutChar('{');
+ offset = Dump (s, start_offset, eFormatHex, 1, item_byte_size, item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt16:
+ s->PutChar('{');
+ offset = Dump (s, start_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, start_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, start_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, start_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, start_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, start_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 eFormatVectorOfFloat32:
+ s->PutChar('{');
+ offset = Dump (s, start_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, start_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, start_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", (num_per_line - (offset - line_start_offset)) * 3 + 2, "");
+ Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, UINT32_MAX, 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().
+//----------------------------------------------------------------------
+uint32_t
+DataExtractor::PutToLog
+(
+ Log *log,
+ uint32_t start_offset,
+ uint32_t length,
+ uint64_t base_addr,
+ uint32_t num_per_line,
+ DataExtractor::Type type,
+ const char *format
+) const
+{
+ if (log == NULL)
+ return start_offset;
+
+ uint32_t offset;
+ uint32_t end_offset = offset + length;
+ uint32_t count;
+ StreamString sstr;
+ for (offset = start_offset, 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.8llx:", (uint64_t)(base_addr + (offset - start_offset)));
+ }
+
+ switch (type)
+ {
+ default:
+ 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.16llx", GetU64(&offset)); break;
+ case TypePointer: sstr.Printf (format ? format : " 0x%llx", GetAddress(&offset)); break;
+ case TypeULEB128: sstr.Printf (format ? format : " 0x%llx", GetULEB128(&offset)); break;
+ case TypeSLEB128: sstr.Printf (format ? format : " %lld", 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, uint32_t offset) const
+{
+ if (s)
+ {
+ const uint8_t *uuid_data = PeekData(offset, 16);
+ if ( uuid_data )
+ {
+ UUID uuid(uuid_data, 16);
+ uuid.Dump(s);
+ }
+ else
+ {
+ s->Printf("<not enough data for UUID at offset 0x%8.8x>", offset);
+ }
+ }
+}
+
+
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
new file mode 100644
index 00000000000..c106d838fed
--- /dev/null
+++ b/lldb/source/Core/Debugger.cpp
@@ -0,0 +1,434 @@
+//===-- 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-private.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Timer.h"
+
+#include "lldb/Target/TargetList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+int Debugger::g_shared_debugger_refcount = 0;
+bool Debugger::g_in_terminate = false;
+
+Debugger::DebuggerSP &
+Debugger::GetDebuggerSP ()
+{
+ static DebuggerSP g_shared_debugger_sp;
+ return g_shared_debugger_sp;
+}
+
+void
+Debugger::Initialize ()
+{
+ g_shared_debugger_refcount++;
+ if (GetDebuggerSP().get() == NULL)
+ {
+ GetDebuggerSP().reset (new Debugger());
+ lldb_private::Initialize();
+ GetDebuggerSP()->GetCommandInterpreter().Initialize();
+ }
+}
+
+void
+Debugger::Terminate ()
+{
+ g_shared_debugger_refcount--;
+ if (g_shared_debugger_refcount == 0)
+ {
+ // Because Terminate is called also in the destructor, we need to make sure
+ // that none of the calls to GetSharedInstance leads to a call to Initialize,
+ // thus bumping the refcount back to 1 & causing Debugger::~Debugger to try to
+ // re-terminate. So we use g_in_terminate to indicate this condition.
+ // When we can require at least Initialize to be called, we won't have to do
+ // this since then the GetSharedInstance won't have to auto-call Initialize...
+
+ g_in_terminate = true;
+ int num_targets = GetDebuggerSP()->GetTargetList().GetNumTargets();
+ for (int i = 0; i < num_targets; i++)
+ {
+ ProcessSP process_sp(GetDebuggerSP()->GetTargetList().GetTargetAtIndex (i)->GetProcessSP());
+ if (process_sp)
+ process_sp->Destroy();
+ }
+ GetDebuggerSP()->DisconnectInput();
+ lldb_private::WillTerminate();
+ GetDebuggerSP().reset();
+ }
+}
+
+Debugger &
+Debugger::GetSharedInstance()
+{
+ // Don't worry about thread race conditions with the code below as
+ // lldb_private::Initialize(); does this in a thread safe way. I just
+ // want to avoid having to lock and unlock a mutex in
+ // lldb_private::Initialize(); every time we want to access the
+ // Debugger shared instance.
+
+ // FIXME: We intend to require clients to call Initialize by hand (since they
+ // will also have to call Terminate by hand.) But for now it is not clear where
+ // we can reliably call these in JH. So the present version initializes on first use
+ // here, and terminates in the destructor.
+ if (g_shared_debugger_refcount == 0 && !g_in_terminate)
+ Initialize();
+
+ assert(GetDebuggerSP().get()!= NULL);
+ return *(GetDebuggerSP().get());
+}
+
+Debugger::Debugger () :
+ m_input_comm("debugger.input"),
+ m_input_file (),
+ m_output_file (),
+ m_error_file (),
+ m_async_execution (true),
+ m_target_list (),
+ m_listener ("lldb.Debugger"),
+ m_source_manager (),
+ m_command_interpreter (eScriptLanguageDefault, false, &m_listener, m_source_manager),
+ m_input_readers (),
+ m_input_reader_data ()
+{
+}
+
+Debugger::~Debugger ()
+{
+ // FIXME:
+ // Remove this once this version of lldb has made its way through a build.
+ Terminate();
+}
+
+
+bool
+Debugger::GetAsyncExecution ()
+{
+ return m_async_execution;
+}
+
+void
+Debugger::SetAsyncExecution (bool async_execution)
+{
+ static bool value_has_been_set = false;
+
+ if (!value_has_been_set)
+ {
+ value_has_been_set = true;
+ m_async_execution = async_execution;
+ m_command_interpreter.SetSynchronous (!async_execution);
+ }
+}
+
+void
+Debugger::DisconnectInput()
+{
+ m_input_comm.Clear ();
+}
+
+void
+Debugger::SetInputFileHandle (FILE *fh, bool tranfer_ownership)
+{
+ m_input_file.SetFileHandle (fh, tranfer_ownership);
+ if (m_input_file.GetFileHandle() == NULL)
+ m_input_file.SetFileHandle (stdin, false);
+
+ // Disconnect from any old connection if we had one
+ m_input_comm.Disconnect ();
+ m_input_comm.SetConnection (new ConnectionFileDescriptor (::fileno (GetInputFileHandle()), true));
+ m_input_comm.SetReadThreadBytesReceivedCallback (Debugger::DispatchInputCallback, this);
+
+ Error error;
+ if (m_input_comm.StartReadThread (&error) == false)
+ {
+ FILE *err_fh = GetErrorFileHandle();
+ if (err_fh)
+ {
+ ::fprintf (err_fh, "error: failed to main input read thread: %s", error.AsCString() ? error.AsCString() : "unkown error");
+ exit(1);
+ }
+ }
+
+}
+
+FILE *
+Debugger::GetInputFileHandle ()
+{
+ return m_input_file.GetFileHandle();
+}
+
+
+void
+Debugger::SetOutputFileHandle (FILE *fh, bool tranfer_ownership)
+{
+ m_output_file.SetFileHandle (fh, tranfer_ownership);
+ if (m_output_file.GetFileHandle() == NULL)
+ m_output_file.SetFileHandle (stdin, false);
+}
+
+FILE *
+Debugger::GetOutputFileHandle ()
+{
+ return m_output_file.GetFileHandle();
+}
+
+void
+Debugger::SetErrorFileHandle (FILE *fh, bool tranfer_ownership)
+{
+ m_error_file.SetFileHandle (fh, tranfer_ownership);
+ if (m_error_file.GetFileHandle() == NULL)
+ m_error_file.SetFileHandle (stdin, false);
+}
+
+
+FILE *
+Debugger::GetErrorFileHandle ()
+{
+ return m_error_file.GetFileHandle();
+}
+
+CommandInterpreter &
+Debugger::GetCommandInterpreter ()
+{
+ return m_command_interpreter;
+}
+
+Listener &
+Debugger::GetListener ()
+{
+ return m_listener;
+}
+
+
+TargetSP
+Debugger::GetCurrentTarget ()
+{
+ return m_target_list.GetCurrentTarget ();
+}
+
+ExecutionContext
+Debugger::GetCurrentExecutionContext ()
+{
+ ExecutionContext exe_ctx;
+ exe_ctx.Clear();
+
+ lldb::TargetSP target_sp = GetCurrentTarget();
+ exe_ctx.target = target_sp.get();
+
+ if (target_sp)
+ {
+ exe_ctx.process = target_sp->GetProcessSP().get();
+ if (exe_ctx.process && exe_ctx.process->IsRunning() == false)
+ {
+ exe_ctx.thread = exe_ctx.process->GetThreadList().GetCurrentThread().get();
+ if (exe_ctx.thread == NULL)
+ exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get();
+ if (exe_ctx.thread)
+ {
+ exe_ctx.frame = exe_ctx.thread->GetCurrentFrame().get();
+ if (exe_ctx.frame == NULL)
+ exe_ctx.frame = exe_ctx.thread->GetStackFrameAtIndex (0).get();
+ }
+ }
+ }
+ return exe_ctx;
+
+}
+
+SourceManager &
+Debugger::GetSourceManager ()
+{
+ return m_source_manager;
+}
+
+
+TargetList&
+Debugger::GetTargetList ()
+{
+ return m_target_list;
+}
+
+void
+Debugger::DispatchInputCallback (void *baton, const void *bytes, size_t bytes_len)
+{
+ ((Debugger *)baton)->DispatchInput ((char *)bytes, bytes_len);
+}
+
+
+void
+Debugger::DispatchInput (const char *bytes, size_t bytes_len)
+{
+ if (bytes == NULL || bytes_len == 0)
+ return;
+
+ // TODO: implement the STDIO to the process as an input reader...
+ TargetSP target = GetCurrentTarget();
+ if (target.get() != NULL)
+ {
+ ProcessSP process_sp = target->GetProcessSP();
+ if (process_sp.get() != NULL
+ && StateIsRunningState (process_sp->GetState()))
+ {
+ Error error;
+ if (process_sp->PutSTDIN (bytes, bytes_len, error) == bytes_len)
+ return;
+ }
+ }
+
+ WriteToDefaultReader (bytes, bytes_len);
+}
+
+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_readers.empty() && !m_input_reader_data.empty())
+ {
+ while (CheckIfTopInputReaderIsDone ())
+ /* Do nothing. */;
+
+ // Get the input reader from the top of the stack
+ InputReaderSP reader_sp(m_input_readers.top());
+
+ if (!reader_sp)
+ break;
+
+ size_t bytes_handled = reader_sp->HandleRawBytes (m_input_reader_data.data(),
+ 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 donesvn
+ while (CheckIfTopInputReaderIsDone ())
+ /* Do nothing. */;
+
+}
+
+void
+Debugger::PushInputReader (const InputReaderSP& reader_sp)
+{
+ if (!reader_sp)
+ return;
+ if (!m_input_readers.empty())
+ {
+ // Deactivate the old top reader
+ InputReaderSP top_reader_sp (m_input_readers.top());
+ if (top_reader_sp)
+ top_reader_sp->Notify (eInputReaderDeactivate);
+ }
+ m_input_readers.push (reader_sp);
+ reader_sp->Notify (eInputReaderActivate);
+ ActivateInputReader (reader_sp);
+}
+
+bool
+Debugger::PopInputReader (const lldb::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_readers.empty())
+ {
+ InputReaderSP reader_sp(m_input_readers.top());
+
+ if (!pop_reader_sp || pop_reader_sp.get() == reader_sp.get())
+ {
+ m_input_readers.pop ();
+ reader_sp->Notify (eInputReaderDeactivate);
+ reader_sp->Notify (eInputReaderDone);
+ result = true;
+
+ if (!m_input_readers.empty())
+ {
+ reader_sp = m_input_readers.top();
+ if (reader_sp)
+ {
+ ActivateInputReader (reader_sp);
+ reader_sp->Notify (eInputReaderReactivate);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+bool
+Debugger::CheckIfTopInputReaderIsDone ()
+{
+ bool result = false;
+ if (!m_input_readers.empty())
+ {
+ InputReaderSP reader_sp(m_input_readers.top());
+
+ if (reader_sp && reader_sp->IsDone())
+ {
+ result = true;
+ PopInputReader (reader_sp);
+ }
+ }
+ return result;
+}
+
+void
+Debugger::ActivateInputReader (const InputReaderSP &reader_sp)
+{
+ FILE *in_fh = GetInputFileHandle();
+
+ if (in_fh)
+ {
+ struct termios in_fh_termios;
+ int in_fd = fileno (in_fh);
+ if (::tcgetattr(in_fd, &in_fh_termios) == 0)
+ {
+ if (reader_sp->GetEcho())
+ in_fh_termios.c_lflag |= ECHO; // Turn on echoing
+ else
+ in_fh_termios.c_lflag &= ~ECHO; // Turn off echoing
+
+ switch (reader_sp->GetGranularity())
+ {
+ case eInputReaderGranularityByte:
+ case eInputReaderGranularityWord:
+ in_fh_termios.c_lflag &= ~ICANON; // Get one char at a time
+ break;
+
+ case eInputReaderGranularityLine:
+ case eInputReaderGranularityAll:
+ in_fh_termios.c_lflag |= ICANON; // Get lines at a time
+ break;
+
+ default:
+ break;
+ }
+ ::tcsetattr (in_fd, TCSANOW, &in_fh_termios);
+ }
+ }
+}
diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp
new file mode 100644
index 00000000000..570ff726225
--- /dev/null
+++ b/lldb/source/Core/Disassembler.cpp
@@ -0,0 +1,299 @@
+//===-- 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/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/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Timer.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;
+
+
+Disassembler*
+Disassembler::FindPlugin (const ArchSpec &arch)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "Disassembler::FindPlugin (arch = %s)",
+ arch.AsCString());
+
+ std::auto_ptr<Disassembler> disassembler_ap;
+ DisassemblerCreateInstance create_callback;
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ disassembler_ap.reset (create_callback(arch));
+
+ if (disassembler_ap.get())
+ return disassembler_ap.release();
+ }
+ return NULL;
+}
+
+bool
+Disassembler::Disassemble
+(
+ const ArchSpec &arch,
+ const ExecutionContext &exe_ctx,
+ uint32_t mixed_context_lines,
+ Stream &strm
+)
+{
+ Disassembler *disassembler = Disassembler::FindPlugin(arch);
+
+ if (disassembler)
+ {
+ lldb::addr_t addr = LLDB_INVALID_ADDRESS;
+ size_t byte_size = 0;
+ if (exe_ctx.frame)
+ {
+ SymbolContext sc(exe_ctx.frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
+ if (sc.function)
+ {
+ addr = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(exe_ctx.process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ byte_size = sc.function->GetAddressRange().GetByteSize();
+ }
+ else if (sc.symbol && sc.symbol->GetAddressRangePtr())
+ {
+ addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetLoadAddress(exe_ctx.process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ {
+ byte_size = sc.symbol->GetAddressRangePtr()->GetByteSize();
+ if (byte_size == 0)
+ byte_size = DEFAULT_DISASM_BYTE_SIZE;
+ }
+ }
+ else
+ {
+ addr = exe_ctx.frame->GetPC().GetLoadAddress(exe_ctx.process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ byte_size = DEFAULT_DISASM_BYTE_SIZE;
+ }
+ }
+
+ if (byte_size)
+ {
+ DataExtractor data;
+ size_t bytes_disassembled = disassembler->ParseInstructions (&exe_ctx, eAddressTypeLoad, addr, byte_size, data);
+ if (bytes_disassembled == 0)
+ {
+ return false;
+ }
+ else
+ {
+ // We got some things disassembled...
+ size_t num_instructions = disassembler->GetInstructionList().GetSize();
+ uint32_t offset = 0;
+ SymbolContext sc;
+ SymbolContext prev_sc;
+ AddressRange sc_range;
+ if (mixed_context_lines)
+ strm.IndentMore ();
+
+ for (size_t i=0; i<num_instructions; ++i)
+ {
+ Disassembler::Instruction *inst = disassembler->GetInstructionList().GetInstructionAtIndex (i);
+ if (inst)
+ {
+ lldb::addr_t curr_addr = addr + offset;
+ if (mixed_context_lines)
+ {
+ if (!sc_range.ContainsLoadAddress (curr_addr, exe_ctx.process))
+ {
+ prev_sc = sc;
+ Address curr_so_addr;
+ Process *process = exe_ctx.process;
+ if (process && process->ResolveLoadAddress (curr_addr, curr_so_addr))
+ {
+ if (curr_so_addr.GetSection())
+ {
+ Module *module = curr_so_addr.GetSection()->GetModule();
+ uint32_t resolved_mask = module->ResolveSymbolContextForAddress(curr_so_addr, eSymbolContextEverything, sc);
+ if (resolved_mask)
+ {
+ sc.GetAddressRange (eSymbolContextEverything, sc_range);
+ if (sc != prev_sc)
+ {
+ if (offset != 0)
+ strm.EOL();
+
+ sc.DumpStopContext(&strm, process, curr_so_addr);
+
+ if (sc.comp_unit && sc.line_entry.IsValid())
+ {
+ Debugger::GetSharedInstance().GetSourceManager().DisplaySourceLinesWithLineNumbers (
+ sc.line_entry.file,
+ sc.line_entry.line,
+ mixed_context_lines,
+ mixed_context_lines,
+ mixed_context_lines ? "->" : "",
+ &strm);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (mixed_context_lines)
+ strm.IndentMore ();
+ strm.Indent();
+ size_t inst_byte_size = inst->GetByteSize();
+ //inst->Dump(&strm, curr_addr, &data, offset); // Do dump opcode bytes
+ inst->Dump(&strm, curr_addr, NULL, offset, exe_ctx, false); // Don't dump opcode bytes
+ strm.EOL();
+ offset += inst_byte_size;
+ if (mixed_context_lines)
+ strm.IndentLess ();
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (mixed_context_lines)
+ strm.IndentLess ();
+
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+Disassembler::Instruction::Instruction()
+{
+}
+
+Disassembler::Instruction::~Instruction()
+{
+}
+
+
+Disassembler::InstructionList::InstructionList() :
+ m_instructions()
+{
+}
+
+Disassembler::InstructionList::~InstructionList()
+{
+}
+
+size_t
+Disassembler::InstructionList::GetSize() const
+{
+ return m_instructions.size();
+}
+
+
+Disassembler::Instruction *
+Disassembler::InstructionList::GetInstructionAtIndex (uint32_t idx)
+{
+ if (idx < m_instructions.size())
+ return m_instructions[idx].get();
+ return NULL;
+}
+
+const Disassembler::Instruction *
+Disassembler::InstructionList::GetInstructionAtIndex (uint32_t idx) const
+{
+ if (idx < m_instructions.size())
+ return m_instructions[idx].get();
+ return NULL;
+}
+
+void
+Disassembler::InstructionList::Clear()
+{
+ m_instructions.clear();
+}
+
+void
+Disassembler::InstructionList::AppendInstruction (Instruction::shared_ptr &inst_sp)
+{
+ if (inst_sp)
+ m_instructions.push_back(inst_sp);
+}
+
+
+size_t
+Disassembler::ParseInstructions
+(
+ const ExecutionContext *exe_ctx,
+ lldb::AddressType addr_type,
+ lldb::addr_t addr,
+ size_t byte_size,
+ DataExtractor& data
+)
+{
+ Process *process = exe_ctx->process;
+
+ if (process == NULL)
+ return 0;
+
+ DataBufferSP data_sp(new DataBufferHeap (byte_size, '\0'));
+
+ Error error;
+ if (process->GetTarget().ReadMemory (addr_type, addr, data_sp->GetBytes(), data_sp->GetByteSize(), error, NULL))
+ {
+ data.SetData(data_sp);
+ data.SetByteOrder(process->GetByteOrder());
+ data.SetAddressByteSize(process->GetAddressByteSize());
+ return ParseInstructions (data, 0, UINT32_MAX, addr);
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Disassembler copy constructor
+//----------------------------------------------------------------------
+Disassembler::Disassembler(const ArchSpec& arch) :
+ m_arch (arch),
+ m_instruction_list(),
+ m_base_addr(LLDB_INVALID_ADDRESS)
+{
+
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Disassembler::~Disassembler()
+{
+}
+
+Disassembler::InstructionList &
+Disassembler::GetInstructionList ()
+{
+ return m_instruction_list;
+}
+
+const Disassembler::InstructionList &
+Disassembler::GetInstructionList () const
+{
+ return m_instruction_list;
+}
diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp
new file mode 100644
index 00000000000..b6b2f27caef
--- /dev/null
+++ b/lldb/source/Core/DynamicLoader.cpp
@@ -0,0 +1,75 @@
+//===-- 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/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)
+ {
+ create_callback = PluginManager::GetDynamicLoaderCreateCallbackForPluginName (plugin_name);
+ if (create_callback)
+ {
+ std::auto_ptr<DynamicLoader> instance_ap(create_callback(process));
+ if (instance_ap.get())
+ return instance_ap.release();
+ }
+ }
+ else
+ {
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetDynamicLoaderCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ std::auto_ptr<DynamicLoader> instance_ap(create_callback(process));
+ if (instance_ap.get())
+ return instance_ap.release();
+ }
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// DynamicLoader constructor
+//----------------------------------------------------------------------
+DynamicLoader::DynamicLoader(Process *process) :
+ m_process (process),
+ m_stop_when_images_change(false) // Stop the process by default when a process' images change
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DynamicLoader::~DynamicLoader()
+{
+}
+
+//----------------------------------------------------------------------
+// Accessosors to the global setting as to wether to stop at image
+// (shared library) loading/unloading.
+//----------------------------------------------------------------------
+bool
+DynamicLoader::GetStopWhenImagesChange () const
+{
+ return m_stop_when_images_change;
+}
+
+void
+DynamicLoader::SetStopWhenImagesChange (bool stop)
+{
+ m_stop_when_images_change = stop;
+}
+
diff --git a/lldb/source/Core/Error.cpp b/lldb/source/Core/Error.cpp
new file mode 100644
index 00000000000..c3522093f9b
--- /dev/null
+++ b/lldb/source/Core/Error.cpp
@@ -0,0 +1,365 @@
+//===-- 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 <sys/errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+
+#if defined (__arm__)
+#include <SpringBoardServices/SpringBoardServer.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+Error::Error(ValueType err, ErrorType type) :
+ m_code (err),
+ m_type (type),
+ m_string ()
+{
+}
+//----------------------------------------------------------------------
+// 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 = (kern_return_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:
+ s = ::mach_error_string (m_code);
+ 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::SetError (kern_return_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;
+ m_string.append("\n");
+ }
+ 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...
+ m_string.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);
+ int length = ::vsnprintf (&m_string[0], m_string.size(), format, args);
+ if (length < m_string.size())
+ {
+ // The error formatted string fit into our buffer, just chop it down
+ // to size
+ m_string.erase (length);
+ }
+ else
+ {
+ // The error formatted string didn't fit into our buffer, resize it
+ // to the exact needed size, and retry
+ m_string.resize(length + 1);
+ length = ::vsnprintf (&m_string[0], m_string.size(), format, copy_args);
+ va_end (copy_args);
+ assert (length < m_string.size());
+ }
+ 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;
+}
diff --git a/lldb/source/Core/Event.cpp b/lldb/source/Core/Event.cpp
new file mode 100644
index 00000000000..c2bf08d8deb
--- /dev/null
+++ b/lldb/source/Core/Event.cpp
@@ -0,0 +1,241 @@
+//===-- 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/Target/Process.h"
+
+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::Clear()
+{
+ m_data_ap.reset();
+}
+
+void
+Event::Dump (Stream *s) const
+{
+ s->Printf("%p Event: broadcaster = %p, type = 0x%8.8x, data = ", this, m_broadcaster, m_type);
+
+ if (m_data_ap.get() == NULL)
+ s->Printf ("<NULL>");
+ else
+ {
+ s->PutChar('{');
+ m_data_ap->Dump (s);
+ s->PutChar('}');
+ }
+}
+
+Broadcaster *
+Event::GetBroadcaster () const
+{
+ return m_broadcaster;
+}
+
+bool
+Event::BroadcasterIs (Broadcaster *broadcaster)
+{
+ return broadcaster == m_broadcaster;
+}
+
+uint32_t
+Event::GetType() const
+{
+ return m_type;
+}
+
+
+EventData *
+Event::GetData ()
+{
+ return m_data_ap.get();
+}
+
+const EventData *
+Event::GetData () const
+{
+ return m_data_ap.get();
+}
+
+void
+Event::DoOnRemoval ()
+{
+ if (m_data_ap.get())
+ m_data_ap->DoOnRemoval (this);
+}
+
+void
+Event::SetBroadcaster (Broadcaster *broadcaster)
+{
+ m_broadcaster = broadcaster;
+}
+
+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
+ {
+ DataExtractor data;
+ data.SetData(m_bytes.data(), m_bytes.size(), eByteOrderHost);
+ 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.data();
+}
+
+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;
+}
+
diff --git a/lldb/source/Core/FileSpec.cpp b/lldb/source/Core/FileSpec.cpp
new file mode 100644
index 00000000000..305650d8643
--- /dev/null
+++ b/lldb/source/Core/FileSpec.cpp
@@ -0,0 +1,580 @@
+//===-- FileSpec.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include <fcntl.h>
+#include <glob.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <fstream>
+
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataBufferMemoryMap.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace std;
+
+static bool
+GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr)
+{
+ char resolved_path[PATH_MAX];
+ if (file_spec->GetPath(&resolved_path[0], sizeof(resolved_path)))
+ return ::stat (resolved_path, stats_ptr) == 0;
+ return false;
+}
+
+static const char*
+GetCachedGlobTildeSlash()
+{
+ static std::string g_tilde;
+ if (g_tilde.empty())
+ {
+ glob_t globbuf;
+ if (::glob("~/", GLOB_TILDE, NULL, &globbuf) == 0) //success
+ {
+ g_tilde = globbuf.gl_pathv[0];
+ ::globfree (&globbuf);
+ }
+ if (g_tilde.empty())
+ return NULL;
+ }
+ return g_tilde.c_str();
+}
+
+int
+FileSpec::Resolve (const char *src_path, char *dst_path, size_t dst_len)
+{
+ if (src_path == NULL || src_path[0] == '\0')
+ return 0;
+
+ // Glob if needed for ~/, otherwise copy in case src_path is same as dst_path...
+ char unglobbed_path[PATH_MAX];
+ if (::strstr (src_path, "~/") == src_path)
+ ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s%s", GetCachedGlobTildeSlash(), src_path + 2);
+ else
+ ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s", src_path);
+
+ // Now resolve the path if needed
+ char resolved_path[PATH_MAX];
+ if (::realpath (unglobbed_path, resolved_path))
+ {
+ // Success, copy the resolved path
+ return ::snprintf(dst_path, dst_len, "%s", resolved_path);
+ }
+ else
+ {
+ // Failed, just copy the unglobbed path
+ return ::snprintf(dst_path, dst_len, "%s", unglobbed_path);
+ }
+}
+
+FileSpec::FileSpec() :
+ m_directory(),
+ m_filename()
+{
+}
+
+//------------------------------------------------------------------
+// Default constructor that can take an optional full path to a
+// file on disk.
+//------------------------------------------------------------------
+FileSpec::FileSpec(const char *pathname) :
+ m_directory(),
+ m_filename()
+{
+ if (pathname && pathname[0])
+ SetFile(pathname);
+}
+
+//------------------------------------------------------------------
+// Copy constructor
+//------------------------------------------------------------------
+FileSpec::FileSpec(const FileSpec& rhs) :
+ m_directory (rhs.m_directory),
+ m_filename (rhs.m_filename)
+{
+}
+
+//------------------------------------------------------------------
+// Copy constructor
+//------------------------------------------------------------------
+FileSpec::FileSpec(const FileSpec* rhs) :
+ m_directory(),
+ m_filename()
+{
+ if (rhs)
+ *this = *rhs;
+}
+
+//------------------------------------------------------------------
+// Virtual destrcuctor in case anyone inherits from this class.
+//------------------------------------------------------------------
+FileSpec::~FileSpec()
+{
+}
+
+//------------------------------------------------------------------
+// Assignment operator.
+//------------------------------------------------------------------
+const FileSpec&
+FileSpec::operator= (const FileSpec& rhs)
+{
+ if (this != &rhs)
+ {
+ m_directory = rhs.m_directory;
+ m_filename = rhs.m_filename;
+ }
+ return *this;
+}
+
+
+//------------------------------------------------------------------
+// Update the contents of this object with a new path. The path will
+// be split up into a directory and filename and stored as uniqued
+// string values for quick comparison and efficient memory usage.
+//------------------------------------------------------------------
+void
+FileSpec::SetFile(const char *pathname)
+{
+ m_filename.Clear();
+ m_directory.Clear();
+ if (pathname == NULL || pathname[0] == '\0')
+ return;
+
+ char resolved_path[PATH_MAX];
+
+ if (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1)
+ {
+ char *filename = ::basename (resolved_path);
+ if (filename)
+ {
+ m_filename.SetCString (filename);
+ // Truncate the basename off the end of the resolved path
+
+ // Only attempt to get the dirname if it looks like we have a path
+ if (strchr(resolved_path, '/'))
+ {
+ char *directory = ::dirname (resolved_path);
+
+ // Make sure we didn't get our directory resolved to "." without having
+ // specified
+ if (directory)
+ m_directory.SetCString(directory);
+ else
+ {
+ char *last_resolved_path_slash = strrchr(resolved_path, '/');
+ if (last_resolved_path_slash)
+ {
+ *last_resolved_path_slash = '\0';
+ m_directory.SetCString(resolved_path);
+ }
+ }
+ }
+ }
+ else
+ m_directory.SetCString(resolved_path);
+ }
+}
+
+//----------------------------------------------------------------------
+// Convert to pointer operator. This allows code to check any FileSpec
+// objects to see if they contain anything valid using code such as:
+//
+// if (file_spec)
+// {}
+//----------------------------------------------------------------------
+FileSpec::operator
+void*() const
+{
+ return (m_directory || m_filename) ? const_cast<FileSpec*>(this) : NULL;
+}
+
+//----------------------------------------------------------------------
+// Logical NOT operator. This allows code to check any FileSpec
+// objects to see if they are invalid using code such as:
+//
+// if (!file_spec)
+// {}
+//----------------------------------------------------------------------
+bool
+FileSpec::operator!() const
+{
+ return !m_directory && !m_filename;
+}
+
+//------------------------------------------------------------------
+// Equal to operator
+//------------------------------------------------------------------
+bool
+FileSpec::operator== (const FileSpec& rhs) const
+{
+ return m_directory == rhs.m_directory && m_filename == rhs.m_filename;
+}
+
+//------------------------------------------------------------------
+// Not equal to operator
+//------------------------------------------------------------------
+bool
+FileSpec::operator!= (const FileSpec& rhs) const
+{
+ return m_filename != rhs.m_filename || m_directory != rhs.m_directory;
+}
+
+//------------------------------------------------------------------
+// Less than operator
+//------------------------------------------------------------------
+bool
+FileSpec::operator< (const FileSpec& rhs) const
+{
+ return FileSpec::Compare(*this, rhs, true) < 0;
+}
+
+//------------------------------------------------------------------
+// Dump a FileSpec object to a stream
+//------------------------------------------------------------------
+Stream&
+lldb_private::operator << (Stream &s, const FileSpec& f)
+{
+ f.Dump(&s);
+ return s;
+}
+
+//------------------------------------------------------------------
+// Clear this object by releasing both the directory and filename
+// string values and making them both the empty string.
+//------------------------------------------------------------------
+void
+FileSpec::Clear()
+{
+ m_directory.Clear();
+ m_filename.Clear();
+}
+
+//------------------------------------------------------------------
+// Compare two FileSpec objects. If "full" is true, then both
+// the directory and the filename must match. If "full" is false,
+// then the directory names for "a" and "b" are only compared if
+// they are both non-empty. This allows a FileSpec object to only
+// contain a filename and it can match FileSpec objects that have
+// matching filenames with different paths.
+//
+// Return -1 if the "a" is less than "b", 0 if "a" is equal to "b"
+// and "1" if "a" is greater than "b".
+//------------------------------------------------------------------
+int
+FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full)
+{
+ int result = 0;
+
+ // If full is true, then we must compare both the directory and filename.
+
+ // If full is false, then if either directory is empty, then we match on
+ // the basename only, and if both directories have valid values, we still
+ // do a full compare. This allows for matching when we just have a filename
+ // in one of the FileSpec objects.
+
+ if (full || (a.m_directory && b.m_directory))
+ {
+ result = ConstString::Compare(a.m_directory, b.m_directory);
+ if (result)
+ return result;
+ }
+ return ConstString::Compare (a.m_filename, b.m_filename);
+}
+
+bool
+FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full)
+{
+ if (full)
+ return a == b;
+ else
+ return a.m_filename == b.m_filename;
+}
+
+
+
+//------------------------------------------------------------------
+// Dump the object to the supplied stream. If the object contains
+// a valid directory name, it will be displayed followed by a
+// directory delimiter, and the filename.
+//------------------------------------------------------------------
+void
+FileSpec::Dump(Stream *s) const
+{
+ if (m_filename)
+ m_directory.Dump(s, ""); // Provide a default for m_directory when we dump it in case it is invalid
+
+ if (m_directory)
+ {
+ // If dirname was valid, then we need to print a slash between
+ // the directory and the filename
+ s->PutChar('/');
+ }
+ m_filename.Dump(s);
+}
+
+//------------------------------------------------------------------
+// Returns true if the file exists.
+//------------------------------------------------------------------
+bool
+FileSpec::Exists () const
+{
+ struct stat file_stats;
+ return GetFileStats (this, &file_stats);
+}
+
+uint64_t
+FileSpec::GetByteSize() const
+{
+ struct stat file_stats;
+ if (GetFileStats (this, &file_stats))
+ return file_stats.st_size;
+ return 0;
+}
+
+FileSpec::FileType
+FileSpec::GetFileType () const
+{
+ struct stat file_stats;
+ if (GetFileStats (this, &file_stats))
+ {
+ mode_t file_type = file_stats.st_mode & S_IFMT;
+ switch (file_type)
+ {
+ case S_IFDIR: return eFileTypeDirectory;
+ case S_IFIFO: return eFileTypePipe;
+ case S_IFREG: return eFileTypeRegular;
+ case S_IFSOCK: return eFileTypeSocket;
+ case S_IFLNK: return eFileTypeSymbolicLink;
+ default:
+ break;
+ }
+ return eFileTypeUknown;
+ }
+ return eFileTypeInvalid;
+}
+
+TimeValue
+FileSpec::GetModificationTime () const
+{
+ TimeValue mod_time;
+ struct stat file_stats;
+ if (GetFileStats (this, &file_stats))
+ mod_time = file_stats.st_mtimespec;
+ return mod_time;
+}
+
+//------------------------------------------------------------------
+// Directory string get accessor.
+//------------------------------------------------------------------
+ConstString &
+FileSpec::GetDirectory()
+{
+ return m_directory;
+}
+
+//------------------------------------------------------------------
+// Directory string const get accessor.
+//------------------------------------------------------------------
+const ConstString &
+FileSpec::GetDirectory() const
+{
+ return m_directory;
+}
+
+//------------------------------------------------------------------
+// Filename string get accessor.
+//------------------------------------------------------------------
+ConstString &
+FileSpec::GetFilename()
+{
+ return m_filename;
+}
+
+//------------------------------------------------------------------
+// Filename string const get accessor.
+//------------------------------------------------------------------
+const ConstString &
+FileSpec::GetFilename() const
+{
+ return m_filename;
+}
+
+//------------------------------------------------------------------
+// Extract the directory and path into a fixed buffer. This is
+// needed as the directory and path are stored in separate string
+// values.
+//------------------------------------------------------------------
+bool
+FileSpec::GetPath(char *path, size_t max_path_length) const
+{
+ if (max_path_length == 0)
+ return false;
+
+ path[0] = '\0';
+ const char *dirname = m_directory.AsCString();
+ const char *filename = m_filename.AsCString();
+ if (dirname)
+ {
+ if (filename && filename[0])
+ {
+ return snprintf (path, max_path_length, "%s/%s", dirname, filename) < max_path_length;
+ }
+ else
+ {
+ strncpy (path, dirname, max_path_length);
+ }
+ }
+ else if (filename)
+ {
+ strncpy (path, filename, max_path_length);
+ }
+
+ // Any code paths that reach here assume that strncpy, or a similar function was called
+ // where any remaining bytes will be filled with NULLs and that the string won't be
+ // NULL terminated if it won't fit in the buffer.
+
+ // If the last character is NULL, then all went well
+ if (path[max_path_length-1] == '\0')
+ return true;
+
+ // Make sure the path is terminated, as it didn't fit into "path"
+ path[max_path_length-1] = '\0';
+ return false;
+}
+
+//------------------------------------------------------------------
+// Returns a shared pointer to a data buffer that contains all or
+// part of the contents of a file. The data is memory mapped and
+// will lazily page in data from the file as memory is accessed.
+// The data that is mappped will start "file_offset" bytes into the
+// file, and "file_size" bytes will be mapped. If "file_size" is
+// greater than the number of bytes available in the file starting
+// at "file_offset", the number of bytes will be appropriately
+// truncated. The final number of bytes that get mapped can be
+// verified using the DataBuffer::GetByteSize() function.
+//------------------------------------------------------------------
+DataBufferSP
+FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const
+{
+ DataBufferSP data_sp;
+ auto_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap());
+ if (mmap_data.get())
+ {
+ if (mmap_data->MemoryMapFromFileSpec (this, file_offset, file_size) >= file_size)
+ data_sp.reset(mmap_data.release());
+ }
+ return data_sp;
+}
+
+
+//------------------------------------------------------------------
+// Return the size in bytes that this object takes in memory. This
+// returns the size in bytes of this object, not any shared string
+// values it may refer to.
+//------------------------------------------------------------------
+size_t
+FileSpec::MemorySize() const
+{
+ return m_filename.MemorySize() + m_directory.MemorySize();
+}
+
+//------------------------------------------------------------------
+// Returns a shared pointer to a data buffer that contains all or
+// part of the contents of a file. The data copies into a heap based
+// buffer that lives in the DataBuffer shared pointer object returned.
+// The data that is cached will start "file_offset" bytes into the
+// file, and "file_size" bytes will be mapped. If "file_size" is
+// greater than the number of bytes available in the file starting
+// at "file_offset", the number of bytes will be appropriately
+// truncated. The final number of bytes that get mapped can be
+// verified using the DataBuffer::GetByteSize() function.
+//------------------------------------------------------------------
+DataBufferSP
+FileSpec::ReadFileContents(off_t file_offset, size_t file_size) const
+{
+ DataBufferSP data_sp;
+ char resolved_path[PATH_MAX];
+ if (GetPath(resolved_path, sizeof(resolved_path)))
+ {
+ int fd = ::open (resolved_path, O_RDONLY, 0);
+ if (fd != -1)
+ {
+ struct stat file_stats;
+ if (::fstat (fd, &file_stats) == 0)
+ {
+ // Read bytes directly into our basic_string buffer
+ if (file_stats.st_size > 0)
+ {
+ off_t lseek_result = 0;
+ if (file_offset > 0)
+ lseek_result = ::lseek (fd, file_offset, SEEK_SET);
+
+ if (lseek_result < 0)
+ {
+ // Get error from errno
+ }
+ else if (lseek_result == file_offset)
+ {
+ std::auto_ptr<DataBufferHeap> data_heap_ap;
+ if (file_stats.st_size < file_size)
+ data_heap_ap.reset(new DataBufferHeap(file_stats.st_size, '\0'));
+ else
+ data_heap_ap.reset(new DataBufferHeap(file_size, '\0'));
+
+ if (data_heap_ap.get())
+ {
+ ssize_t bytesRead = ::read (fd, (void *)data_heap_ap->GetBytes(), data_heap_ap->GetByteSize());
+ if (bytesRead >= 0)
+ {
+ // Make sure we read exactly what we asked for and if we got
+ // less, adjust the array
+ if (bytesRead < data_heap_ap->GetByteSize())
+ data_heap_ap->SetByteSize(bytesRead);
+ data_sp.reset(data_heap_ap.release());
+ }
+ }
+ }
+ }
+ }
+ }
+ close(fd);
+ }
+ return data_sp;
+}
+
+bool
+FileSpec::ReadFileLines (STLStringArray &lines)
+{
+ bool ret_val = false;
+ lines.clear();
+
+ std::string dir_str (m_directory.AsCString());
+ std::string file_str (m_filename.AsCString());
+ std::string full_name = dir_str + "/" + file_str;
+
+ ifstream file_stream (full_name.c_str());
+
+ if (file_stream)
+ {
+ std::string line;
+ while (getline (file_stream, line))
+ lines.push_back (line);
+ ret_val = true;
+ }
+
+ return ret_val;
+}
diff --git a/lldb/source/Core/FileSpecList.cpp b/lldb/source/Core/FileSpecList.cpp
new file mode 100644
index 00000000000..17abf4b24e5
--- /dev/null
+++ b/lldb/source/Core/FileSpecList.cpp
@@ -0,0 +1,228 @@
+//===-- 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"
+
+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
+{
+ for_each (m_files.begin(), m_files.end(), bind2nd(mem_fun_ref(&FileSpec::Dump),s));
+}
+
+//------------------------------------------------------------------
+// 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.
+//------------------------------------------------------------------
+uint32_t
+FileSpecList::FindFileIndex (uint32_t start_idx, const FileSpec &file_spec) const
+{
+ const uint32_t num_files = m_files.size();
+ uint32_t idx;
+
+ // 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 (idx = start_idx; idx < num_files; ++idx)
+ {
+ if (compare_filename_only)
+ {
+ if (m_files[idx].GetFilename() == file_spec.GetFilename())
+ return idx;
+ }
+ else
+ {
+ if (m_files[idx] == file_spec)
+ 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(uint32_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(uint32_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.
+//------------------------------------------------------------------
+uint32_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/lldb/source/Core/Flags.cpp b/lldb/source/Core/Flags.cpp
new file mode 100644
index 00000000000..13cbd85915b
--- /dev/null
+++ b/lldb/source/Core/Flags.cpp
@@ -0,0 +1,122 @@
+//===-- Flags.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/Flags.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default Constructor
+//----------------------------------------------------------------------
+Flags::Flags (ValueType flags) :
+ m_flags(flags)
+{
+}
+
+//----------------------------------------------------------------------
+// Copy Constructor
+//----------------------------------------------------------------------
+Flags::Flags (const Flags& rhs) :
+ m_flags(rhs.m_flags)
+{
+}
+
+//----------------------------------------------------------------------
+// Virtual destructor in case anyone inherits from this class.
+//----------------------------------------------------------------------
+Flags::~Flags ()
+{
+}
+
+//----------------------------------------------------------------------
+// Get accessor for all of the current flag bits.
+//----------------------------------------------------------------------
+Flags::ValueType
+Flags::GetAllFlagBits () const
+{
+ return m_flags;
+}
+
+size_t
+Flags::GetBitSize() const
+{
+ return sizeof (ValueType) * 8;
+}
+
+//----------------------------------------------------------------------
+// Set accessor for all of the current flag bits.
+//----------------------------------------------------------------------
+void
+Flags::SetAllFlagBits (ValueType flags)
+{
+ m_flags = flags;
+}
+
+//----------------------------------------------------------------------
+// Clear one or more bits in our flag bits
+//----------------------------------------------------------------------
+Flags::ValueType
+Flags::Clear (ValueType bits)
+{
+ m_flags &= ~bits;
+ return m_flags;
+}
+
+//----------------------------------------------------------------------
+// Set one or more bits in our flag bits
+//----------------------------------------------------------------------
+Flags::ValueType
+Flags::Set (ValueType bits)
+{
+ m_flags |= bits;
+ return m_flags;
+}
+
+//----------------------------------------------------------------------
+// Returns true if any flag bits in "bits" are set
+//----------------------------------------------------------------------
+bool
+Flags::IsSet (ValueType bits) const
+{
+ return (m_flags & bits) != 0;
+}
+
+//----------------------------------------------------------------------
+// Returns true if all flag bits in "bits" are clear
+//----------------------------------------------------------------------
+bool
+Flags::IsClear (ValueType bits) const
+{
+ return (m_flags & bits) == 0;
+}
+
+
+size_t
+Flags::SetCount () const
+{
+ size_t count = 0;
+ for (ValueType mask = m_flags; mask; mask >>= 1)
+ {
+ if (mask & 1)
+ ++count;
+ }
+ return count;
+}
+
+size_t
+Flags::ClearCount () const
+{
+ size_t count = 0;
+ for (ValueType shift = 0; shift < sizeof(ValueType)*8; ++shift)
+ {
+ if ((m_flags & (1u << shift)) == 0)
+ ++count;
+ }
+ return count;
+}
diff --git a/lldb/source/Core/InputReader.cpp b/lldb/source/Core/InputReader.cpp
new file mode 100644
index 00000000000..c139a87387a
--- /dev/null
+++ b/lldb/source/Core/InputReader.cpp
@@ -0,0 +1,343 @@
+//===-- 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 <string>
+
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Debugger.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+InputReader::InputReader () :
+ m_callback (NULL),
+ m_callback_baton (NULL),
+ m_end_token (),
+ m_granularity (eInputReaderGranularityInvalid),
+ m_done (true),
+ m_echo (true),
+ m_active (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)
+ {
+ 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;
+ const char *end = bytes + bytes_len;
+ 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;
+}
+
+
+FILE *
+InputReader::GetInputFileHandle ()
+{
+ return Debugger::GetSharedInstance().GetInputFileHandle ();
+}
+
+FILE *
+InputReader::GetOutputFileHandle ()
+{
+ return Debugger::GetSharedInstance().GetOutputFileHandle ();
+}
+
+const char *
+InputReader::GetPrompt () const
+{
+ if (!m_prompt.empty())
+ return m_prompt.c_str();
+ else
+ return NULL;
+}
+
+void
+InputReader::RefreshPrompt ()
+{
+ if (!m_prompt.empty())
+ {
+ FILE *out_fh = GetOutputFileHandle();
+ if (out_fh)
+ ::fprintf (out_fh, "%s", m_prompt.c_str());
+ }
+}
+
+void
+InputReader::Notify (InputReaderAction notification)
+{
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ case eInputReaderReactivate:
+ m_active = true;
+ break;
+
+ case eInputReaderDeactivate:
+ case eInputReaderDone:
+ m_active = false;
+ 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);
+}
diff --git a/lldb/source/Core/Language.cpp b/lldb/source/Core/Language.cpp
new file mode 100644
index 00000000000..82b4e4f3aca
--- /dev/null
+++ b/lldb/source/Core/Language.cpp
@@ -0,0 +1,150 @@
+//===-- 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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define ENUM_TO_DCSTREAM(x) case x: s->PutCString(#x); return
+
+typedef 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 uint32_t
+g_num_languages = sizeof(g_languages)/sizeof(LanguageStrings);
+
+Language::Language(Language::Type language) :
+ m_language (language)
+{
+}
+
+Language::~Language()
+{
+}
+
+Language::Type
+Language::GetLanguage() const
+{
+ return m_language;
+}
+
+void
+Language::Clear ()
+{
+ m_language = Unknown;
+}
+
+void
+Language::SetLanguage(Language::Type 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 = (Language::Type)i;
+ return true;
+ }
+ }
+ }
+
+ m_language = Unknown;
+ 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/lldb/source/Core/Listener.cpp b/lldb/source/Core/Listener.cpp
new file mode 100644
index 00000000000..639b74a4c7d
--- /dev/null
+++ b/lldb/source/Core/Listener.cpp
@@ -0,0 +1,480 @@
+//===-- 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"
+
+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);
+ 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();
+}
+
+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::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 (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.Reset();
+ 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)
+ {
+ 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
+ m_cond_wait.SetValue (false, eBroadcastNever);
+
+ if (m_cond_wait.WaitForValueEqualTo (true, timeout, &timed_out))
+ continue;
+
+ else if (timed_out)
+ {
+ if (log)
+ log->Printf ("%p Listener::WaitForEvents() timed out for %s", this, m_name.c_str());
+ break;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("%p Listener::WaitForEvents() 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;
+}
diff --git a/lldb/source/Core/Log.cpp b/lldb/source/Core/Log.cpp
new file mode 100644
index 00000000000..fe2071683ca
--- /dev/null
+++ b/lldb/source/Core/Log.cpp
@@ -0,0 +1,590 @@
+//===-- Log.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 <mach/mach.h>
+#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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static Stream *
+StreamForSTDOUTAccess (bool set, StreamSP &stream_sp)
+{
+ // Since we are in a shared library and we can't have global
+ // constructors, we need to control access to this static variable
+ // through an accessor function to get and set the value.
+ static StreamSP g_stream_sp;
+
+ if (set)
+ g_stream_sp = stream_sp;
+ else
+ {
+ if (g_stream_sp)
+ stream_sp = g_stream_sp;
+ else
+ {
+ FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle();
+ if (out_fh)
+ stream_sp.reset(new StreamFile(out_fh));
+ else
+ stream_sp.reset();
+ }
+ }
+ return stream_sp.get();
+}
+
+StreamSP
+Log::GetStreamForSTDOUT ()
+{
+ StreamSP stream_sp;
+ StreamForSTDOUTAccess (false, stream_sp);
+ return stream_sp;
+}
+
+void
+Log::SetStreamForSTDOUT (StreamSP &stream_sp)
+{
+ StreamForSTDOUTAccess (true, stream_sp);
+}
+
+void
+Log::STDOUT (const char *format, ...)
+{
+ StreamSP stream_sp;
+ if (StreamForSTDOUTAccess(false, stream_sp))
+ {
+ va_list args;
+ va_start (args, format);
+ stream_sp->PrintfVarArg(format, args);
+ va_end (args);
+ }
+}
+
+static Stream *
+StreamForSTDERRAccess (bool set, StreamSP &stream_sp)
+{
+ // Since we are in a shared library and we can't have global
+ // constructors, we need to control access to this static variable
+ // through an accessor function to get and set the value.
+ static StreamSP g_stream_sp(new StreamFile(Debugger::GetSharedInstance().GetErrorFileHandle()));
+
+ if (set)
+ g_stream_sp = stream_sp;
+ else
+ stream_sp = g_stream_sp;
+ return stream_sp.get();
+}
+
+StreamSP
+Log::GetStreamForSTDERR ()
+{
+ StreamSP stream_sp;
+ StreamForSTDERRAccess (false, stream_sp);
+ return stream_sp;
+}
+
+void
+Log::SetStreamForSTDERR (StreamSP &stream_sp)
+{
+ StreamForSTDERRAccess (true, stream_sp);
+}
+
+void
+Log::STDERR (const char *format, ...)
+{
+ StreamSP stream_sp;
+ if (StreamForSTDERRAccess(false, stream_sp))
+ {
+ va_list args;
+ va_start (args, format);
+ stream_sp->PrintfVarArg(format, args);
+ va_end (args);
+ }
+}
+
+Log::Log () :
+ m_stream_sp(),
+ m_options(0),
+ m_mask_bits(0)
+{
+}
+
+Log::Log (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;
+ static Mutex g_LogThreadedMutex(Mutex::eMutexTypeRecursive);
+
+ Mutex::Locker locker;
+
+ uint32_t log_options = m_options.GetAllFlagBits();
+
+ // Lock the threaded logging mutex if we are doing thread safe logging
+ if (log_options & LLDB_LOG_OPTION_THREADSAFE)
+ locker.Reset(g_LogThreadedMutex.GetMutex());
+
+ // Add a sequence ID if requested
+ if (log_options & LLDB_LOG_OPTION_PREPEND_SEQUENCE)
+ header.Printf ("%u ", ++g_sequence_id);
+
+ // Timestamp if requested
+ if (log_options & LLDB_LOG_OPTION_PREPEND_TIMESTAMP)
+ {
+ struct timeval tv = TimeValue::Now().GetAsTimeVal();
+ header.Printf ("%9llu.%6.6llu ", tv.tv_sec, tv.tv_usec);
+ }
+
+ // Add the process and thread if requested
+ if (log_options & LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD)
+ header.Printf ("[%4.4x/%4.4x]: ", getpid(), mach_thread_self());
+
+ // Add the process and thread if requested
+ if (log_options & LLDB_LOG_OPTION_PREPEND_THREAD_NAME)
+ {
+ const char *thread_name_str = Host::GetThreadName (getpid(), mach_thread_self());
+ if (thread_name_str)
+ header.Printf ("%s ", thread_name_str);
+ }
+
+ header.PrintfVarArg (format, args);
+ m_stream_sp->Printf("%s\n", header.GetData());
+ }
+}
+
+
+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().IsSet(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().IsSet(LLDB_LOG_OPTION_DEBUG) && GetOptions().IsSet(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 ((bits & m_options.GetAllFlagBits()) == 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.IsSet(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.IsSet(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 <std::string, 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 char *channel, const Log::Callbacks &log_callbacks)
+{
+ GetCallbackMap().insert(std::make_pair(channel, log_callbacks));
+}
+
+bool
+Log::UnregisterLogChannel (const char *channel)
+{
+ return GetCallbackMap().erase(channel) != 0;
+}
+
+bool
+Log::GetLogChannelCallbacks (const char *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;
+ }
+ ::bzero (&log_callbacks, sizeof(log_callbacks));
+ return false;
+}
+
+void
+Log::EnableAllLogChannels
+(
+ StreamSP &log_stream_sp,
+ uint32_t log_options,
+ Args &args,
+ 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, args, 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, args);
+ }
+
+}
+
+void
+Log::DisableAllLogChannels ()
+{
+ CallbackMap &callback_map = GetCallbackMap ();
+ CallbackMapIter pos, end = callback_map.end();
+
+ for (pos = callback_map.begin(); pos != end; ++pos)
+ pos->second.disable ();
+
+ 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 ();
+}
+
+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
+{
+ 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())
+ {
+ LogChannelCreateInstance create_callback = PluginManager::GetLogChannelCreateCallbackForPluginName (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_sp ()
+{
+}
+
+LogChannel::~LogChannel ()
+{
+}
+
+const char *
+LogChannel::GetPluginSuffix ()
+{
+ return ".log-channel";
+}
+
+
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
new file mode 100644
index 00000000000..38667a86def
--- /dev/null
+++ b/lldb/source/Core/Mangled.cpp
@@ -0,0 +1,733 @@
+//===-- Mangled.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cxxabi.h>
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+
+using namespace lldb_private;
+
+#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 char *s, bool mangled) :
+ m_mangled(),
+ m_demangled()
+{
+ if (s && s[0])
+ {
+ SetValue(s, mangled);
+ }
+}
+
+//----------------------------------------------------------------------
+// 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(), a.GetName());
+}
+
+
+
+//----------------------------------------------------------------------
+// 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 char *s, bool mangled)
+{
+ m_mangled.Clear();
+ m_demangled.Clear();
+
+ if (s)
+ {
+ if (mangled)
+ m_mangled.SetCString (s);
+ else
+ m_demangled.SetCString(s);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// 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());
+
+ // We already know mangled is valid from the above check,
+ // lets just make sure it isn't empty...
+ const char * mangled = m_mangled.AsCString();
+ if (mangled[0])
+ {
+ // The first time the demangling routine is called, it will
+ // return a buffer value and length and we will continue to
+ // re-use that buffer so we don't always have to malloc/free
+ // a buffer for each demangle. The buffer can be realloc'ed
+ // by abi::__cxa_demangle, so we may need to make it thread
+ // specific if we ever start doing multi-threaded calls to
+ // this function. g_demangle_buf will currently leak one
+ // malloc entry that can vary in size. If we need to reclaim
+ // this memory, we will need to add some code to free this
+ // buffer at exit time.
+ static char *g_demangle_buf = NULL;
+ static size_t g_demangle_buf_len = 0;
+ int status = 0;
+ g_demangle_buf = abi::__cxa_demangle(mangled, g_demangle_buf, &g_demangle_buf_len, &status);
+ if (g_demangle_buf != NULL)
+ {
+ m_demangled.SetCString(g_demangle_buf);
+ }
+ else
+ {
+ // Set the demangled string to the empty string to indicate we
+ // tried to parse it once and failed.
+ m_demangled.SetCString("");
+ }
+ }
+ }
+
+ return m_demangled;
+}
+
+//----------------------------------------------------------------------
+// Mangled name get accessor
+//----------------------------------------------------------------------
+ConstString&
+Mangled::GetMangledName ()
+{
+ return m_mangled;
+}
+
+//----------------------------------------------------------------------
+// Mangled name const get accessor
+//----------------------------------------------------------------------
+const ConstString&
+Mangled::GetMangledName () const
+{
+ return m_mangled;
+}
+
+//----------------------------------------------------------------------
+// Get the demangled name if there is one, else return the mangled name.
+//----------------------------------------------------------------------
+const ConstString&
+Mangled::GetName () const
+{
+ const ConstString& name = GetDemangledName();
+ if (name && !name.IsEmpty())
+ return name;
+ return m_mangled;
+}
+
+//----------------------------------------------------------------------
+// Generate the tokens from the demangled name.
+//
+// Returns the number of tokens that were parsed.
+//----------------------------------------------------------------------
+size_t
+Mangled::GetTokens (Mangled::TokenList &tokens) const
+{
+ tokens.Clear();
+ const ConstString& demangled = GetDemangledName();
+ if (demangled && !demangled.IsEmpty())
+ tokens.Parse(demangled.AsCString());
+
+ return tokens.Size();
+}
+
+//----------------------------------------------------------------------
+// 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;
+}
+
+
+
+
+#pragma mark Mangled::Token
+
+//--------------------------------------------------------------
+// Default constructor
+//--------------------------------------------------------------
+Mangled::Token::Token () :
+ type(eInvalid),
+ value()
+{
+}
+
+//--------------------------------------------------------------
+// Equal to operator
+//--------------------------------------------------------------
+bool
+Mangled::Token::operator== (const Token& rhs) const
+{
+ return type == rhs.type && value == rhs.value;
+}
+
+//--------------------------------------------------------------
+// Dump the token to a stream "s"
+//--------------------------------------------------------------
+void
+Mangled::Token::Dump (Stream *s) const
+{
+ switch (type)
+ {
+ case eInvalid: s->PutCString("invalid "); break;
+ case eNameSpace: s->PutCString("namespace "); break;
+ case eMethodName: s->PutCString("method "); break;
+ case eType: s->PutCString("type "); break;
+ case eTemplate: s->PutCString("template "); break;
+ case eTemplateBeg: s->PutCString("template < "); break;
+ case eTemplateEnd: s->PutCString("template > "); break;
+ case eParamsBeg: s->PutCString("params ( "); break;
+ case eParamsEnd: s->PutCString("params ) "); break;
+ case eQualifier: s->PutCString("qualifier "); break;
+ case eError: s->PutCString("ERROR "); break;
+ default:
+ s->Printf("type = %i", type);
+ break;
+ }
+ value.DumpDebug(s);
+}
+
+//--------------------------------------------------------------
+// Returns true if this token is a wildcard
+//--------------------------------------------------------------
+bool
+Mangled::Token::IsWildcard () const
+{
+ static ConstString g_wildcard_str("*");
+ return value == g_wildcard_str;
+}
+
+
+//----------------------------------------------------------------------
+// Dump "obj" to the supplied stream "s"
+//----------------------------------------------------------------------
+Stream&
+lldb_private::operator << (Stream& s, const Mangled::Token& obj)
+{
+ obj.Dump(&s);
+ return s;
+}
+
+
+#pragma mark Mangled::TokenList
+//----------------------------------------------------------------------
+// Mangled::TokenList
+//----------------------------------------------------------------------
+
+//--------------------------------------------------------------
+// Default constructor. If demangled is non-NULL and not-empty
+// the token list will parse up the demangled string it is
+// given, else the object will initialize an empty token list.
+//--------------------------------------------------------------
+Mangled::TokenList::TokenList (const char *demangled) :
+ m_tokens()
+{
+ if (demangled && demangled[0])
+ {
+ Parse(demangled);
+ }
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Mangled::TokenList::~TokenList ()
+{
+}
+
+//----------------------------------------------------------------------
+// Parses "demangled" into tokens. This allows complex
+// comparisons to be done. Comparisons can include wildcards at
+// the namespace, method name, template, and template and
+// parameter type levels.
+//
+// Example queries include:
+// "std::basic_string<*>" // Find all std::basic_string variants
+// "std::basic_string<*>::erase(*)" // Find all std::basic_string::erase variants with any number of parameters
+// "*::clear()" // Find all functions with a method name of
+// // "clear" that are in any namespace that
+// // have no parameters
+// "::printf" // Find the printf function in the global namespace
+// "printf" // Ditto
+// "foo::*(int)" // Find all functions in the class or namespace "foo" that take a single integer argument
+//
+// Returns the number of tokens that were decoded, or zero when
+// we fail.
+//----------------------------------------------------------------------
+size_t
+Mangled::TokenList::Parse (const char *s)
+{
+ m_tokens.clear();
+
+ Token token;
+ token.type = eNameSpace;
+
+ TokenType max_type = eInvalid;
+ const char *p = s;
+ size_t span = 0;
+ size_t sep_size = 0;
+
+ while (*p != '\0')
+ {
+ p = p + span + sep_size;
+ while (isspace(*p))
+ ++p;
+
+ if (*p == '\0')
+ break;
+
+ span = strcspn(p, ":<>(),");
+ sep_size = 1;
+ token.type = eInvalid;
+ switch (p[span])
+ {
+ case '\0':
+ break;
+
+ case ':':
+ if (p[span+1] == ':')
+ {
+ sep_size = 2;
+ if (span > 0)
+ {
+ token.type = eNameSpace;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+ else
+ continue;
+ }
+ break;
+
+ case '(':
+ if (span > 0)
+ {
+ token.type = eMethodName;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+
+ token.type = eParamsBeg;
+ token.value.Clear();
+ m_tokens.push_back(token);
+ break;
+
+ case ',':
+ if (span > 0)
+ {
+ token.type = eType;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+ else
+ {
+ continue;
+ }
+ break;
+
+ case ')':
+ if (span > 0)
+ {
+ token.type = eType;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+
+ token.type = eParamsEnd;
+ token.value.Clear();
+ m_tokens.push_back(token);
+ break;
+
+ case '<':
+ if (span > 0)
+ {
+ token.type = eTemplate;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+
+ token.type = eTemplateBeg;
+ token.value.Clear();
+ m_tokens.push_back(token);
+ break;
+
+ case '>':
+ if (span > 0)
+ {
+ token.type = eType;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+
+ token.type = eTemplateEnd;
+ token.value.Clear();
+ m_tokens.push_back(token);
+ break;
+ }
+
+ if (max_type < token.type)
+ max_type = token.type;
+
+ if (token.type == eInvalid)
+ {
+ if (max_type >= eParamsEnd)
+ {
+ token.type = eQualifier;
+ token.value.SetCString(p);
+ m_tokens.push_back(token);
+ }
+ else if (max_type >= eParamsBeg)
+ {
+ token.type = eType;
+ token.value.SetCString(p);
+ m_tokens.push_back(token);
+ }
+ else
+ {
+ token.type = eMethodName;
+ token.value.SetCString(p);
+ m_tokens.push_back(token);
+ }
+ break;
+ }
+ }
+ return m_tokens.size();
+}
+
+
+//----------------------------------------------------------------------
+// Clear the token list.
+//----------------------------------------------------------------------
+void
+Mangled::TokenList::Clear ()
+{
+ m_tokens.clear();
+}
+
+//----------------------------------------------------------------------
+// Dump the token list to the stream "s"
+//----------------------------------------------------------------------
+void
+Mangled::TokenList::Dump (Stream *s) const
+{
+ collection::const_iterator pos;
+ collection::const_iterator beg = m_tokens.begin();
+ collection::const_iterator end = m_tokens.end();
+ for (pos = beg; pos != end; ++pos)
+ {
+ s->Indent("token[");
+ *s << (uint32_t)std::distance(beg, pos) << "] = " << *pos << "\n";
+ }
+}
+
+//----------------------------------------------------------------------
+// Find the first token in the list that has "token_type" as its
+// type
+//----------------------------------------------------------------------
+const Mangled::Token *
+Mangled::TokenList::Find (TokenType token_type) const
+{
+ collection::const_iterator pos;
+ collection::const_iterator beg = m_tokens.begin();
+ collection::const_iterator end = m_tokens.end();
+ for (pos = beg; pos != end; ++pos)
+ {
+ if (pos->type == token_type)
+ return &(*pos);
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Return the token at index "idx", or NULL if the index is
+// out of range.
+//----------------------------------------------------------------------
+const Mangled::Token *
+Mangled::TokenList::GetTokenAtIndex (uint32_t idx) const
+{
+ if (idx < m_tokens.size())
+ return &m_tokens[idx];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Given a token list, see if it matches this object's tokens.
+// "token_list" can contain wild card values to enable powerful
+// matching. Matching the std::string::erase(*) example that was
+// tokenized above we could use a token list such as:
+//
+// token name
+// ----------- ----------------------------------------
+// eNameSpace "std"
+// eTemplate "basic_string"
+// eTemplateBeg
+// eInvalid "*"
+// eTemplateEnd
+// eMethodName "erase"
+// eParamsBeg
+// eInvalid "*"
+// eParamsEnd
+//
+// Returns true if it "token_list" matches this object's tokens,
+// false otherwise.
+//----------------------------------------------------------------------
+bool
+Mangled::TokenList::MatchesQuery (const Mangled::TokenList &match) const
+{
+ size_t match_count = 0;
+ collection::const_iterator pos;
+ collection::const_iterator pos_end = m_tokens.end();
+
+ collection::const_iterator match_pos;
+ collection::const_iterator match_pos_end = match.m_tokens.end();
+ collection::const_iterator match_wildcard_pos = match_pos_end;
+ collection::const_iterator match_next_pos = match_pos_end;
+
+ size_t template_scope_depth = 0;
+
+ for (pos = m_tokens.begin(), match_pos = match.m_tokens.begin();
+ pos != pos_end && match_pos != match_pos_end;
+ ++match_pos)
+ {
+ match_next_pos = match_pos + 1;
+ // Is this a wildcard?
+ if (match_pos->IsWildcard())
+ {
+ if (match_wildcard_pos != match_pos_end)
+ return false; // Can't have two wildcards in effect at once.
+
+ match_wildcard_pos = match_pos;
+ // Are we at the end of the MATCH token list?
+ if (match_next_pos == match_pos_end)
+ {
+ // There is nothing more to match, return if we have any matches so far...
+ return match_count > 0;
+ }
+ }
+
+ if (match_pos->type == eInvalid || match_pos->type == eError)
+ {
+ return false;
+ }
+ else
+ {
+ if (match_pos->type == eTemplateBeg)
+ {
+ ++template_scope_depth;
+ }
+ else if (match_pos->type == eTemplateEnd)
+ {
+ assert(template_scope_depth > 0);
+ --template_scope_depth;
+ }
+
+ // Do we have a wildcard going right now?
+ if (match_wildcard_pos == match_pos_end)
+ {
+ // No wildcard matching right now, just check and see if things match
+ if (*pos == *match_pos)
+ ++match_count;
+ else
+ return false;
+ }
+ else
+ {
+ // We have a wildcard match going
+
+ // For template types we need to make sure to match the template depths...
+ const size_t start_wildcard_template_scope_depth = template_scope_depth;
+ size_t curr_wildcard_template_scope_depth = template_scope_depth;
+ while (pos != pos_end)
+ {
+ if (match_wildcard_pos->type == eNameSpace && pos->type == eParamsBeg)
+ return false;
+
+ if (start_wildcard_template_scope_depth == curr_wildcard_template_scope_depth)
+ {
+ if (*pos == *match_next_pos)
+ {
+ ++match_count;
+ match_pos = match_next_pos;
+ match_wildcard_pos = match_pos_end;
+ break;
+ }
+ }
+ if (pos->type == eTemplateBeg)
+ ++curr_wildcard_template_scope_depth;
+ else if (pos->type == eTemplateEnd)
+ --curr_wildcard_template_scope_depth;
+
+
+ ++pos;
+ }
+ }
+ }
+
+ if (pos != pos_end)
+ ++pos;
+ }
+ if (match_pos != match_pos_end)
+ return false;
+
+ return match_count > 0;
+}
+
+
+//----------------------------------------------------------------------
+// Return the number of tokens in the token collection
+//----------------------------------------------------------------------
+size_t
+Mangled::TokenList::Size () const
+{
+ return m_tokens.size();
+}
+
+
+//----------------------------------------------------------------------
+// Stream out the tokens
+//----------------------------------------------------------------------
+Stream&
+lldb_private::operator << (Stream& s, const Mangled::TokenList& obj)
+{
+ obj.Dump(&s);
+ return s;
+}
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
new file mode 100644
index 00000000000..c8e7d2f2c42
--- /dev/null
+++ b/lldb/source/Core/Module.cpp
@@ -0,0 +1,515 @@
+//===-- 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/Core/Module.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Module::Module(const FileSpec& file_spec, const ArchSpec& arch, const ConstString *object_name, off_t object_offset) :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_mod_time (file_spec.GetModificationTime()),
+ m_arch (arch),
+ m_uuid (),
+ m_file (file_spec),
+ m_flags (),
+ m_object_name (),
+ m_objfile_ap (),
+ m_symfile_ap ()
+{
+ if (object_name)
+ m_object_name = *object_name;
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Module::Module((%s) '%s/%s%s%s%s')",
+ this,
+ m_arch.AsCString(),
+ m_file.GetDirectory().AsCString(""),
+ m_file.GetFilename().AsCString(""),
+ m_object_name.IsEmpty() ? "" : "(",
+ m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
+ m_object_name.IsEmpty() ? "" : ")");
+
+}
+
+Module::~Module()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Module::~Module((%s) '%s/%s%s%s%s')",
+ this,
+ m_arch.AsCString(),
+ m_file.GetDirectory().AsCString(""),
+ m_file.GetFilename().AsCString(""),
+ m_object_name.IsEmpty() ? "" : "(",
+ m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
+ m_object_name.IsEmpty() ? "" : ")");
+}
+
+
+ModuleSP
+Module::GetSP ()
+{
+ return ModuleList::GetModuleSP (this);
+}
+
+const UUID&
+Module::GetUUID()
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_flags.IsClear(flagsParsedUUID))
+ {
+ ObjectFile * obj_file = GetObjectFile ();
+
+ if (obj_file != NULL)
+ {
+ obj_file->GetUUID(&m_uuid);
+ m_flags.Set(flagsParsedUUID);
+ }
+ }
+ return m_uuid;
+}
+
+void
+Module::ParseAllDebugSymbols()
+{
+ Mutex::Locker locker (m_mutex);
+ uint32_t num_comp_units = GetNumCompileUnits();
+ if (num_comp_units == 0)
+ return;
+
+ TargetSP null_target;
+ SymbolContext sc(null_target, GetSP());
+ uint32_t cu_idx;
+ SymbolVendor *symbols = GetSymbolVendor ();
+
+ for (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);
+
+ uint32_t func_idx;
+ for (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 = GetSP();
+}
+
+void
+Module::DumpSymbolContext(Stream *s)
+{
+ s->Printf(", Module{0x%8.8x}", this);
+}
+
+uint32_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 (uint32_t index)
+{
+ Mutex::Locker locker (m_mutex);
+ uint32_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;
+}
+
+//CompUnitSP
+//Module::FindCompUnit(lldb::user_id_t uid)
+//{
+// CompUnitSP cu_sp;
+// SymbolVendor *symbols = GetSymbolVendor ();
+// if (symbols)
+// cu_sp = symbols->FindCompUnit(uid);
+// 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%llx)", vm_addr);
+ ObjectFile* ofile = GetObjectFile();
+ if (ofile)
+ return so_addr.ResolveAddressUsingFileSections(vm_addr, ofile->GetSectionList());
+ 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
+ sc.Clear();
+
+ // Get the section from the section/offset address.
+ const Section *section = so_addr.GetSection();
+
+ // Make sure the section matches this module before we try and match anything
+ if (section && section->GetModule() == this)
+ {
+ // If the section offset based address resolved itself, then this
+ // is the right module.
+ sc.module_sp = GetSP();
+ 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
+ if (resolve_scope & eSymbolContextSymbol)
+ {
+ ObjectFile* ofile = GetObjectFile();
+ if (ofile)
+ {
+ Symtab *symtab = ofile->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);
+ 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%s%s:%u, check_inlines = %s, resolve_scope = 0x%8.8x)",
+ file_spec.GetDirectory().AsCString(""),
+ file_spec.GetDirectory() ? "/" : "",
+ file_spec.GetFilename().AsCString(""),
+ 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;
+}
+
+
+uint32_t
+Module::FindGlobalVariables(const ConstString &name, bool append, uint32_t max_matches, VariableList& variables)
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindGlobalVariables(name, append, max_matches, variables);
+ return 0;
+}
+uint32_t
+Module::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindGlobalVariables(regex, append, max_matches, variables);
+ return 0;
+}
+
+uint32_t
+Module::FindFunctions(const ConstString &name, bool append, SymbolContextList& sc_list)
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindFunctions(name, append, sc_list);
+ return 0;
+}
+
+uint32_t
+Module::FindFunctions(const RegularExpression& regex, bool append, SymbolContextList& sc_list)
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindFunctions(regex, append, sc_list);
+ return 0;
+}
+
+//uint32_t
+//Module::FindTypes(const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, const char *udt_name, TypeList& types)
+//{
+// Timer scoped_timer(__PRETTY_FUNCTION__);
+// SymbolVendor *symbols = GetSymbolVendor ();
+// if (symbols)
+// return symbols->FindTypes(sc, name, append, max_matches, encoding, udt_name, types);
+// return 0;
+//}
+//
+//uint32_t
+//Module::FindTypes(const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, const char *udt_name, TypeList& types)
+//{
+// Timer scoped_timer(__PRETTY_FUNCTION__);
+// SymbolVendor *symbols = GetSymbolVendor ();
+// if (symbols)
+// return symbols->FindTypes(sc, regex, append, max_matches, encoding, udt_name, types);
+// return 0;
+//
+//}
+
+SymbolVendor*
+Module::GetSymbolVendor (bool can_create)
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_flags.IsClear(flagsSearchedForSymVendor) && can_create)
+ {
+ ObjectFile *obj_file = GetObjectFile ();
+ if (obj_file != NULL)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+ m_symfile_ap.reset(SymbolVendor::FindPlugin(this));
+ m_flags.Set (flagsSearchedForSymVendor);
+ }
+ }
+ return m_symfile_ap.get();
+}
+
+const FileSpec &
+Module::GetFileSpec () const
+{
+ return m_file;
+}
+
+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;
+}
+
+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%s\n",
+ m_file.GetDirectory().AsCString(),
+ m_file.GetFilename().AsCString(),
+ 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_flags.IsClear(flagsSearchedForObjParser))
+ {
+ m_flags.Set (flagsSearchedForObjParser);
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::GetObjectFile () module = %s", GetFileSpec().GetFilename().AsCString(""));
+ m_objfile_ap.reset(ObjectFile::FindPlugin(this, &m_file, 0, m_file.GetByteSize()));
+ }
+ return m_objfile_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);
+ ObjectFile *objfile = GetObjectFile();
+ if (objfile)
+ {
+ Symtab *symtab = objfile->GetSymtab();
+ if (symtab)
+ return symtab->FindFirstSymbolWithNameAndType (name, symbol_type);
+ }
+ 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::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();
+ ObjectFile *objfile = GetObjectFile ();
+ if (objfile)
+ {
+ Symtab *symtab = objfile->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();
+ ObjectFile *objfile = GetObjectFile ();
+ if (objfile)
+ {
+ Symtab *symtab = objfile->GetSymtab();
+ if (symtab)
+ {
+ std::vector<uint32_t> symbol_indexes;
+ symtab->FindAllSymbolsMatchingRexExAndType (regex, symbol_type, symbol_indexes);
+ SymbolIndicesToSymbolContextList (symtab, symbol_indexes, sc_list);
+ }
+ }
+ return sc_list.GetSize() - initial_size;
+}
+
+const TimeValue &
+Module::GetModificationTime () const
+{
+ return m_mod_time;
+}
diff --git a/lldb/source/Core/ModuleChild.cpp b/lldb/source/Core/ModuleChild.cpp
new file mode 100644
index 00000000000..f38fb4f6c36
--- /dev/null
+++ b/lldb/source/Core/ModuleChild.cpp
@@ -0,0 +1,52 @@
+//===-- 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 (Module* module) :
+ m_module(module)
+{
+}
+
+ModuleChild::ModuleChild (const ModuleChild& rhs) :
+ m_module(rhs.m_module)
+{
+}
+
+ModuleChild::~ModuleChild()
+{
+}
+
+const ModuleChild&
+ModuleChild::operator= (const ModuleChild& rhs)
+{
+ if (this != &rhs)
+ m_module = rhs.m_module;
+ return *this;
+}
+
+Module *
+ModuleChild::GetModule ()
+{
+ return m_module;
+}
+
+Module *
+ModuleChild::GetModule () const
+{
+ return m_module;
+}
+
+void
+ModuleChild::SetModule (Module *module)
+{
+ m_module = module;
+}
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
new file mode 100644
index 00000000000..ae6e27b1dd2
--- /dev/null
+++ b/lldb/source/Core/ModuleList.cpp
@@ -0,0 +1,626 @@
+//===-- 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/Module.h"
+#include "lldb/Host/Symbols.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)
+{
+}
+
+//----------------------------------------------------------------------
+// Copy constructor
+//----------------------------------------------------------------------
+ModuleList::ModuleList(const ModuleList& rhs) :
+ m_modules(rhs.m_modules)
+{
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const ModuleList&
+ModuleList::operator= (const ModuleList& rhs)
+{
+ if (this != &rhs)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ m_modules = rhs.m_modules;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ModuleList::~ModuleList()
+{
+}
+
+void
+ModuleList::Append (ModuleSP &module_sp)
+{
+ Mutex::Locker locker(m_modules_mutex);
+ m_modules.push_back(module_sp);
+}
+
+bool
+ModuleList::AppendInNeeded (ModuleSP &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.
+ m_modules.push_back(module_sp);
+ return true;
+}
+
+bool
+ModuleList::Remove (ModuleSP &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);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+void
+ModuleList::Clear()
+{
+ Mutex::Locker locker(m_modules_mutex);
+ m_modules.clear();
+}
+
+Module*
+ModuleList::GetModulePointerAtIndex (uint32_t idx) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ if (idx < m_modules.size())
+ return m_modules[idx].get();
+ return NULL;
+}
+
+ModuleSP
+ModuleList::GetModuleAtIndex(uint32_t idx)
+{
+ Mutex::Locker locker(m_modules_mutex);
+ ModuleSP module_sp;
+ if (idx < m_modules.size())
+ module_sp = m_modules[idx];
+ return module_sp;
+}
+
+size_t
+ModuleList::FindFunctions (const ConstString &name, SymbolContextList &sc_list)
+{
+ 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)->FindFunctions (name, true, sc_list);
+ }
+ return sc_list.GetSize();
+}
+
+uint32_t
+ModuleList::FindGlobalVariables (const ConstString &name, bool append, uint32_t max_matches, VariableList& variable_list)
+{
+ size_t initial_size = variable_list.GetSize();
+ Mutex::Locker locker(m_modules_mutex);
+ collection::iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindGlobalVariables (name, append, max_matches, variable_list);
+ }
+ return variable_list.GetSize() - initial_size;
+}
+
+
+uint32_t
+ModuleList::FindGlobalVariables (const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variable_list)
+{
+ size_t initial_size = variable_list.GetSize();
+ Mutex::Locker locker(m_modules_mutex);
+ collection::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)
+{
+ Mutex::Locker locker(m_modules_mutex);
+ sc_list.Clear();
+ collection::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();
+}
+
+class ModuleMatches
+{
+public:
+ //--------------------------------------------------------------
+ /// Construct with the user ID to look for.
+ //--------------------------------------------------------------
+ ModuleMatches (const FileSpec *file_spec_ptr,
+ const ArchSpec *arch_ptr,
+ const UUID *uuid_ptr,
+ const ConstString *object_name) :
+ m_file_spec_ptr (file_spec_ptr),
+ m_arch_ptr (arch_ptr),
+ m_uuid_ptr (uuid_ptr),
+ m_object_name (object_name)
+ {
+ }
+
+ //--------------------------------------------------------------
+ /// Unary predicate function object callback.
+ //--------------------------------------------------------------
+ bool
+ operator () (const ModuleSP& module_sp) const
+ {
+ if (m_file_spec_ptr)
+ {
+ if (!FileSpec::Equal (*m_file_spec_ptr, module_sp->GetFileSpec(), m_file_spec_ptr->GetDirectory()))
+ return false;
+ }
+
+ if (m_arch_ptr)
+ {
+ if (module_sp->GetArchitecture() != *m_arch_ptr)
+ return false;
+ }
+
+ if (m_uuid_ptr)
+ {
+ if (module_sp->GetUUID() != *m_uuid_ptr)
+ return false;
+ }
+
+ if (m_object_name)
+ {
+ if (module_sp->GetObjectName() != *m_object_name)
+ return false;
+ }
+ return true;
+ }
+
+private:
+ //--------------------------------------------------------------
+ // Member variables.
+ //--------------------------------------------------------------
+ const FileSpec * m_file_spec_ptr;
+ const ArchSpec * m_arch_ptr;
+ const UUID * m_uuid_ptr;
+ const ConstString * m_object_name;
+};
+
+size_t
+ModuleList::FindModules
+(
+ const FileSpec *file_spec_ptr,
+ const ArchSpec *arch_ptr,
+ const UUID *uuid_ptr,
+ const ConstString *object_name,
+ ModuleList& matching_module_list
+) const
+{
+ size_t existing_matches = matching_module_list.GetSize();
+ ModuleMatches matcher (file_spec_ptr, arch_ptr, uuid_ptr, object_name);
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator end = m_modules.end();
+ collection::const_iterator pos;
+
+ for (pos = std::find_if (m_modules.begin(), end, matcher);
+ pos != end;
+ pos = std::find_if (++pos, end, matcher))
+ {
+ ModuleSP module_sp(*pos);
+ matching_module_list.Append(module_sp);
+ }
+ return matching_module_list.GetSize() - existing_matches;
+}
+
+ModuleSP
+ModuleList::FindModule (lldb_private::Module *module_ptr)
+{
+ 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::FindFirstModuleForFileSpec (const FileSpec &file_spec, const ConstString *object_name)
+{
+ ModuleSP module_sp;
+ ModuleMatches matcher (&file_spec, NULL, NULL, NULL);
+
+ // Scope for "locker"
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator end = m_modules.end();
+ collection::const_iterator pos = m_modules.begin();
+
+ pos = std::find_if (pos, end, matcher);
+ if (pos != end)
+ module_sp = (*pos);
+ }
+ 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);
+ }
+}
+
+
+bool
+ModuleList::ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr)
+{
+ 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)
+{
+ // The address is already section offset so it has a module
+ uint32_t resolved_flags = 0;
+ Module *module = so_addr.GetModule();
+ if (module)
+ {
+ resolved_flags = module->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)
+{
+ FileSpec file_spec(file_path);
+ 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)
+{
+ 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();
+}
+
+uint32_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 ()
+{
+ static ModuleList g_shared_module_list;
+ return g_shared_module_list;
+}
+
+const lldb::ModuleSP
+ModuleList::GetModuleSP (lldb_private::Module *module_ptr)
+{
+ lldb::ModuleSP module_sp;
+ if (module_ptr)
+ {
+ ModuleList &shared_module_list = GetSharedModuleList ();
+ module_sp = shared_module_list.FindModule (module_ptr);
+ assert (module_sp.get()); // This might fire off a few times and we need to make sure it never fires...
+ }
+ return module_sp;
+}
+
+
+Error
+ModuleList::GetSharedModule
+(
+ const FileSpec& in_file_spec,
+ const ArchSpec& arch,
+ const UUID *uuid_ptr,
+ const ConstString *object_name_ptr,
+ off_t object_offset,
+ ModuleSP &module_sp,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr
+)
+{
+ ModuleList &shared_module_list = GetSharedModuleList ();
+ char path[PATH_MAX];
+ char uuid_cstr[64];
+
+ Error error;
+
+ module_sp.reset();
+
+ if (did_create_ptr)
+ *did_create_ptr = false;
+ if (old_module_sp_ptr)
+ old_module_sp_ptr->reset();
+
+
+ // First just try and get the file where it purports to be (path in
+ // in_file_spec), then check and uuid.
+
+ if (in_file_spec)
+ {
+ // 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.
+ ModuleList matching_module_list;
+ Mutex::Locker locker(shared_module_list.m_modules_mutex);
+ if (shared_module_list.FindModules (&in_file_spec, &arch, uuid_ptr, object_name_ptr, 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 (uuid_ptr == NULL)
+ {
+ TimeValue file_spec_mod_time(in_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 (in_file_spec, arch, object_name_ptr, object_offset));
+ if (module_sp)
+ {
+ // 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.Append(module_sp);
+ return error;
+ }
+ }
+ }
+ }
+
+ // 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 (&in_file_spec, arch.IsValid() ? &arch : NULL, uuid_ptr);
+
+ // Don't look for the file if it appears to be the same one we already
+ // checked for above...
+ if (file_spec != in_file_spec)
+ {
+ if (!file_spec.Exists())
+ {
+ file_spec.GetPath(path, sizeof(path));
+ if (file_spec.Exists())
+ {
+ if (uuid_ptr && uuid_ptr->IsValid())
+ uuid_ptr->GetAsCString(uuid_cstr, sizeof (uuid_cstr));
+ else
+ uuid_cstr[0] = '\0';
+
+
+ if (arch.IsValid())
+ {
+ if (uuid_cstr[0])
+ error.SetErrorStringWithFormat("'%s' does not contain the %s architecture and UUID %s.\n", path, arch.AsCString(), uuid_cstr[0]);
+ else
+ error.SetErrorStringWithFormat("'%s' does not contain the %s architecture.\n", path, arch.AsCString());
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' does not exist.\n", path);
+ }
+ 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.
+ Mutex::Locker locker(shared_module_list.m_modules_mutex);
+ ModuleList matching_module_list;
+ if (shared_module_list.FindModules (&file_spec, &arch, uuid_ptr, object_name_ptr, 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 (uuid_ptr == 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 (file_spec, arch, object_name_ptr, object_offset));
+ if (module_sp)
+ {
+ if (did_create_ptr)
+ *did_create_ptr = true;
+
+ shared_module_list.Append(module_sp);
+ }
+ else
+ {
+ file_spec.GetPath(path, sizeof(path));
+
+ if (file_spec)
+ {
+ if (arch.IsValid())
+ error.SetErrorStringWithFormat("Unable to open %s architecture in '%s'.\n", arch.AsCString(), path);
+ else
+ error.SetErrorStringWithFormat("Unable to open '%s'.\n", path);
+ }
+ else
+ {
+ if (uuid_ptr && uuid_ptr->IsValid())
+ uuid_ptr->GetAsCString(uuid_cstr, sizeof (uuid_cstr));
+ else
+ uuid_cstr[0] = '\0';
+
+ if (uuid_cstr[0])
+ error.SetErrorStringWithFormat("Cannot locate a module for UUID '%s'.\n", uuid_cstr[0]);
+ else
+ error.SetErrorStringWithFormat("Cannot locate a module.\n", path, arch.AsCString());
+ }
+ }
+ }
+ }
+
+ return error;
+}
+
diff --git a/lldb/source/Core/Options.cpp b/lldb/source/Core/Options.cpp
new file mode 100644
index 00000000000..35a9fa40e1b
--- /dev/null
+++ b/lldb/source/Core/Options.cpp
@@ -0,0 +1,700 @@
+//===-- Options.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/Options.h"
+
+// C Includes
+// C++ Includes
+#include <bitset>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// Options
+//-------------------------------------------------------------------------
+Options::Options () :
+ m_getopt_table ()
+{
+}
+
+Options::~Options ()
+{
+}
+
+
+void
+Options::ResetOptionValues ()
+{
+ m_seen_options.clear();
+}
+
+void
+Options::OptionSeen (int option_idx)
+{
+ m_seen_options.insert ((char) option_idx);
+}
+
+// Returns true is set_a is a subset of set_b; Otherwise returns false.
+
+bool
+Options::IsASubset (const OptionSet& set_a, const OptionSet& set_b)
+{
+ bool is_a_subset = true;
+ OptionSet::const_iterator pos_a;
+ OptionSet::const_iterator pos_b;
+
+ // set_a is a subset of set_b if every member of set_a is also a member of set_b
+
+ for (pos_a = set_a.begin(); pos_a != set_a.end() && is_a_subset; ++pos_a)
+ {
+ pos_b = set_b.find(*pos_a);
+ if (pos_b == set_b.end())
+ is_a_subset = false;
+ }
+
+ return is_a_subset;
+}
+
+// Returns the set difference set_a - set_b, i.e. { x | ElementOf (x, set_a) && !ElementOf (x, set_b) }
+
+size_t
+Options::OptionsSetDiff (const OptionSet& set_a, const OptionSet& set_b, OptionSet& diffs)
+{
+ size_t num_diffs = 0;
+ OptionSet::const_iterator pos_a;
+ OptionSet::const_iterator pos_b;
+
+ for (pos_a = set_a.begin(); pos_a != set_a.end(); ++pos_a)
+ {
+ pos_b = set_b.find(*pos_a);
+ if (pos_b == set_b.end())
+ {
+ ++num_diffs;
+ diffs.insert(*pos_a);
+ }
+ }
+
+ return num_diffs;
+}
+
+// Returns the union of set_a and set_b. Does not put duplicate members into the union.
+
+void
+Options::OptionsSetUnion (const OptionSet &set_a, const OptionSet &set_b, OptionSet &union_set)
+{
+ OptionSet::const_iterator pos;
+ OptionSet::iterator pos_union;
+
+ // Put all the elements of set_a into the union.
+
+ for (pos = set_a.begin(); pos != set_a.end(); ++pos)
+ union_set.insert(*pos);
+
+ // Put all the elements of set_b that are not already there into the union.
+ for (pos = set_b.begin(); pos != set_b.end(); ++pos)
+ {
+ pos_union = union_set.find(*pos);
+ if (pos_union == union_set.end())
+ union_set.insert(*pos);
+ }
+}
+
+bool
+Options::VerifyOptions (CommandReturnObject &result)
+{
+ bool options_are_valid = false;
+
+ int num_levels = m_required_options.size();
+ if (num_levels)
+ {
+ for (int i = 0; i < num_levels && !options_are_valid; ++i)
+ {
+ // This is the correct set of options if: 1). m_seen_options contains all of m_required_options[i]
+ // (i.e. all the required options at this level are a subset of m_seen_options); AND
+ // 2). { m_seen_options - m_required_options[i] is a subset of m_options_options[i] (i.e. all the rest of
+ // m_seen_options are in the set of optional options at this level.
+
+ // Check to see if all of m_required_options[i] are a subset of m_seen_options
+ if (IsASubset (m_required_options[i], m_seen_options))
+ {
+ // Construct the set difference: remaining_options = {m_seen_options} - {m_required_options[i]}
+ OptionSet remaining_options;
+ OptionsSetDiff (m_seen_options, m_required_options[i], remaining_options);
+ // Check to see if remaining_options is a subset of m_optional_options[i]
+ if (IsASubset (remaining_options, m_optional_options[i]))
+ options_are_valid = true;
+ }
+ }
+ }
+ else
+ {
+ options_are_valid = true;
+ }
+
+ if (options_are_valid)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("invalid combination of options for the given command");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return options_are_valid;
+}
+
+void
+Options::BuildValidOptionSets ()
+{
+ // Check to see if we already did this.
+ if (m_required_options.size() != 0)
+ return;
+
+ // Check to see if there are any options.
+ int num_options = NumCommandOptions ();
+ if (num_options == 0)
+ return;
+
+ const lldb::OptionDefinition *full_options_table = GetDefinitions();
+ uint32_t usage_level = 0;
+ m_required_options.resize(1);
+ m_optional_options.resize(1);
+
+ for (int i = 0; i < num_options; ++i)
+ {
+ // NOTE: Assumption: The full options table is ordered with usage level growing monotonically.
+ assert (full_options_table[i].usage_level >= usage_level);
+
+ if (full_options_table[i].usage_level > usage_level)
+ {
+ // start a new level
+ usage_level = full_options_table[i].usage_level;
+ m_required_options.resize(m_required_options.size()+1);
+ m_optional_options.resize(m_optional_options.size()+1);
+ }
+ else
+ {
+ assert (m_required_options.empty() == false);
+ assert (m_optional_options.empty() == false);
+ }
+
+ if (full_options_table[i].required)
+ m_required_options.back().insert(full_options_table[i].short_option);
+ else
+ m_optional_options.back().insert(full_options_table[i].short_option);
+ }
+}
+
+uint32_t
+Options::NumCommandOptions ()
+{
+ const lldb::OptionDefinition *full_options_table = GetDefinitions ();
+ int i = 0;
+
+ if (full_options_table != NULL)
+ {
+ while (full_options_table[i].long_option != NULL)
+ ++i;
+ }
+
+ return i;
+}
+
+struct option *
+Options::GetLongOptions ()
+{
+ // Check to see if this has already been done.
+ if (m_getopt_table.empty())
+ {
+ // Check to see if there are any options.
+ const uint32_t num_options = NumCommandOptions();
+ if (num_options == 0)
+ return NULL;
+
+ uint32_t i;
+ uint32_t j;
+ const lldb::OptionDefinition *full_options_table = GetDefinitions();
+
+ std::bitset<256> option_seen;
+
+ m_getopt_table.resize(num_options + 1);
+ for (i = 0, j = 0; i < num_options; ++i)
+ {
+ char short_opt = full_options_table[i].short_option;
+
+ if (option_seen.test(short_opt) == false)
+ {
+ m_getopt_table[j].name = full_options_table[i].long_option;
+ m_getopt_table[j].has_arg = full_options_table[i].option_has_arg;
+ m_getopt_table[j].flag = NULL;
+ m_getopt_table[j].val = full_options_table[i].short_option;
+ option_seen.set(short_opt);
+ ++j;
+ }
+ }
+
+ //getopt_long requires a NULL final entry in the table:
+
+ m_getopt_table[j].name = NULL;
+ m_getopt_table[j].has_arg = 0;
+ m_getopt_table[j].flag = NULL;
+ m_getopt_table[j].val = 0;
+ }
+
+ return m_getopt_table.data();
+}
+
+
+// This function takes INDENT, which tells how many spaces to output at the front of each line; SPACES, which is
+// a string containing 80 spaces; and TEXT, which is the text that is to be output. It outputs the text, on
+// multiple lines if necessary, to RESULT, with INDENT spaces at the front of each line. It breaks lines on spaces,
+// tabs or newlines, shortening the line if necessary to not break in the middle of a word. It assumes that each
+// output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
+
+
+void
+Options::OutputFormattedUsageText
+(
+ Stream &strm,
+ const char *text,
+ uint32_t output_max_columns
+)
+{
+ int len = strlen (text);
+
+ // Will it all fit on one line?
+
+ if ((len + strm.GetIndentLevel()) < output_max_columns)
+ {
+ // Output it as a single line.
+ strm.Indent (text);
+ strm.EOL();
+ }
+ else
+ {
+ // We need to break it up into multiple lines.
+
+ int text_width = output_max_columns - strm.GetIndentLevel() - 1;
+ int start = 0;
+ int end = start;
+ int final_end = strlen (text);
+ int sub_len;
+
+ while (end < final_end)
+ {
+ // Don't start the 'text' on a space, since we're already outputting the indentation.
+ while ((start < final_end) && (text[start] == ' '))
+ start++;
+
+ end = start + text_width;
+ if (end > final_end)
+ end = final_end;
+ else
+ {
+ // If we're not at the end of the text, make sure we break the line on white space.
+ while (end > start
+ && text[end] != ' ' && text[end] != '\t' && text[end] != '\n')
+ end--;
+ }
+
+ sub_len = end - start;
+ if (start != 0)
+ strm.EOL();
+ strm.Indent();
+ assert (start < final_end);
+ assert (start + sub_len <= final_end);
+ strm.Write(text + start, sub_len);
+ start = end + 1;
+ }
+ strm.EOL();
+ }
+}
+
+void
+Options::GenerateOptionUsage
+(
+ Stream &strm,
+ CommandObject *cmd,
+ const char *program_name)
+{
+ uint32_t screen_width = 80;
+ const lldb::OptionDefinition *full_options_table = GetDefinitions();
+ const uint32_t save_indent_level = strm.GetIndentLevel();
+ const char *name;
+
+ if (cmd)
+ name = cmd->GetCommandName();
+ else
+ name = program_name;
+
+ strm.PutCString ("\nCommand Options Usage:\n");
+
+ strm.IndentMore(2);
+
+ // First, show each usage level set of options, e.g. <cmd> [options-for-level-0]
+ // <cmd> [options-for-level-1]
+ // etc.
+
+ uint32_t usage_level = 0;
+ const uint32_t num_options = NumCommandOptions();
+ uint32_t i;
+ for (i = 0; i < num_options; ++i)
+ {
+ if (i==0 || full_options_table[i].usage_level > usage_level)
+ {
+ // start a new level
+ usage_level = full_options_table[i].usage_level;
+ if (usage_level > 0)
+ {
+ strm.Printf ("\n");
+ }
+ strm.Indent (name);
+ }
+
+ // Add current option to the end of out_stream.
+
+ if (full_options_table[i].required)
+ {
+ if (full_options_table[i].option_has_arg == required_argument)
+ {
+ strm.Printf (" -%c %s",
+ full_options_table[i].short_option,
+ full_options_table[i].argument_name);
+ }
+ else if (full_options_table[i].option_has_arg == optional_argument)
+ {
+ strm.Printf (" -%c [%s]",
+ full_options_table[i].short_option,
+ full_options_table[i].argument_name);
+ }
+ else
+ strm.Printf (" -%c", full_options_table[i].short_option);
+ }
+ else
+ {
+ if (full_options_table[i].option_has_arg == required_argument)
+ strm.Printf (" [-%c %s]", full_options_table[i].short_option,
+ full_options_table[i].argument_name);
+ else if (full_options_table[i].option_has_arg == optional_argument)
+ strm.Printf (" [-%c [%s]]", full_options_table[i].short_option,
+ full_options_table[i].argument_name);
+ else
+ strm.Printf (" [-%c]", full_options_table[i].short_option);
+ }
+ }
+
+ strm.Printf ("\n\n");
+
+ // Now print out all the detailed information about the various options: long form, short form and help text:
+ // -- long_name <argument>
+ // - short <argument>
+ // help text
+
+ // This variable is used to keep track of which options' info we've printed out, because some options can be in
+ // more than one usage level, but we only want to print the long form of its information once.
+
+ OptionSet options_seen;
+ OptionSet::iterator pos;
+ strm.IndentMore (5);
+
+ int first_option_printed = 1;
+ for (i = 0; i < num_options; ++i)
+ {
+ // Only print out this option if we haven't already seen it.
+ pos = options_seen.find (full_options_table[i].short_option);
+ if (pos == options_seen.end())
+ {
+ // Put a newline separation between arguments
+ if (first_option_printed)
+ first_option_printed = 0;
+ else
+ strm.EOL();
+
+ options_seen.insert (full_options_table[i].short_option);
+ strm.Indent ();
+ strm.Printf ("-%c ", full_options_table[i].short_option);
+ if (full_options_table[i].argument_name != NULL)
+ strm.PutCString(full_options_table[i].argument_name);
+ strm.EOL();
+ strm.Indent ();
+ strm.Printf ("--%s ", full_options_table[i].long_option);
+ if (full_options_table[i].argument_name != NULL)
+ strm.PutCString(full_options_table[i].argument_name);
+ strm.EOL();
+
+ strm.IndentMore (5);
+
+ if (full_options_table[i].usage_text)
+ OutputFormattedUsageText (strm,
+ full_options_table[i].usage_text,
+ screen_width);
+ if (full_options_table[i].enum_values != NULL)
+ {
+ strm.Indent ();
+ strm.Printf("Values: ");
+ for (int j = 0; full_options_table[i].enum_values[j].string_value != NULL; j++)
+ {
+ if (j == 0)
+ strm.Printf("%s", full_options_table[i].enum_values[j].string_value);
+ else
+ strm.Printf(" | %s", full_options_table[i].enum_values[j].string_value);
+ }
+ strm.EOL();
+ }
+ strm.IndentLess (5);
+ }
+ }
+
+ // Restore the indent level
+ strm.SetIndentLevel (save_indent_level);
+}
+
+// This function is called when we have been given a potentially incomplete set of
+// options, such as when an alias has been defined (more options might be added at
+// at the time the alias is invoked). We need to verify that the options in the set
+// m_seen_options are all part of a set that may be used together, but m_seen_options
+// may be missing some of the "required" options.
+
+bool
+Options::VerifyPartialOptions (CommandReturnObject &result)
+{
+ bool options_are_valid = false;
+
+ int num_levels = m_required_options.size();
+ if (num_levels)
+ {
+ for (int i = 0; i < num_levels && !options_are_valid; ++i)
+ {
+ // In this case we are treating all options as optional rather than required.
+ // Therefore a set of options is correct if m_seen_options is a subset of the
+ // union of m_required_options and m_optional_options.
+ OptionSet union_set;
+ OptionsSetUnion (m_required_options[i], m_optional_options[i], union_set);
+ if (IsASubset (m_seen_options, union_set))
+ options_are_valid = true;
+ }
+ }
+
+ return options_are_valid;
+}
+
+bool
+Options::HandleOptionCompletion
+(
+ Args &input,
+ OptionElementVector &opt_element_vector,
+ int cursor_index,
+ int char_pos,
+ int match_start_point,
+ int max_return_elements,
+ lldb_private::CommandInterpreter *interpreter,
+ lldb_private::StringList &matches
+)
+{
+ // For now we just scan the completions to see if the cursor position is in
+ // an option or its argument. Otherwise we'll call HandleArgumentCompletion.
+ // In the future we can use completion to validate options as well if we want.
+
+ const OptionDefinition *opt_defs = GetDefinitions();
+
+ std::string cur_opt_std_str (input.GetArgumentAtIndex(cursor_index));
+ cur_opt_std_str.erase(char_pos);
+ const char *cur_opt_str = cur_opt_std_str.c_str();
+
+ for (int i = 0; i < opt_element_vector.size(); i++)
+ {
+ int opt_pos = opt_element_vector[i].opt_pos;
+ int opt_arg_pos = opt_element_vector[i].opt_arg_pos;
+ int opt_defs_index = opt_element_vector[i].opt_defs_index;
+ if (opt_pos == cursor_index)
+ {
+ // We're completing the option itself.
+ if (opt_defs_index != -1)
+ {
+ // We recognized it, if it an incomplete long option, complete it anyway (getopt_long is
+ // happy with shortest unique string, but it's still a nice thing to do.) Otherwise return
+ // The string so the upper level code will know this is a full match and add the " ".
+ if (cur_opt_str && strlen (cur_opt_str) > 2
+ && cur_opt_str[0] == '-' && cur_opt_str[1] == '-'
+ && strcmp (opt_defs[opt_defs_index].long_option, cur_opt_str) != 0)
+ {
+ std::string full_name ("--");
+ full_name.append (opt_defs[opt_defs_index].long_option);
+ matches.AppendString(full_name.c_str());
+ return true;
+ }
+ else
+ {
+ matches.AppendString(input.GetArgumentAtIndex(cursor_index));
+ return true;
+ }
+ }
+ else
+ {
+ // FIXME - not handling wrong options yet:
+ // Check to see if they are writing a long option & complete it.
+ // I think we will only get in here if the long option table has two elements
+ // that are not unique up to this point. getopt_long does shortest unique match
+ // for long options already.
+
+ if (cur_opt_str && strlen (cur_opt_str) > 2
+ && cur_opt_str[0] == '-' && cur_opt_str[1] == '-')
+ {
+ for (int i = 0 ; opt_defs[i].short_option != 0 ; i++)
+ {
+ if (strstr(opt_defs[i].long_option, cur_opt_str + 2) == opt_defs[i].long_option)
+ {
+ std::string full_name ("--");
+ full_name.append (opt_defs[i].long_option);
+ // The options definitions table has duplicates because of the
+ // way the grouping information is stored, so only add once.
+ bool duplicate = false;
+ for (int j = 0; j < matches.GetSize(); j++)
+ {
+ if (matches.GetStringAtIndex(j) == full_name)
+ {
+ duplicate = true;
+ break;
+ }
+ }
+ if (!duplicate)
+ matches.AppendString(full_name.c_str());
+ }
+ }
+ }
+ return true;
+ }
+
+
+ }
+ else if (opt_arg_pos == cursor_index)
+ {
+ // Okay the cursor is on the completion of an argument.
+ // See if it has a completion, otherwise return no matches.
+
+ if (opt_defs_index != -1)
+ {
+ HandleOptionArgumentCompletion (input,
+ cursor_index,
+ strlen (input.GetArgumentAtIndex(cursor_index)),
+ opt_element_vector,
+ i,
+ match_start_point,
+ max_return_elements,
+ interpreter,
+ matches);
+ return true;
+ }
+ else
+ {
+ // No completion callback means no completions...
+ return true;
+ }
+
+ }
+ else
+ {
+ // Not the last element, keep going.
+ continue;
+ }
+ }
+ return false;
+}
+
+bool
+Options::HandleOptionArgumentCompletion
+(
+ Args &input,
+ int cursor_index,
+ int char_pos,
+ OptionElementVector &opt_element_vector,
+ int opt_element_index,
+ int match_start_point,
+ int max_return_elements,
+ lldb_private::CommandInterpreter *interpreter,
+ lldb_private::StringList &matches
+)
+{
+ const OptionDefinition *opt_defs = GetDefinitions();
+ std::auto_ptr<SearchFilter> filter_ap;
+
+ int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
+ int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
+
+ // See if this is an enumeration type option, and if so complete it here:
+
+ OptionEnumValueElement *enum_values = opt_defs[opt_defs_index].enum_values;
+ if (enum_values != NULL)
+ {
+ bool return_value = false;
+ std::string match_string(input.GetArgumentAtIndex (opt_arg_pos), input.GetArgumentAtIndex (opt_arg_pos) + char_pos);
+ for (int i = 0; enum_values[i].string_value != NULL; i++)
+ {
+ if (strstr(enum_values[i].string_value, match_string.c_str()) == enum_values[i].string_value)
+ {
+ matches.AppendString (enum_values[i].string_value);
+ return_value = true;
+ }
+ }
+ return return_value;
+ }
+
+ // If this is a source file or symbol type completion, and there is a
+ // -shlib option somewhere in the supplied arguments, then make a search filter
+ // for that shared library.
+ // FIXME: Do we want to also have an "OptionType" so we don't have to match string names?
+
+ uint32_t completion_mask = opt_defs[opt_defs_index].completionType;
+ if (completion_mask & CommandCompletions::eSourceFileCompletion
+ || completion_mask & CommandCompletions::eSymbolCompletion)
+ {
+ for (int i = 0; i < opt_element_vector.size(); i++)
+ {
+ int cur_defs_index = opt_element_vector[i].opt_defs_index;
+ int cur_arg_pos = opt_element_vector[i].opt_arg_pos;
+ const char *cur_opt_name = opt_defs[cur_defs_index].long_option;
+
+ // If this is the "shlib" option and there was an argument provided,
+ // restrict it to that shared library.
+ if (strcmp(cur_opt_name, "shlib") == 0 && cur_arg_pos != -1)
+ {
+ const char *module_name = input.GetArgumentAtIndex(cur_arg_pos);
+ if (module_name)
+ {
+ FileSpec module_spec(module_name);
+ lldb::TargetSP target_sp = interpreter->Context()->GetTarget()->GetSP();
+ // Search filters require a target...
+ if (target_sp != NULL)
+ filter_ap.reset (new SearchFilterByModule (target_sp, module_spec));
+ }
+ break;
+ }
+ }
+ }
+
+ return CommandCompletions::InvokeCommonCompletionCallbacks (completion_mask,
+ input.GetArgumentAtIndex (opt_arg_pos),
+ match_start_point,
+ max_return_elements,
+ interpreter,
+ filter_ap.get(),
+ matches);
+
+}
diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp
new file mode 100644
index 00000000000..3723e7cf89a
--- /dev/null
+++ b/lldb/source/Core/PluginManager.cpp
@@ -0,0 +1,1133 @@
+//===-- 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/Core/PluginManager.h"
+
+#include <string>
+#include <vector>
+
+using namespace lldb_private;
+
+typedef enum PluginAction
+{
+ ePluginRegisterInstance,
+ ePluginUnregisterInstance,
+ ePluginGetInstanceAtIndex
+};
+
+
+#pragma mark ABI
+
+
+typedef struct ABIInstance
+{
+ ABIInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ ABICreateInstance create_callback;
+};
+
+typedef std::vector<ABIInstance> ABIInstances;
+
+static bool
+AccessABIInstances (PluginAction action, ABIInstance &instance, uint32_t index)
+{
+ static ABIInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ ABIInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+ (
+ const char *name,
+ const char *description,
+ ABICreateInstance create_callback
+ )
+{
+ if (create_callback)
+ {
+ ABIInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessABIInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ABICreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ ABIInstance instance;
+ instance.create_callback = create_callback;
+ return AccessABIInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+ABICreateInstance
+PluginManager::GetABICreateCallbackAtIndex (uint32_t idx)
+{
+ ABIInstance instance;
+ if (AccessABIInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+
+ABICreateInstance
+PluginManager::GetABICreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ ABIInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessABIInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+#pragma mark Disassembler
+
+
+typedef struct DisassemblerInstance
+{
+ DisassemblerInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ DisassemblerCreateInstance create_callback;
+};
+
+typedef std::vector<DisassemblerInstance> DisassemblerInstances;
+
+static bool
+AccessDisassemblerInstances (PluginAction action, DisassemblerInstance &instance, uint32_t index)
+{
+ static DisassemblerInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ DisassemblerInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ DisassemblerCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ DisassemblerInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessDisassemblerInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (DisassemblerCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ DisassemblerInstance instance;
+ instance.create_callback = create_callback;
+ return AccessDisassemblerInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+DisassemblerCreateInstance
+PluginManager::GetDisassemblerCreateCallbackAtIndex (uint32_t idx)
+{
+ DisassemblerInstance instance;
+ if (AccessDisassemblerInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+
+DisassemblerCreateInstance
+PluginManager::GetDisassemblerCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ DisassemblerInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessDisassemblerInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+#pragma mark DynamicLoader
+
+
+typedef struct DynamicLoaderInstance
+{
+ DynamicLoaderInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ DynamicLoaderCreateInstance create_callback;
+};
+
+typedef std::vector<DynamicLoaderInstance> DynamicLoaderInstances;
+
+static bool
+AccessDynamicLoaderInstances (PluginAction action, DynamicLoaderInstance &instance, uint32_t index)
+{
+ static DynamicLoaderInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ DynamicLoaderInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ DynamicLoaderCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ DynamicLoaderInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessDynamicLoaderInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (DynamicLoaderCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ DynamicLoaderInstance instance;
+ instance.create_callback = create_callback;
+ return AccessDynamicLoaderInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+DynamicLoaderCreateInstance
+PluginManager::GetDynamicLoaderCreateCallbackAtIndex (uint32_t idx)
+{
+ DynamicLoaderInstance instance;
+ if (AccessDynamicLoaderInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+
+DynamicLoaderCreateInstance
+PluginManager::GetDynamicLoaderCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ DynamicLoaderInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessDynamicLoaderInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+
+#pragma mark ObjectFile
+
+typedef struct ObjectFileInstance
+{
+ ObjectFileInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ ObjectFileCreateInstance create_callback;
+};
+
+typedef std::vector<ObjectFileInstance> ObjectFileInstances;
+
+static bool
+AccessObjectFileInstances (PluginAction action, ObjectFileInstance &instance, uint32_t index)
+{
+ static ObjectFileInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ ObjectFileInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ ObjectFileCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ ObjectFileInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessObjectFileInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ObjectFileCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ ObjectFileInstance instance;
+ instance.create_callback = create_callback;
+ return AccessObjectFileInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+ObjectFileCreateInstance
+PluginManager::GetObjectFileCreateCallbackAtIndex (uint32_t idx)
+{
+ ObjectFileInstance instance;
+ if (AccessObjectFileInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+ObjectFileCreateInstance
+PluginManager::GetObjectFileCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ ObjectFileInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessObjectFileInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+#pragma mark ObjectContainer
+
+typedef struct ObjectContainerInstance
+{
+ ObjectContainerInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ ObjectContainerCreateInstance create_callback;
+};
+
+typedef std::vector<ObjectContainerInstance> ObjectContainerInstances;
+
+static bool
+AccessObjectContainerInstances (PluginAction action, ObjectContainerInstance &instance, uint32_t index)
+{
+ static ObjectContainerInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ ObjectContainerInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ ObjectContainerCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ ObjectContainerInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessObjectContainerInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ObjectContainerCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ ObjectContainerInstance instance;
+ instance.create_callback = create_callback;
+ return AccessObjectContainerInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+ObjectContainerCreateInstance
+PluginManager::GetObjectContainerCreateCallbackAtIndex (uint32_t idx)
+{
+ ObjectContainerInstance instance;
+ if (AccessObjectContainerInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+ObjectContainerCreateInstance
+PluginManager::GetObjectContainerCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ ObjectContainerInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessObjectContainerInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark LogChannel
+
+typedef struct LogChannelInstance
+{
+ LogChannelInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ LogChannelCreateInstance create_callback;
+};
+
+typedef std::vector<LogChannelInstance> LogChannelInstances;
+
+static bool
+AccessLogChannelInstances (PluginAction action, LogChannelInstance &instance, uint32_t index)
+{
+ static LogChannelInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ LogChannelInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ LogChannelCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ LogChannelInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessLogChannelInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (LogChannelCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ LogChannelInstance instance;
+ instance.create_callback = create_callback;
+ return AccessLogChannelInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+const char *
+PluginManager::GetLogChannelCreateNameAtIndex (uint32_t idx)
+{
+ LogChannelInstance instance;
+ if (AccessLogChannelInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.name.c_str();
+ return NULL;
+}
+
+
+LogChannelCreateInstance
+PluginManager::GetLogChannelCreateCallbackAtIndex (uint32_t idx)
+{
+ LogChannelInstance instance;
+ if (AccessLogChannelInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+
+LogChannelCreateInstance
+PluginManager::GetLogChannelCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ LogChannelInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessLogChannelInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark Process
+
+typedef struct ProcessInstance
+{
+ ProcessInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ ProcessCreateInstance create_callback;
+};
+
+typedef std::vector<ProcessInstance> ProcessInstances;
+
+static bool
+AccessProcessInstances (PluginAction action, ProcessInstance &instance, uint32_t index)
+{
+ static ProcessInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ ProcessInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ ProcessCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ ProcessInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessProcessInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ProcessCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ ProcessInstance instance;
+ instance.create_callback = create_callback;
+ return AccessProcessInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+ProcessCreateInstance
+PluginManager::GetProcessCreateCallbackAtIndex (uint32_t idx)
+{
+ ProcessInstance instance;
+ if (AccessProcessInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+
+ProcessCreateInstance
+PluginManager::GetProcessCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ ProcessInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessProcessInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark SymbolFile
+
+typedef struct SymbolFileInstance
+{
+ SymbolFileInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ SymbolFileCreateInstance create_callback;
+};
+
+typedef std::vector<SymbolFileInstance> SymbolFileInstances;
+
+static bool
+AccessSymbolFileInstances (PluginAction action, SymbolFileInstance &instance, uint32_t index)
+{
+ static SymbolFileInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ SymbolFileInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ SymbolFileCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ SymbolFileInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessSymbolFileInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (SymbolFileCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ SymbolFileInstance instance;
+ instance.create_callback = create_callback;
+ return AccessSymbolFileInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+SymbolFileCreateInstance
+PluginManager::GetSymbolFileCreateCallbackAtIndex (uint32_t idx)
+{
+ SymbolFileInstance instance;
+ if (AccessSymbolFileInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+SymbolFileCreateInstance
+PluginManager::GetSymbolFileCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ SymbolFileInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessSymbolFileInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+#pragma mark SymbolVendor
+
+typedef struct SymbolVendorInstance
+{
+ SymbolVendorInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ SymbolVendorCreateInstance create_callback;
+};
+
+typedef std::vector<SymbolVendorInstance> SymbolVendorInstances;
+
+static bool
+AccessSymbolVendorInstances (PluginAction action, SymbolVendorInstance &instance, uint32_t index)
+{
+ static SymbolVendorInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ SymbolVendorInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ SymbolVendorCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ SymbolVendorInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessSymbolVendorInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (SymbolVendorCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ SymbolVendorInstance instance;
+ instance.create_callback = create_callback;
+ return AccessSymbolVendorInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+SymbolVendorCreateInstance
+PluginManager::GetSymbolVendorCreateCallbackAtIndex (uint32_t idx)
+{
+ SymbolVendorInstance instance;
+ if (AccessSymbolVendorInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+
+SymbolVendorCreateInstance
+PluginManager::GetSymbolVendorCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ SymbolVendorInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessSymbolVendorInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+
diff --git a/lldb/source/Core/RegularExpression.cpp b/lldb/source/Core/RegularExpression.cpp
new file mode 100644
index 00000000000..aca1671c181
--- /dev/null
+++ b/lldb/source/Core/RegularExpression.cpp
@@ -0,0 +1,154 @@
+//===-- 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"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+RegularExpression::RegularExpression() :
+ m_re(),
+ m_comp_err (1),
+ m_preg(),
+ m_matches()
+{
+ 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()
+{
+ memset(&m_preg,0,sizeof(m_preg));
+ Compile(re, flags);
+}
+
+//----------------------------------------------------------------------
+// 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, int flags)
+{
+ Free();
+ 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, size_t num_matches, int execute_flags) const
+{
+ int match_result = 1;
+ if (m_comp_err == 0)
+ {
+ if (num_matches > 0)
+ m_matches.resize(num_matches + 1);
+ else
+ m_matches.clear();
+
+ match_result = ::regexec (&m_preg,
+ s,
+ m_matches.size(),
+ const_cast<regmatch_t *>(m_matches.data()),
+ execute_flags);
+ }
+ return match_result == 0;
+}
+
+bool
+RegularExpression::GetMatchAtIndex (const char* s, uint32_t idx, std::string& match_str) const
+{
+ if (idx <= m_preg.re_nsub && idx < m_matches.size())
+ {
+ match_str.assign (s + m_matches[idx].rm_so,
+ m_matches[idx].rm_eo - m_matches[idx].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
+{
+ 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;
+ }
+}
diff --git a/lldb/source/Core/Scalar.cpp b/lldb/source/Core/Scalar.cpp
new file mode 100644
index 00000000000..56590b8d69e
--- /dev/null
+++ b/lldb/source/Core/Scalar.cpp
@@ -0,0 +1,2084 @@
+//===-- 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 "lldb/Core/Args.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/DataExtractor.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 (eByteOrderHost == 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, eByteOrderHost);
+ }
+ else if (eByteOrderHost == 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, eByteOrderHost);
+ }
+ }
+ else
+ {
+ // We want all of the data
+ data.SetData((uint8_t*)&m_data, byte_size, eByteOrderHost);
+ }
+ return true;
+ }
+ data.Clear();
+ return false;
+}
+
+size_t
+Scalar::GetByteSize() const
+{
+ switch (m_type)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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:
+ default:
+ 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)
+ {
+ default:
+ break;
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default: break;
+ 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(int))
+ return e_sint;
+ if (byte_size <= sizeof(long))
+ return e_slong;
+ if (byte_size <= sizeof(long long))
+ return e_slonglong;
+ return e_void;
+}
+
+Scalar::Type
+Scalar::GetValueTypeForUnsignedIntegerWithByteSize (size_t byte_size)
+{
+ if (byte_size <= sizeof(unsigned int))
+ return e_uint;
+ if (byte_size <= sizeof(unsigned long))
+ return e_ulong;
+ if (byte_size <= sizeof(unsigned long long))
+ return e_ulonglong;
+ return e_void;
+}
+
+Scalar::Type
+Scalar::GetValueTypeForFloatWithByteSize (size_t byte_size)
+{
+ if (byte_size == sizeof(float))
+ return e_float;
+ if (byte_size == sizeof(double))
+ return e_double;
+ if (byte_size == sizeof(long double))
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.slong; success = true; break;
+ case e_uint: m_data.uint = 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.ulong; success = true; break;
+ case e_uint: m_data.uint = 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.slonglong; success = true; break;
+ case e_uint: m_data.uint = 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.ulonglong; success = true; break;
+ case e_uint: m_data.uint = 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.flt; success = true; break;
+ case e_uint: m_data.uint = m_data.flt; success = true; break;
+ case e_slong: m_data.slong = m_data.flt; success = true; break;
+ case e_ulong: m_data.ulong = m_data.flt; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.flt; success = true; break;
+ case e_ulonglong: m_data.ulonglong = 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.dbl; success = true; break;
+ case e_uint: m_data.uint = m_data.dbl; success = true; break;
+ case e_slong: m_data.slong = m_data.dbl; success = true; break;
+ case e_ulong: m_data.ulong = m_data.dbl; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.dbl; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.dbl; success = true; break;
+ case e_float: m_data.flt = 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.ldbl; success = true; break;
+ case e_uint: m_data.uint = m_data.ldbl; success = true; break;
+ case e_slong: m_data.slong = m_data.ldbl; success = true; break;
+ case e_ulong: m_data.ulong = m_data.ldbl; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.ldbl; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.ldbl; success = true; break;
+ case e_float: m_data.flt = m_data.ldbl; success = true; break;
+ case e_double: m_data.dbl = m_data.ldbl; success = true; break;
+ case e_long_double: success = true; break;
+ }
+ break;
+ }
+
+ if (success)
+ m_type = type;
+ return success;
+}
+
+int
+Scalar::SInt(int fail_value) const
+{
+ switch (m_type)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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(int))
+ return m_data.uint;
+ else if (sizeof(m_data.flt) == sizeof(unsigned long))
+ return m_data.ulong;
+ else if (sizeof(m_data.flt) == sizeof(unsigned long long))
+ return m_data.ulonglong;
+ break;
+
+ case e_double:
+ if (sizeof(m_data.dbl) == sizeof(int))
+ return m_data.uint;
+ else if (sizeof(m_data.dbl) == sizeof(unsigned long))
+ return m_data.ulong;
+ else if (sizeof(m_data.dbl) == sizeof(unsigned long long))
+ return m_data.ulonglong;
+ break;
+
+ case e_long_double:
+ if (sizeof(m_data.ldbl) == sizeof(int))
+ return m_data.uint;
+ else if (sizeof(m_data.ldbl) == sizeof(unsigned long))
+ return m_data.ulong;
+ else if (sizeof(m_data.ldbl) == sizeof(unsigned long long))
+ return m_data.ulonglong;
+ break;
+ }
+ return fail_value;
+}
+
+
+
+long long
+Scalar::SLongLong(long long fail_value) const
+{
+ switch (m_type)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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;
+
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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;
+
+ default:
+ 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;
+
+ default:
+ 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;
+
+ default:
+ 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;
+
+ default:
+ 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;
+}
+
+// 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, uint32_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)
+ {
+ default:
+ 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.\n", value_str);
+ else if (!UIntValueIsValidForSize (uval64, byte_size))
+ error.SetErrorStringWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, byte_size);
+ else
+ {
+ m_type = Scalar::GetValueTypeForUnsignedIntegerWithByteSize (byte_size);
+ switch (m_type)
+ {
+ case e_uint: m_data.uint = uval64; break;
+ case e_ulong: m_data.ulong = uval64; break;
+ case e_ulonglong: m_data.ulonglong = uval64; break;
+ default:
+ error.SetErrorStringWithFormat ("Unsupported unsigned integer byte size: %u.\n", byte_size);
+ break;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Unsupported unsigned integer byte size: %u.\n", 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.\n", value_str);
+ else if (!SIntValueIsValidForSize (sval64, byte_size))
+ error.SetErrorStringWithFormat ("Value 0x%llx is too large to fit in a %u byte signed integer value.\n", sval64, byte_size);
+ else
+ {
+ m_type = Scalar::GetValueTypeForSignedIntegerWithByteSize (byte_size);
+ switch (m_type)
+ {
+ case e_sint: m_data.sint = sval64; break;
+ case e_slong: m_data.slong = sval64; break;
+ case e_slonglong: m_data.slonglong = sval64; break;
+ default:
+ error.SetErrorStringWithFormat ("Unsupported signed integer byte size: %u.\n", byte_size);
+ break;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Unsupported signed integer byte size: %u.\n", 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.\n", 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.\n", 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.\n", value_str);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Unsupported float byte size: %u.\n", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingVector:
+ error.SetErrorString ("Vector encoding unsupported.");
+ break;
+ }
+ if (error.Fail())
+ m_type = e_void;
+
+ return error;
+}
+
+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))
+ {
+ default:
+ 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))
+ {
+ default:
+ 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))
+ {
+ default:
+ 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))
+ {
+ default:
+ 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))
+ {
+ default:
+ 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))
+ {
+ default:
+ 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/lldb/source/Core/SearchFilter.cpp b/lldb/source/Core/SearchFilter.cpp
new file mode 100644
index 00000000000..4c54a912801
--- /dev/null
+++ b/lldb/source/Core/SearchFilter.cpp
@@ -0,0 +1,435 @@
+//===-- 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/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(lldb::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::SymbolContextPasses
+(
+ const SymbolContext &context,
+ lldb::SymbolContextItem scope
+)
+{
+ return true;
+}
+
+bool
+SearchFilter::AddressPasses (Address &address)
+{
+ return true;
+}
+
+bool
+SearchFilter::CompUnitPasses (FileSpec &fileSpec)
+{
+ return true;
+}
+
+bool
+SearchFilter::CompUnitPasses (CompileUnit &compUnit)
+{
+ return true;
+}
+
+void
+SearchFilter::GetDescription (Stream *s)
+{
+ s->PutCString("No Filter");
+}
+
+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 == NULL)
+ 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 == NULL)
+ return;
+ empty_sc.target_sp = m_target_sp;
+
+ if (searcher.GetDepth() == Searcher::eDepthTarget)
+ searcher.SearchCallback (*this, empty_sc, NULL, false);
+ else
+ {
+ size_t numModules = modules.GetSize();
+
+ for (int i = 0; i < numModules; i++)
+ {
+ ModuleSP module_sp(modules.GetModuleAtIndex(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)
+{
+ Searcher::CallbackReturn shouldContinue;
+
+ if (searcher.GetDepth () >= Searcher::eDepthModule)
+ {
+ if (!context.module_sp)
+ {
+ size_t n_modules = m_target_sp->GetImages().GetSize();
+ for (int i = 0; i < n_modules; i++)
+ {
+ // If this is the last level supplied, then call the callback directly,
+ // otherwise descend.
+ ModuleSP module_sp(m_target_sp->GetImages().GetModuleAtIndex(i));
+ if (!ModulePasses (module_sp))
+ continue;
+
+ if (searcher.GetDepth () == Searcher::eDepthModule)
+ {
+ SymbolContext matchingContext(m_target_sp, module_sp);
+
+ shouldContinue = searcher.SearchCallback (*this, matchingContext, NULL, false);
+ if (shouldContinue == Searcher::eCallbackReturnStop
+ || shouldContinue == Searcher::eCallbackReturnPop)
+ return shouldContinue;
+ }
+ else
+ {
+ shouldContinue = DoCUIteration(module_sp, context, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return shouldContinue;
+ else if (shouldContinue == Searcher::eCallbackReturnPop)
+ continue;
+ }
+ }
+ }
+ else
+ {
+ if (searcher.GetDepth () == Searcher::eDepthModule)
+ {
+ SymbolContext matchingContext(context.module_sp.get());
+
+ shouldContinue = searcher.SearchCallback (*this, matchingContext, NULL, false);
+ }
+ else
+ {
+ return DoCUIteration(context.module_sp, context, searcher);
+ }
+ }
+
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::CallbackReturn
+SearchFilter::DoCUIteration (const ModuleSP &module_sp, const SymbolContext &context, Searcher &searcher)
+{
+ Searcher::CallbackReturn shouldContinue;
+ if (context.comp_unit == NULL)
+ {
+ uint32_t num_comp_units = module_sp->GetNumCompileUnits();
+ for (uint32_t i = 0; i < num_comp_units; i++)
+ {
+ CompUnitSP cu_sp (module_sp->GetCompileUnitAtIndex (i));
+ 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;
+}
+
+//----------------------------------------------------------------------
+// SearchFilterByModule:
+// Selects a shared library matching a given file spec
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// SearchFilterByModule constructors
+//----------------------------------------------------------------------
+
+SearchFilterByModule::SearchFilterByModule (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::Compare (module_sp->GetFileSpec(), m_module_spec, false) == 0)
+ return true;
+ else
+ return false;
+}
+
+bool
+SearchFilterByModule::ModulePasses (const FileSpec &spec)
+{
+ if (FileSpec::Compare(spec, m_module_spec, false) == 0)
+ return true;
+ else
+ return false;
+}
+
+bool
+SearchFilterByModule::SymbolContextPasses
+(
+ const SymbolContext &context,
+ lldb::SymbolContextItem scope
+ )
+{
+ if (!(scope & eSymbolContextModule))
+ return false;
+
+ if (context.module_sp && FileSpec::Compare (context.module_sp->GetFileSpec(), m_module_spec, false) == 0)
+ return true;
+ else
+ return false;
+}
+
+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.
+
+ ModuleList matching_modules;
+ // const size_t num_matching_modules = m_target_sp->GetImages().FindModules(&m_module_spec, NULL, NULL, NULL, matching_modules);
+ for (int i = 0; i < m_target_sp->GetImages().GetSize (); i++)
+ {
+ Module* module = m_target_sp->GetImages().GetModulePointerAtIndex(i);
+ if (FileSpec::Compare (m_module_spec, module->GetFileSpec(), false) == 0)
+ {
+ SymbolContext matchingContext(m_target_sp, module->GetSP());
+ Searcher::CallbackReturn shouldContinue;
+
+ shouldContinue = DoModuleIteration(matchingContext, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return;
+ }
+ }
+}
+
+void
+SearchFilterByModule::GetDescription (Stream *s)
+{
+ s->PutCString("In 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>"));
+ }
+}
+
+void
+SearchFilterByModule::Dump (Stream *s) const
+{
+
+}
diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp
new file mode 100644
index 00000000000..57c519918f2
--- /dev/null
+++ b/lldb/source/Core/Section.cpp
@@ -0,0 +1,791 @@
+//===-- 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/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Section::Section
+(
+ Section *parent,
+ Module* module,
+ user_id_t sect_id,
+ const ConstString &name,
+ SectionType sect_type,
+ addr_t file_addr,
+ addr_t byte_size,
+ uint64_t file_offset,
+ uint64_t file_size,
+ uint32_t flags
+) :
+ ModuleChild (module),
+ UserID (sect_id),
+ Flags (flags),
+ m_parent (parent),
+ m_name (name),
+ m_type (sect_type),
+ 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_linked_section(NULL),
+ m_linked_offset (0)
+{
+}
+
+//Section::Section
+//(
+// Section *parent,
+// Module* module,
+// user_id_t sect_id,
+// const ConstString &name,
+// const AddressRange *file_vm_range,
+// uint64_t file_offset,
+// uint64_t file_size,
+// uint32_t flags
+//) :
+// ModuleChild (module),
+// UserID (sect_id),
+// Flags (flags),
+// m_parent (parent),
+// m_name (name),
+// m_range (),
+// m_file_offset (file_offset),
+// m_file_size (file_size),
+// m_children (),
+// m_fake (false)
+//{
+// if (file_vm_range)
+// m_range = *file_vm_range;
+//}
+
+Section::~Section()
+{
+}
+
+
+// Get a valid shared pointer to this section object
+SectionSP
+Section::GetSharedPointer() const
+{
+ SectionSP this_sp;
+ if (m_parent)
+ this_sp = m_parent->GetChildren().GetSharedPointer (this, false);
+ else
+ {
+ ObjectFile *objfile = m_module->GetObjectFile();
+ if (objfile)
+ {
+ SectionList *section_list = objfile->GetSectionList();
+ if (section_list)
+ this_sp = section_list->GetSharedPointer (this, false);
+ }
+ }
+ return this_sp;
+}
+
+
+
+ConstString&
+Section::GetName()
+{
+ if (m_linked_section)
+ return const_cast<Section *>(m_linked_section)->GetName();
+ return m_name;
+}
+
+const ConstString&
+Section::GetName() const
+{
+ if (m_linked_section)
+ return m_linked_section->GetName();
+ return m_name;
+}
+
+SectionList&
+Section::GetChildren()
+{
+ return m_children;
+}
+
+const SectionList&
+Section::GetChildren() const
+{
+ return m_children;
+}
+
+addr_t
+Section::GetFileAddress () const
+{
+ if (m_parent)
+ {
+ // 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 m_parent->GetFileAddress() + m_file_addr;
+ }
+ // This section has no parent, so m_file_addr is the file base address
+ return m_file_addr;
+}
+
+addr_t
+Section::GetLinkedFileAddress () const
+{
+ if (m_linked_section)
+ return m_linked_section->GetFileAddress() + m_linked_offset;
+ return LLDB_INVALID_ADDRESS;
+}
+
+addr_t
+Section::GetOffset () const
+{
+ if (m_parent)
+ {
+ // This section has a parent which means m_file_addr is an offset.
+ return m_file_addr;
+ }
+
+ // This section has no parent, so there is no offset to be had
+ return 0;
+}
+
+addr_t
+Section::GetByteSize () const
+{
+ return m_byte_size;
+}
+
+void
+Section::SetByteSize (addr_t byte_size)
+{
+ m_byte_size = byte_size;
+}
+
+
+addr_t
+Section::GetLoadBaseAddress (Process *process) const
+{
+ addr_t load_base_addr = LLDB_INVALID_ADDRESS;
+ if (m_linked_section)
+ {
+ load_base_addr = m_linked_section->GetLoadBaseAddress(process) + m_linked_offset;
+ }
+ else
+ if (m_parent)
+ {
+ load_base_addr = m_parent->GetLoadBaseAddress (process);
+ if (load_base_addr != LLDB_INVALID_ADDRESS)
+ load_base_addr += GetOffset();
+ }
+ else
+ {
+ load_base_addr = process->GetSectionLoadAddress(this);
+ }
+
+ return load_base_addr;
+}
+
+bool
+Section::ResolveContainedAddress (addr_t offset, Address &so_addr) const
+{
+ const uint32_t num_children = m_children.GetSize();
+ if (num_children > 0)
+ {
+ for (uint32_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);
+ }
+ }
+ if (m_linked_section)
+ {
+ so_addr.SetOffset(m_linked_offset + offset);
+ so_addr.SetSection(m_linked_section);
+ }
+ else
+ {
+ so_addr.SetOffset(offset);
+ so_addr.SetSection(this);
+ }
+ return true;
+}
+
+uint64_t
+Section::GetFileOffset() const
+{
+ return m_file_offset;
+}
+
+uint64_t
+Section::GetFileSize() const
+{
+ return m_file_size;
+}
+
+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;
+}
+
+bool
+Section::ContainsLinkedFileAddress (addr_t vm_addr) const
+{
+ const addr_t linked_file_addr = GetLinkedFileAddress();
+ if (linked_file_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (linked_file_addr <= vm_addr)
+ {
+ const addr_t offset = vm_addr - linked_file_addr;
+ return offset < GetByteSize();
+ }
+ }
+ return false;
+}
+
+int
+Section::Compare (const Section& a, const Section& b)
+{
+ if (&a == &b)
+ return 0;
+
+ const Module* a_module = a.GetModule();
+ const Module* b_module = b.GetModule();
+ if (a_module == b_module)
+ {
+ 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 < b_module)
+ return -1;
+ else
+ return 1; // We already know the modules aren't equal
+ }
+}
+
+
+void
+Section::Dump(Stream *s, Process *process) const
+{
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ s->Printf("0x%8.8x ", GetID());
+ bool resolved = true;
+ addr_t addr = LLDB_INVALID_ADDRESS;
+
+ if (GetByteSize() == 0)
+ s->Printf("%39s", "");
+ else
+ {
+ if (process)
+ addr = GetLoadBaseAddress (process);
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ if (process)
+ resolved = false;
+ addr = GetFileAddress();
+ }
+
+ VMRange range(addr, addr + m_byte_size);
+ range.Dump (s, 0);
+ }
+
+ s->Printf("%c 0x%8.8llx 0x%8.8llx 0x%8.8x ", resolved ? ' ' : '*', m_file_offset, m_file_size, GetAllFlagBits());
+
+ DumpName (s);
+
+ s->EOL();
+
+ if (m_linked_section)
+ {
+ addr = LLDB_INVALID_ADDRESS;
+
+ if (process)
+ {
+ addr = m_linked_section->GetLoadBaseAddress(process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ addr += m_linked_offset;
+ }
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ if (process)
+ resolved = false;
+ addr = m_linked_section->GetFileAddress() + m_linked_offset;
+ }
+
+ int indent = (sizeof(void*) + 1 + sizeof(user_id_t) + 1) * 2 + 3 + s->GetIndentLevel();
+ s->Printf("%*.*s", indent, indent, "");
+ VMRange linked_range(addr, addr + m_byte_size);
+ linked_range.Dump (s, 0);
+ indent = 3 * (sizeof(uint32_t) * 2 + 2 + 1) + 1;
+ s->Printf("%c%*.*s", resolved ? ' ' : '*', indent, indent, "");
+
+ m_linked_section->DumpName(s);
+ s->Printf(" + 0x%llx\n", m_linked_offset);
+ }
+
+ m_children.Dump(s, process, false);
+}
+
+void
+Section::DumpName (Stream *s) const
+{
+ if (m_linked_section)
+ return m_linked_section->DumpName(s);
+ else if (m_parent == NULL)
+ {
+ // The top most section prints the module basename
+ const char *module_basename = m_module->GetFileSpec().GetFilename().AsCString();
+ if (module_basename && module_basename[0])
+ s->Printf("%s.", module_basename);
+ }
+ else
+ {
+ m_parent->DumpName (s);
+ s->PutChar('.');
+ }
+ m_name.Dump(s);
+}
+
+//----------------------------------------------------------------------
+// Get the section data from a complete contiguous copy of the
+// entire executable image.
+//----------------------------------------------------------------------
+size_t
+Section::GetSectionDataFromImage (const DataExtractor& image_data, DataExtractor& section_data) const
+{
+ size_t file_size = GetByteSize();
+ if (file_size > 0)
+ {
+ off_t file_offset = GetFileOffset();
+ if (section_data.SetData (image_data, file_offset, file_size) == file_size)
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Get the section data the file on disk
+//----------------------------------------------------------------------
+size_t
+Section::ReadSectionDataFromObjectFile(const ObjectFile* objfile, DataExtractor& section_data) const
+{
+ if (objfile == NULL)
+ return 0;
+
+ const FileSpec& file = objfile->GetFileSpec();
+
+ if (file)
+ {
+ size_t section_file_size = GetByteSize();
+ if (section_file_size > 0)
+ {
+ off_t section_file_offset = GetFileOffset() + objfile->GetOffset();
+ DataBufferSP sectionDataSP(file.ReadFileContents(section_file_offset, section_file_size));
+
+ section_data.SetByteOrder(objfile->GetByteOrder());
+ section_data.SetAddressByteSize(objfile->GetAddressByteSize());
+ return section_data.SetData (sectionDataSP);
+ }
+ }
+ return 0;
+}
+
+size_t
+Section::MemoryMapSectionDataFromObjectFile(const ObjectFile* objfile, DataExtractor& section_data) const
+{
+ if (objfile == NULL)
+ return 0;
+
+ const FileSpec& file = objfile->GetFileSpec();
+
+ if (file)
+ {
+ size_t section_file_size = GetFileSize();
+ if (section_file_size > 0)
+ {
+ off_t section_file_offset = GetFileOffset() + objfile->GetOffset();
+ DataBufferSP sectionDataSP(file.MemoryMapFileContents(section_file_offset, section_file_size));
+ section_data.SetByteOrder(objfile->GetByteOrder());
+ section_data.SetAddressByteSize(objfile->GetAddressByteSize());
+ return section_data.SetData (sectionDataSP);
+ }
+ }
+ return 0;
+}
+
+bool
+Section::IsFake() const
+{
+ return m_fake;
+}
+
+void
+Section::SetIsFake(bool fake)
+{
+ m_fake = fake;
+}
+
+
+bool
+Section::IsDescendant (const Section *section)
+{
+ if (this == section)
+ return true;
+ if (m_parent)
+ return m_parent->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;
+}
+
+void
+Section::SetLinkedLocation (const Section *linked_section, uint64_t linked_offset)
+{
+ if (linked_section)
+ m_module = linked_section->GetModule();
+ m_linked_section = linked_section;
+ m_linked_offset = linked_offset;
+}
+
+const Section *
+Section::GetLinkedSection () const
+{
+ return m_linked_section;
+}
+
+uint64_t
+Section::GetLinkedOffset () const
+{
+ return m_linked_offset;
+}
+
+#pragma mark SectionList
+
+SectionList::SectionList () :
+ m_sections()
+{
+}
+
+
+SectionList::~SectionList ()
+{
+}
+
+uint32_t
+SectionList::AddSection (SectionSP& sect_sp)
+{
+ uint32_t section_index = m_sections.size();
+ m_sections.push_back(sect_sp);
+ return section_index;
+}
+
+uint32_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;
+}
+
+uint32_t
+SectionList::AddUniqueSection (SectionSP& sect_sp)
+{
+ uint32_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, 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::GetSize () const
+{
+ return m_sections.size();
+}
+
+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 (uint32_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)
+ {
+ 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)->GetName() == section_dstr)
+ {
+ sect_sp = *sect_iter;
+ }
+ else
+ {
+ sect_sp = (*sect_iter)->GetChildren().FindSectionByName(section_dstr);
+ }
+ }
+ }
+ return sect_sp;
+}
+//
+//SectionSP
+//SectionList::FindSectionByNames (const char *s, ...) const
+//{
+// SectionSP sect_sp;
+// va_list ap;
+// va_start(ap, s);
+// uint32_t idx = 0;
+// for (const char *sect_name = s; sect_name != NULL; sect_name = va_arg(ap, const char *))
+// {
+// printf("[%u] %s\n", idx++, sect_name);
+// }
+// va_end(ap);
+// 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::GetSharedPointer (const Section *section, bool check_children) const
+{
+ SectionSP sect_sp;
+ if (section)
+ {
+ 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->get() == section)
+ {
+ sect_sp = *sect_iter;
+ break;
+ }
+ else if (check_children)
+ {
+ sect_sp = (*sect_iter)->GetChildren().GetSharedPointer (section, true);
+ }
+ }
+ }
+ 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;
+}
+
+
+SectionSP
+SectionList::FindSectionContainingLinkedFileAddress (addr_t vm_addr) 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->ContainsLinkedFileAddress (vm_addr))
+ {
+ sect_sp = *sect_iter;
+ break;
+ }
+ }
+ return sect_sp;
+}
+
+bool
+SectionList::ContainsSection(user_id_t sect_id) const
+{
+ return FindSectionByID (sect_id).get() != NULL;
+}
+
+void
+SectionList::Dump (Stream *s, Process *process, bool show_header) const
+{
+ if (show_header && !m_sections.empty())
+ {
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ s->PutCString( "SectionList\n");
+ s->IndentMore();
+ s->Printf("%*s", 2*(sizeof(void *) + 2), "");
+ s->Indent();
+ s->Printf("SectID %s Address File Off. File Size Flags Section Name\n", process ? "Load" : "File");
+ s->Printf("%*s", 2*(sizeof(void *) + 2), "");
+ 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, process);
+ }
+
+ 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/lldb/source/Core/SourceManager.cpp b/lldb/source/Core/SourceManager.cpp
new file mode 100644
index 00000000000..2786fe40720
--- /dev/null
+++ b/lldb/source/Core/SourceManager.cpp
@@ -0,0 +1,305 @@
+//===-- 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/Core/SourceManager.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb_private;
+
+static inline bool is_newline_char(char ch)
+{
+ return ch == '\n' || ch == '\r';
+}
+
+
+//----------------------------------------------------------------------
+// SourceManager constructor
+//----------------------------------------------------------------------
+SourceManager::SourceManager() :
+ m_file_cache (),
+ m_last_file_sp (),
+ m_last_file_line (0),
+ m_last_file_context_before (0),
+ m_last_file_context_after (0)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SourceManager::~SourceManager()
+{
+}
+
+size_t
+SourceManager::DisplaySourceLines
+(
+ const FileSpec &file_spec,
+ uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ Stream *s
+)
+{
+ m_last_file_sp = GetFile (file_spec);
+ m_last_file_line = line + context_after + 1;
+ m_last_file_context_before = context_before;
+ m_last_file_context_after = context_after;
+ if (m_last_file_sp.get())
+ return m_last_file_sp->DisplaySourceLines (line, context_before, context_after, s);
+
+ return 0;
+}
+
+SourceManager::FileSP
+SourceManager::GetFile (const FileSpec &file_spec)
+{
+ FileSP file_sp;
+ FileCache::iterator pos = m_file_cache.find(file_spec);
+ if (pos != m_file_cache.end())
+ file_sp = pos->second;
+ else
+ {
+ file_sp.reset (new File (file_spec));
+ m_file_cache[file_spec] = file_sp;
+ }
+ return file_sp;
+}
+
+size_t
+SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile
+(
+ uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ const char* current_line_cstr,
+ Stream *s
+)
+{
+ if (line == 0)
+ {
+ if (m_last_file_line != 0
+ && m_last_file_line != UINT32_MAX)
+ line = m_last_file_line + context_before;
+ else
+ line = 1;
+ }
+
+ m_last_file_line = line + context_after + 1;
+ m_last_file_context_before = context_before;
+ m_last_file_context_after = context_after;
+
+ if (context_before == UINT32_MAX)
+ context_before = 0;
+ if (context_after == UINT32_MAX)
+ context_after = 10;
+
+ if (m_last_file_sp.get())
+ {
+ const uint32_t start_line = line <= context_before ? 1 : line - context_before;
+ const uint32_t end_line = line + context_after;
+ uint32_t curr_line;
+ for (curr_line = start_line; curr_line <= end_line; ++curr_line)
+ {
+ if (!m_last_file_sp->LineIsValid (curr_line))
+ {
+ m_last_file_line = UINT32_MAX;
+ break;
+ }
+
+ s->Printf("%4u %2.2s\t", curr_line, curr_line == line ? current_line_cstr : "");
+ if (m_last_file_sp->DisplaySourceLines (curr_line, 0, 0, s) == 0)
+ {
+ m_last_file_line = UINT32_MAX;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+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
+)
+{
+ bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec);
+
+ if (!same_as_previous)
+ m_last_file_sp = GetFile (file_spec);
+
+ if (line == 0)
+ {
+ if (!same_as_previous)
+ m_last_file_line = 0;
+ }
+
+ return DisplaySourceLinesWithLineNumbersUsingLastFile (line, context_before, context_after, current_line_cstr, s);
+}
+
+size_t
+SourceManager::DisplayMoreWithLineNumbers (Stream *s)
+{
+ if (m_last_file_sp)
+ {
+ if (m_last_file_line == UINT32_MAX)
+ return 0;
+ DisplaySourceLinesWithLineNumbersUsingLastFile (0, m_last_file_context_before, m_last_file_context_after, "", s);
+ }
+ return 0;
+}
+
+
+
+SourceManager::File::File(const FileSpec &file_spec) :
+ m_file_spec(file_spec),
+ m_data_sp(file_spec.ReadFileContents ()),
+ m_offsets()
+{
+}
+
+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)
+{
+ 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;
+}
+
+bool
+SourceManager::File::FileSpecMatches (const FileSpec &file_spec)
+{
+ return FileSpec::Compare (m_file_spec, file_spec, false) == 0;
+}
+
+
+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))
+ {
+ 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");
+ }
+
+ }
+ else
+ {
+ // Calculate all line offsets up to "line"
+ assert(!"Not implemented yet");
+ }
+ return false;
+}
diff --git a/lldb/source/Core/State.cpp b/lldb/source/Core/State.cpp
new file mode 100644
index 00000000000..cf9a8345818
--- /dev/null
+++ b/lldb/source/Core/State.cpp
@@ -0,0 +1,87 @@
+//===-- 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"
+
+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 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;
+}
+
+bool
+lldb_private::StateIsRunningState (StateType state)
+{
+ switch (state)
+ {
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ return true;
+
+ case eStateDetached:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ default:
+ break;
+ }
+ return false;
+}
+
+bool
+lldb_private::StateIsStoppedState (StateType state)
+{
+ switch (state)
+ {
+ case eStateInvalid:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ default:
+ break;
+
+ case eStateUnloaded:
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ return true;
+ }
+ return false;
+}
diff --git a/lldb/source/Core/Stream.cpp b/lldb/source/Core/Stream.cpp
new file mode 100644
index 00000000000..a0de2d431e9
--- /dev/null
+++ b/lldb/source/Core/Stream.cpp
@@ -0,0 +1,776 @@
+//===-- 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"
+
+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 (eByteOrderHost),
+ 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".
+//------------------------------------------------------------------
+int
+Stream::PutSLEB128 (int64_t sval)
+{
+ int bytes_written = 0;
+ if (m_flags.IsSet(eBinary))
+ {
+ bool more = true;
+ bool negative = (sval < 0);
+ while (more)
+ {
+ uint8_t byte = sval & 0x7fu;
+ sval >>= 7;
+ assert((!negative && sval >= 0) || (negative && sval < 0));
+ /* 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%lli", sval);
+ }
+
+ return bytes_written;
+
+}
+
+//------------------------------------------------------------------
+// Put an ULEB128 "uval" out to the stream using the printf format
+// in "format".
+//------------------------------------------------------------------
+int
+Stream::PutULEB128 (uint64_t uval)
+{
+ int bytes_written = 0;
+ if (m_flags.IsSet(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%llx", uval);
+ }
+ return bytes_written;
+}
+
+//------------------------------------------------------------------
+// Print a raw NULL terminated C string to the stream using the
+// printf format in "format".
+//------------------------------------------------------------------
+int
+Stream::PutCString (const char *cstr)
+{
+ int cstr_len = strlen(cstr);
+ // when in binary mode, emit the NULL terminator
+ if (m_flags.IsSet(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, int 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*llx%s", prefix, addr_width, addr, suffix);
+ Printf ("%s0x%0*llx%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, int addr_size, const char *prefix, const char *suffix)
+{
+ if (prefix != NULL)
+ PutCString (prefix);
+ Address (lo_addr, addr_size, "[");
+ Address (hi_addr, addr_size, "-", ")");
+}
+
+
+int
+Stream::PutChar (char ch)
+{
+ return Write (&ch, 1);
+}
+
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+int
+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.
+//------------------------------------------------------------------
+int
+Stream::PrintfVarArg (const char *format, va_list args)
+{
+ char str[1024];
+ va_list args_copy;
+
+ va_copy (args_copy, args);
+
+ int bytes_written = 0;
+ // Try and format our string into a fixed buffer first and see if it fits
+ int length = vsnprintf (str, sizeof(str), format, args);
+ if (length < sizeof(str))
+ {
+ va_end (args);
+ // Include the NULL termination byte for binary output
+ if (m_flags.IsSet(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.IsSet(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
+//------------------------------------------------------------------
+int
+Stream::EOL()
+{
+ return PutChar ('\n');
+}
+
+//------------------------------------------------------------------
+// Indent the current line using the current indentation level and
+// print an optional string following the idenatation spaces.
+//------------------------------------------------------------------
+int
+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 ("%lli", 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
+//------------------------------------------------------------------
+uint8_t
+Stream::GetAddressByteSize() const
+{
+ return m_addr_size;
+}
+
+//------------------------------------------------------------------
+// Set the address size in bytes
+//------------------------------------------------------------------
+void
+Stream::SetAddressByteSize(uint8_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.IsSet(eVerbose);
+}
+
+//------------------------------------------------------------------
+// Returns true if the debug flag bit is set in this stream.
+//------------------------------------------------------------------
+bool
+Stream::GetDebug() const
+{
+ return m_flags.IsSet(eDebug);
+}
+
+//------------------------------------------------------------------
+// The flags get accessor
+//------------------------------------------------------------------
+Flags&
+Stream::GetFlags()
+{
+ return m_flags;
+}
+
+//------------------------------------------------------------------
+// The flags const get accessor
+//------------------------------------------------------------------
+const Flags&
+Stream::GetFlags() const
+{
+ return m_flags;
+}
+
+int
+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
+
+ int i;
+ char str[1024];
+ int bytes_written = 0;
+ // Try and format our string into a fixed buffer first and see if it fits
+ int 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 (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 (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;
+}
+
+int
+Stream::PutNHex8 (size_t n, uint8_t uvalue)
+{
+ int bytes_written = 0;
+ for (int i=0; i<n; ++i)
+ bytes_written += _PutHex8 (uvalue, m_flags.IsSet(eAddPrefix));
+ return bytes_written;
+}
+
+int
+Stream::_PutHex8 (uint8_t uvalue, bool add_prefix)
+{
+ int bytes_written = 0;
+ if (m_flags.IsSet(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;
+}
+
+int
+Stream::PutHex8 (uint8_t uvalue)
+{
+ return _PutHex8 (uvalue, m_flags.IsSet(eAddPrefix));
+}
+
+int
+Stream::PutHex16 (uint16_t uvalue, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ bool add_prefix = m_flags.IsSet(eAddPrefix);
+ int bytes_written = 0;
+ int byte;
+ if (byte_order == eByteOrderLittle)
+ {
+ for (byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
+ bytes_written += _PutHex8 (uvalue >> (byte * 8), add_prefix);
+ }
+ else
+ {
+ for (byte = sizeof(uvalue)-1; byte >= 0; --byte, add_prefix = false)
+ bytes_written += _PutHex8 (uvalue >> (byte * 8), add_prefix);
+ }
+ return bytes_written;
+}
+
+int
+Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ bool add_prefix = m_flags.IsSet(eAddPrefix);
+ int bytes_written = 0;
+ int byte;
+ if (byte_order == eByteOrderLittle)
+ {
+ for (byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
+ bytes_written += _PutHex8 (uvalue >> (byte * 8), add_prefix);
+ }
+ else
+ {
+ for (byte = sizeof(uvalue)-1; byte >= 0; --byte, add_prefix = false)
+ bytes_written += _PutHex8 (uvalue >> (byte * 8), add_prefix);
+ }
+ return bytes_written;
+}
+
+int
+Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ bool add_prefix = m_flags.IsSet(eAddPrefix);
+ int bytes_written = 0;
+ int byte;
+ if (byte_order == eByteOrderLittle)
+ {
+ for (byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
+ bytes_written += _PutHex8 (uvalue >> (byte * 8), add_prefix);
+ }
+ else
+ {
+ for (byte = sizeof(uvalue)-1; byte >= 0; --byte, add_prefix = false)
+ bytes_written += _PutHex8 (uvalue >> (byte * 8), add_prefix);
+ }
+ return bytes_written;
+}
+
+int
+Stream::PutMaxHex64
+(
+ uint64_t uvalue,
+ size_t byte_size,
+ lldb::ByteOrder byte_order
+)
+{
+ switch (byte_size)
+ {
+ case 1: return PutHex8 (uvalue);
+ case 2: return PutHex16 (uvalue);
+ case 4: return PutHex32 (uvalue);
+ case 8: return PutHex64 (uvalue);
+ }
+ return 0;
+}
+
+int
+Stream::PutPointer (void *ptr)
+{
+ return PutRawBytes (&ptr, sizeof(ptr), eByteOrderHost, eByteOrderHost);
+}
+
+int
+Stream::PutFloat(float f, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes (&f, sizeof(f), eByteOrderHost, byte_order);
+}
+
+int
+Stream::PutDouble(double d, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes (&d, sizeof(d), eByteOrderHost, byte_order);
+}
+
+int
+Stream::PutLongDouble(long double ld, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes (&ld, sizeof(ld), eByteOrderHost, byte_order);
+}
+
+int
+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;
+
+ int bytes_written = 0;
+ const uint8_t *src = (const uint8_t *)s;
+ int i;
+ bool binary_is_clear = m_flags.IsClear (eBinary);
+ m_flags.Set (eBinary);
+ if (src_byte_order == dst_byte_order)
+ {
+ for (i=0;i<src_len; ++i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ else
+ {
+ for (i=src_len-1;i>=0; --i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ if (binary_is_clear)
+ m_flags.Clear (eBinary);
+
+ return bytes_written;
+}
+
+int
+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;
+
+ int bytes_written = 0;
+ const uint8_t *src = (const uint8_t *)s;
+ int i;
+ bool binary_is_set = m_flags.IsSet(eBinary);
+ m_flags.Clear(eBinary);
+ if (src_byte_order == dst_byte_order)
+ {
+ for (i=0;i<src_len; ++i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ else
+ {
+ for (i=src_len-1;i>=0; --i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+
+ return bytes_written;
+}
+
+int
+Stream::PutCStringAsRawHex8 (const char *s)
+{
+ int bytes_written = 0;
+ bool binary_is_set = m_flags.IsSet(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, eByteOrderHost);
+ s->PutChar(' ');
+ s->PutHex16(0x3456, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex16(0x3456, eByteOrderLittle);
+
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderHost);
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderLittle);
+
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, eByteOrderHost);
+ 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/lldb/source/Core/StreamFile.cpp b/lldb/source/Core/StreamFile.cpp
new file mode 100644
index 00000000000..9c6c508b49e
--- /dev/null
+++ b/lldb/source/Core/StreamFile.cpp
@@ -0,0 +1,132 @@
+//===-- 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
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// StreamFile constructor
+//----------------------------------------------------------------------
+StreamFile::StreamFile () :
+ Stream (),
+ m_file (NULL),
+ m_path_name (),
+ m_close_file (false)
+{
+}
+
+StreamFile::StreamFile(uint32_t flags, uint32_t addr_size, ByteOrder byte_order, FILE *f) :
+ Stream (flags, addr_size, byte_order),
+ m_file(f),
+ m_path_name (),
+ m_close_file(false)
+{
+}
+
+StreamFile::StreamFile(FILE *f) :
+ Stream (),
+ m_file(f),
+ m_path_name (),
+ m_close_file(false)
+{
+}
+
+StreamFile::StreamFile(uint32_t flags, uint32_t addr_size, ByteOrder byte_order, const char *path, const char *permissions) :
+ Stream (flags, addr_size, byte_order),
+ m_file (NULL),
+ m_path_name (path),
+ m_close_file(false)
+{
+ Open(path, permissions);
+}
+
+StreamFile::StreamFile(const char *path, const char *permissions) :
+ Stream (),
+ m_file (NULL),
+ m_path_name (path),
+ m_close_file(false)
+{
+ Open(path, permissions);
+}
+
+
+StreamFile::~StreamFile()
+{
+ Close ();
+}
+
+void
+StreamFile::Close ()
+{
+ if (m_close_file && m_file != NULL)
+ ::fclose (m_file);
+ m_file = NULL;
+ m_close_file = false;
+}
+
+bool
+StreamFile::Open (const char *path, const char *permissions)
+{
+ Close();
+ if (path && path[0])
+ {
+ if ((m_path_name.size() == 0)
+ || (m_path_name.compare(path) != 0))
+ m_path_name = path;
+ m_file = ::fopen (path, permissions);
+ if (m_file != NULL)
+ m_close_file = true;
+ }
+ return m_file != NULL;
+}
+
+void
+StreamFile::Flush ()
+{
+ if (m_file)
+ ::fflush (m_file);
+}
+
+int
+StreamFile::Write (const void *s, size_t length)
+{
+ if (m_file)
+ return ::fwrite (s, 1, length, m_file);
+ return 0;
+}
+
+FILE *
+StreamFile::GetFileHandle()
+{
+ return m_file;
+}
+
+void
+StreamFile::SetFileHandle (FILE *file, bool close_file)
+{
+ Close();
+ m_file = file;
+ m_close_file = close_file;
+}
+
+const char *
+StreamFile::GetFilePathname ()
+{
+ if (m_path_name.size() == 0)
+ return NULL;
+ else
+ return m_path_name.c_str();
+}
diff --git a/lldb/source/Core/StreamString.cpp b/lldb/source/Core/StreamString.cpp
new file mode 100644
index 00000000000..ccd9f972582
--- /dev/null
+++ b/lldb/source/Core/StreamString.cpp
@@ -0,0 +1,81 @@
+//===-- 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 <libkern/OSByteOrder.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...
+}
+
+int
+StreamString::Write (const void *s, size_t length)
+{
+ m_packet.append ((char *)s, length);
+ return length;
+}
+
+void
+StreamString::Clear()
+{
+ m_packet.clear();
+}
+
+void
+StreamString::Dump(FILE *f)
+{
+ int size = GetSize();
+ if (size > 0)
+ fprintf(f, "%*.*s", size, size, m_packet.c_str());
+}
+
+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;
+}
+
diff --git a/lldb/source/Core/StringList.cpp b/lldb/source/Core/StringList.cpp
new file mode 100644
index 00000000000..cb96fb0f7b9
--- /dev/null
+++ b/lldb/source/Core/StringList.cpp
@@ -0,0 +1,200 @@
+//===-- 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 <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 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)
+{
+ uint32_t len = strings.GetSize();
+
+ for (int i = 0; i < len; ++i)
+ m_strings.push_back (strings.GetStringAtIndex(i));
+}
+
+uint32_t
+StringList::GetSize ()
+{
+ return m_strings.size();
+}
+
+const char *
+StringList::GetStringAtIndex (size_t idx)
+{
+ if (idx < m_strings.size())
+ return m_strings[idx].c_str();
+ return NULL;
+}
+
+void
+StringList::Clear ()
+{
+ m_strings.clear();
+}
+
+void
+StringList::LongestCommonPrefix (std::string &common_prefix)
+{
+ //arg_sstr_collection::iterator pos, end = m_args.end();
+ int pos = 0;
+ int end = m_strings.size();
+
+ if (pos == end)
+ common_prefix.clear();
+ else
+ common_prefix = m_strings[pos];
+
+ for (++pos; pos != end; ++pos)
+ {
+ int 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 (int 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;
+
+ int idx = 0;
+ while (idx < m_strings.size())
+ {
+ if (m_strings[idx].empty())
+ DeleteStringAtIndex(idx);
+ else
+ idx++;
+ }
+}
diff --git a/lldb/source/Core/TTYState.cpp b/lldb/source/Core/TTYState.cpp
new file mode 100644
index 00000000000..6ba415832d4
--- /dev/null
+++ b/lldb/source/Core/TTYState.cpp
@@ -0,0 +1,203 @@
+//===-- TTYState.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/TTYState.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/signal.h>
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+TTYState::TTYState() :
+ m_fd(-1),
+ m_tflags(-1),
+ m_ttystate_err(-1),
+ m_ttystate(),
+ m_process_group(-1)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+TTYState::~TTYState()
+{
+}
+
+//----------------------------------------------------------------------
+// Save the current state of the TTY for the file descriptor "fd"
+// and if "save_process_group" is true, attempt to save the process
+// group info for the TTY.
+//----------------------------------------------------------------------
+bool
+TTYState::Save (int fd, bool save_process_group)
+{
+ if (fd >= 0 && ::isatty (fd))
+ {
+ m_fd = fd;
+ m_tflags = ::fcntl (fd, F_GETFL, 0);
+ m_ttystate_err = ::tcgetattr (fd, &m_ttystate);
+ if (save_process_group)
+ m_process_group = ::tcgetpgrp (0);
+ else
+ m_process_group = -1;
+ }
+ else
+ {
+ m_fd = -1;
+ m_tflags = -1;
+ m_ttystate_err = -1;
+ m_process_group = -1;
+ }
+ return m_ttystate_err == 0;
+}
+
+//----------------------------------------------------------------------
+// Restore the state of the TTY using the cached values from a
+// previous call to Save().
+//----------------------------------------------------------------------
+bool
+TTYState::Restore () const
+{
+ int result = 0;
+ if (IsValid())
+ {
+ if (TFlagsIsValid())
+ result = fcntl (m_fd, F_SETFL, m_tflags);
+
+ if (TTYStateIsValid())
+ result = tcsetattr (m_fd, TCSANOW, &m_ttystate);
+
+ if (ProcessGroupIsValid())
+ {
+ // Save the original signal handler.
+ void (*saved_sigttou_callback) (int) = NULL;
+ saved_sigttou_callback = (void (*)(int)) signal (SIGTTOU, SIG_IGN);
+ // Set the process group
+ result = tcsetpgrp (m_fd, m_process_group);
+ // Restore the original signal handler.
+ signal (SIGTTOU, saved_sigttou_callback);
+ }
+ return true;
+ }
+ return false;
+}
+
+
+
+
+//----------------------------------------------------------------------
+// Returns true if this object has valid saved TTY state settings
+// that can be used to restore a previous state.
+//----------------------------------------------------------------------
+bool
+TTYState::IsValid() const
+{
+ return (m_fd >= 0) && (TFlagsIsValid() || TTYStateIsValid());
+}
+
+//----------------------------------------------------------------------
+// Returns true if m_tflags is valid
+//----------------------------------------------------------------------
+bool
+TTYState::TFlagsIsValid() const
+{
+ return m_tflags != -1;
+}
+
+//----------------------------------------------------------------------
+// Returns true if m_ttystate is valid
+//----------------------------------------------------------------------
+bool
+TTYState::TTYStateIsValid() const
+{
+ return m_ttystate_err == 0;
+}
+
+//----------------------------------------------------------------------
+// Returns true if m_process_group is valid
+//----------------------------------------------------------------------
+bool
+TTYState::ProcessGroupIsValid() const
+{
+ return m_process_group != -1;
+}
+
+//------------------------------------------------------------------
+// Constructor
+//------------------------------------------------------------------
+TTYStateSwitcher::TTYStateSwitcher () :
+ m_currentState(UINT32_MAX)
+{
+}
+
+//------------------------------------------------------------------
+// Destructor
+//------------------------------------------------------------------
+TTYStateSwitcher::~TTYStateSwitcher ()
+{
+}
+
+//------------------------------------------------------------------
+// Returns the number of states that this switcher contains
+//------------------------------------------------------------------
+uint32_t
+TTYStateSwitcher::GetNumberOfStates() const
+{
+ return sizeof(m_ttystates)/sizeof(TTYState);
+}
+
+//------------------------------------------------------------------
+// Restore the state at index "idx".
+//
+// Returns true if the restore was successful, false otherwise.
+//------------------------------------------------------------------
+bool
+TTYStateSwitcher::Restore (uint32_t idx) const
+{
+ const uint32_t num_states = GetNumberOfStates();
+ if (idx >= num_states)
+ return false;
+
+ // See if we already are in this state?
+ if (m_currentState < num_states && (idx == m_currentState) && m_ttystates[idx].IsValid())
+ return true;
+
+ // Set the state to match the index passed in and only update the
+ // current state if there are no errors.
+ if (m_ttystates[idx].Restore())
+ {
+ m_currentState = idx;
+ return true;
+ }
+
+ // We failed to set the state. The tty state was invalid or not
+ // initialized.
+ return false;
+}
+
+//------------------------------------------------------------------
+// Save the state at index "idx" for file descriptor "fd" and
+// save the process group if requested.
+//
+// Returns true if the restore was successful, false otherwise.
+//------------------------------------------------------------------
+bool
+TTYStateSwitcher::Save (uint32_t idx, int fd, bool save_process_group)
+{
+ const uint32_t num_states = GetNumberOfStates();
+ if (idx < num_states)
+ return m_ttystates[idx].Save(fd, save_process_group);
+ return false;
+}
+
+
diff --git a/lldb/source/Core/Timer.cpp b/lldb/source/Core/Timer.cpp
new file mode 100644
index 00000000000..e0d3bab354a
--- /dev/null
+++ b/lldb/source/Core/Timer.cpp
@@ -0,0 +1,235 @@
+//===-- 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 "lldb/Core/Stream.h"
+#include "lldb/Host/Mutex.h"
+
+using namespace lldb_private;
+
+#define TIMER_INDENT_AMOUNT 2
+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> CategoryMap;
+static pthread_key_t g_key;
+
+
+static Mutex &
+GetCategoryMutex()
+{
+ static Mutex g_category_mutex(Mutex::eMutexTypeNormal);
+ return g_category_mutex;
+}
+
+static CategoryMap &
+GetCategoryMap()
+{
+ static CategoryMap 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::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)
+ {
+ // 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();
+ bool notify = false;
+ if (m_total_start.IsValid())
+ {
+ m_total_ticks += (stop_time - m_total_start);
+ m_total_start.Clear();
+ notify = true;
+ }
+ 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;
+ ::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());
+ CategoryMap &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 CategoryMap::const_iterator& lhs, const CategoryMap::const_iterator& rhs)
+{
+ return lhs->second > rhs->second;
+}
+
+
+void
+Timer::ResetCategoryTimes ()
+{
+ Mutex::Locker locker (GetCategoryMutex());
+ CategoryMap &category_map = GetCategoryMap();
+ category_map.clear();
+}
+
+void
+Timer::DumpCategoryTimes (Stream *s)
+{
+ Mutex::Locker locker (GetCategoryMutex());
+ CategoryMap &category_map = GetCategoryMap();
+ std::vector<CategoryMap::const_iterator> sorted_iterators;
+ CategoryMap::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);
+ }
+} \ No newline at end of file
diff --git a/lldb/source/Core/UUID.cpp b/lldb/source/Core/UUID.cpp
new file mode 100644
index 00000000000..1ccfdccfab0
--- /dev/null
+++ b/lldb/source/Core/UUID.cpp
@@ -0,0 +1,218 @@
+//===-- 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
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+
+using namespace lldb_private;
+
+UUID::UUID()
+{
+ ::bzero (m_uuid, sizeof(m_uuid));
+}
+
+UUID::UUID(const UUID& rhs)
+{
+ ::memcpy (m_uuid, rhs.m_uuid, sizeof (m_uuid));
+}
+
+UUID::UUID (const void *uuid_bytes, uint32_t num_uuid_bytes)
+{
+ if (uuid_bytes && num_uuid_bytes >= 16)
+ ::memcpy (m_uuid, uuid_bytes, sizeof (m_uuid));
+ else
+ ::bzero (m_uuid, sizeof(m_uuid));
+}
+
+UUID::UUID (const uuid_t *uuid)
+{
+ if (uuid)
+ ::memcpy (m_uuid, uuid, sizeof (m_uuid));
+ else
+ ::bzero (m_uuid, sizeof(m_uuid));
+}
+
+const UUID&
+UUID::operator=(const UUID& rhs)
+{
+ if (this != &rhs)
+ ::memcpy (m_uuid, rhs.m_uuid, sizeof (m_uuid));
+ return *this;
+}
+
+UUID::~UUID()
+{
+}
+
+void
+UUID::Clear()
+{
+ ::bzero (m_uuid, sizeof(m_uuid));
+}
+
+const void *
+UUID::GetBytes() const
+{
+ return m_uuid;
+}
+
+char *
+UUID::GetAsCString (char *dst, size_t dst_len) const
+{
+ const uint8_t *u = (const uint8_t *)GetBytes();
+ snprintf(dst, dst_len, "%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]);
+ return dst;
+}
+
+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]);
+}
+
+void
+UUID::SetBytes (const void *uuid_bytes)
+{
+ if (uuid_bytes)
+ ::memcpy (m_uuid, uuid_bytes, sizeof (m_uuid));
+ else
+ ::bzero (m_uuid, sizeof(m_uuid));
+}
+
+size_t
+UUID::GetByteSize()
+{
+ return sizeof(UUID::ValueType);
+}
+
+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];
+}
+
+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::SetfromCString (const char *cstr)
+{
+ if (cstr == NULL)
+ return 0;
+
+ uint32_t uuid_byte_idx = 0;
+ const char *p = cstr;
+
+ // Skip leading whitespace characters
+ while (isspace(*p))
+ ++p;
+
+ // Try and decode a UUID
+ while (*p != '\0')
+ {
+ if (isxdigit(*p) && 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
+ m_uuid[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 == 16)
+ break;
+ }
+ else if (*p == '-')
+ {
+ // Skip dashes
+ p++;
+ }
+ else
+ {
+ // UUID values can only consist of hex characters and '-' chars
+ return 0;
+ }
+ }
+ // If we successfully decoded a UUID, return the amount of characters that
+ // were consumed
+ if (uuid_byte_idx == 16)
+ return p - cstr;
+
+ // Else return zero to indicate we were not able to parse a UUID value
+ return 0;
+}
+
+
+
+bool
+lldb_private::operator == (const UUID &lhs, const UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), UUID::GetByteSize()) == 0;
+}
+
+bool
+lldb_private::operator != (const UUID &lhs, const UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), UUID::GetByteSize()) != 0;
+}
+
+bool
+lldb_private::operator < (const UUID &lhs, const UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), UUID::GetByteSize()) < 0;
+}
+
+bool
+lldb_private::operator <= (const UUID &lhs, const UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), UUID::GetByteSize()) <= 0;
+}
+
+bool
+lldb_private::operator > (const UUID &lhs, const UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), UUID::GetByteSize()) > 0;
+}
+
+bool
+lldb_private::operator >= (const UUID &lhs, const UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), UUID::GetByteSize()) >= 0;
+}
diff --git a/lldb/source/Core/UserID.cpp b/lldb/source/Core/UserID.cpp
new file mode 100644
index 00000000000..b1dd5a618c1
--- /dev/null
+++ b/lldb/source/Core/UserID.cpp
@@ -0,0 +1,73 @@
+//===-- 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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UserID::UserID (user_id_t uid) :
+ m_uid(uid)
+{
+}
+
+UserID::~UserID ()
+{
+}
+
+void
+UserID::Clear ()
+{
+ m_uid = LLDB_INVALID_UID;
+}
+
+
+user_id_t
+UserID::GetID () const
+{
+ return m_uid;
+}
+
+void
+UserID::SetID (user_id_t uid)
+{
+ m_uid = uid;
+}
+
+UserID::IDMatches::IDMatches (user_id_t uid) :
+ m_uid(uid)
+{
+}
+
+bool
+UserID::IDMatches::operator() (const UserID& rhs) const
+{
+ return m_uid == rhs.GetID();
+}
+
+Stream&
+lldb_private::operator << (Stream& strm, const UserID& uid)
+{
+ strm.Printf("{0x%8.8x}", uid.GetID());
+ return strm;
+}
+
+bool
+lldb_private::operator== (const UserID& lhs, const UserID& rhs)
+{
+ return lhs.GetID() == rhs.GetID();
+}
+
+bool
+lldb_private::operator!= (const UserID& lhs, const UserID& rhs)
+{
+ return lhs.GetID() != rhs.GetID();
+}
+
diff --git a/lldb/source/Core/VMRange.cpp b/lldb/source/Core/VMRange.cpp
new file mode 100644
index 00000000000..2f5d8ecf9ab
--- /dev/null
+++ b/lldb/source/Core/VMRange.cpp
@@ -0,0 +1,100 @@
+//===-- 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"
+
+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;
+}
+
+
+void
+VMRange::Dump(Stream *s, lldb::addr_t offset) const
+{
+ s->AddressRange(offset + GetBaseAddress(), offset + GetEndAddress(), sizeof (addr_t));
+}
+
+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/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp
new file mode 100644
index 00000000000..c4c17dd0428
--- /dev/null
+++ b/lldb/source/Core/Value.cpp
@@ -0,0 +1,803 @@
+//===-- 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/Stream.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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Value::Value() :
+ m_value(),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(const Scalar& scalar) :
+ m_value(scalar),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(int v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(unsigned int v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(long v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(unsigned long v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(long long v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(unsigned long long v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(float v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(double v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(long double v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(const uint8_t *bytes, int len) :
+ m_value(),
+ m_value_type(eValueTypeHostAddress),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+ 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_value_type(v.m_value_type),
+ m_context(v.m_context),
+ m_context_type(v.m_context_type)
+{
+ 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::CreateProxy()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->CreateProxy ();
+
+ Value *ret = new Value;
+ ret->SetContext(eContextTypeValue, this);
+ return ret;
+}
+
+Value *
+Value::GetProxyTarget()
+{
+ if (m_context_type == eContextTypeValue)
+ return (Value*)m_context;
+ else
+ return NULL;
+}
+
+//#include "clang/Lex/LiteralSupport.h"
+//#include "clang/AST/ASTContext.h"
+//#include "clang/Frontend/CompilerInstance.h"
+//
+//Value::Value (const char *data, llvm::CompilerInstance *compiler)
+//{
+// clang::NumericLiteralParser parser(data, data + strlen(data), clang::SourceLocation(),
+// compiler->getPreprocessor());
+// if (parser.had_error)
+// {
+// }
+// else if (parser.isBool)
+// {
+// APInt value;
+// parser.GetIntegerValue(value);
+// }
+// else if (parser.isLong)
+// {
+// }
+// else if (parser.isLongLong)
+// {
+// }
+// else if (parser.isFloat)
+// {
+// }
+//
+//}
+//
+void
+Value::Dump (Stream* strm)
+{
+ if (m_context_type == eContextTypeValue)
+ {
+ ((Value*)m_context)->Dump (strm);
+ return;
+ }
+
+ 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));
+}
+
+void *
+Value::GetOpaqueClangQualType()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetOpaqueClangQualType ();
+
+ if (m_context_type == eContextTypeOpaqueClangQualType)
+ return m_context;
+
+ return NULL;
+}
+
+Value::ValueType
+Value::GetValueType() const
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetValueType ();
+
+ return m_value_type;
+}
+
+lldb::AddressType
+Value::GetValueAddressType () const
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetValueAddressType ();
+
+ switch (m_value_type)
+ {
+ default:
+ case eValueTypeScalar:
+ break;
+ case eValueTypeLoadAddress: return eAddressTypeLoad;
+ case eValueTypeFileAddress: return eAddressTypeFile;
+ case eValueTypeHostAddress: return eAddressTypeHost;
+ }
+ return eAddressTypeInvalid;
+}
+
+
+Value::ContextType
+Value::GetContextType() const
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetContextType ();
+
+ return m_context_type;
+}
+
+void
+Value::SetValueType (Value::ValueType value_type)
+{
+ if (m_context_type == eContextTypeValue)
+ {
+ ((Value*)m_context)->SetValueType(value_type);
+ return;
+ }
+
+ m_value_type = value_type;
+}
+
+void
+Value::ClearContext ()
+{
+ if (m_context_type == eContextTypeValue)
+ {
+ ((Value*)m_context)->ClearContext();
+ return;
+ }
+
+ m_context = NULL;
+ m_context_type = eContextTypeInvalid;
+}
+
+void
+Value::SetContext (Value::ContextType context_type, void *p)
+{
+ if (m_context_type == eContextTypeValue)
+ {
+ ((Value*)m_context)->SetContext(context_type, p);
+ return;
+ }
+
+ m_context_type = context_type;
+ m_context = p;
+}
+
+RegisterInfo *
+Value::GetRegisterInfo()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetRegisterInfo();
+
+ if (m_context_type == eContextTypeDCRegisterInfo)
+ return static_cast<RegisterInfo *> (m_context);
+ return NULL;
+}
+
+Type *
+Value::GetType()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetType();
+
+ if (m_context_type == eContextTypeDCType)
+ return static_cast<Type *> (m_context);
+ return NULL;
+}
+
+Scalar &
+Value::GetScalar()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetScalar();
+
+ return m_value;
+}
+
+void
+Value::ResizeData(int len)
+{
+ if (m_context_type == eContextTypeValue)
+ {
+ ((Value*)m_context)->ResizeData(len);
+ return;
+ }
+
+ m_value_type = eValueTypeHostAddress;
+ m_data_buffer.SetByteSize(len);
+ m_value = (uintptr_t)m_data_buffer.GetBytes();
+}
+
+bool
+Value::ValueOf(ExecutionContext *exe_ctx, clang::ASTContext *ast_context)
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->ValueOf(exe_ctx, ast_context);
+
+ switch (m_context_type)
+ {
+ default:
+ case eContextTypeInvalid:
+ case eContextTypeOpaqueClangQualType: // clang::Type *
+ case eContextTypeDCRegisterInfo: // RegisterInfo *
+ case eContextTypeDCType: // Type *
+ break;
+
+ case eContextTypeDCVariable: // Variable *
+ ResolveValue(exe_ctx, ast_context);
+ return true;
+ }
+ return false;
+}
+
+size_t
+Value::GetValueByteSize (clang::ASTContext *ast_context, Error *error_ptr)
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetValueByteSize(ast_context, error_ptr);
+
+ size_t byte_size = 0;
+
+ switch (m_context_type)
+ {
+ default:
+ case eContextTypeInvalid:
+ // If we have no context, there is no way to know how much memory to read
+ if (error_ptr)
+ error_ptr->SetErrorString ("Invalid context type, there is no way to know how much memory to read.");
+ break;
+
+ case eContextTypeOpaqueClangQualType:
+ if (ast_context == NULL)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("Can't determine size of opaque clang type with NULL ASTContext *.");
+ }
+ else
+ {
+ uint64_t bit_width = ClangASTContext::GetTypeBitSize (ast_context, m_context);
+ byte_size = (bit_width + 7 ) / 8;
+ }
+ break;
+
+ case eContextTypeDCRegisterInfo: // RegisterInfo *
+ if (GetRegisterInfo())
+ byte_size = GetRegisterInfo()->byte_size;
+ else if (error_ptr)
+ error_ptr->SetErrorString ("Can't determine byte size with NULL RegisterInfo *.");
+
+ break;
+
+ case eContextTypeDCType: // Type *
+ if (GetType())
+ byte_size = GetType()->GetByteSize();
+ else if (error_ptr)
+ error_ptr->SetErrorString ("Can't determine byte size with NULL Type *.");
+ break;
+
+ case eContextTypeDCVariable: // Variable *
+ if (GetVariable())
+ byte_size = GetVariable()->GetType()->GetByteSize();
+ else if (error_ptr)
+ error_ptr->SetErrorString ("Can't determine byte size with NULL Variable *.");
+ 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;
+}
+
+void *
+Value::GetValueOpaqueClangQualType ()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetValueOpaqueClangQualType();
+
+ switch (m_context_type)
+ {
+ default:
+ case eContextTypeInvalid:
+ break;
+
+ case eContextTypeOpaqueClangQualType:
+ return m_context;
+
+ case eContextTypeDCRegisterInfo:
+ break; // TODO: Eventually convert into a clang type?
+
+ case eContextTypeDCType:
+ if (GetType())
+ return GetType()->GetOpaqueClangQualType();
+ break;
+
+ case eContextTypeDCVariable:
+ if (GetVariable())
+ return GetVariable()->GetType()->GetOpaqueClangQualType();
+ break;
+ }
+
+ return NULL;
+}
+
+lldb::Format
+Value::GetValueDefaultFormat ()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetValueDefaultFormat();
+
+ switch (m_context_type)
+ {
+ default:
+ case eContextTypeInvalid:
+ break;
+
+ case eContextTypeOpaqueClangQualType:
+ return Type::GetFormat (m_context);
+
+ case eContextTypeDCRegisterInfo:
+ if (GetRegisterInfo())
+ return GetRegisterInfo()->format;
+ break;
+
+ case eContextTypeDCType:
+ if (GetType())
+ return GetType()->GetFormat();
+ break;
+
+ case eContextTypeDCVariable:
+ if (GetVariable())
+ return GetVariable()->GetType()->GetFormat();
+ break;
+
+ }
+
+ // Return a good default in case we can't figure anything out
+ return eFormatHex;
+}
+
+Error
+Value::GetValueAsData (ExecutionContext *exe_ctx, clang::ASTContext *ast_context, DataExtractor &data, uint32_t data_offset)
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetValueAsData(exe_ctx, ast_context, data, data_offset);
+
+ data.Clear();
+
+ Error error;
+ lldb::addr_t address = LLDB_INVALID_ADDRESS;
+ lldb::AddressType address_type = eAddressTypeFile;
+ switch (m_value_type)
+ {
+ default:
+ error.SetErrorStringWithFormat("Invalid value type %i.\n", m_value_type);
+ break;
+
+ case eValueTypeScalar:
+ data.SetByteOrder (eByteOrderHost);
+ data.SetAddressByteSize(sizeof(void *));
+ if (m_value.GetData (data))
+ return error; // Success;
+ error.SetErrorStringWithFormat("Extracting data from value failed.\n");
+ break;
+
+ case eValueTypeLoadAddress:
+ if (exe_ctx == NULL)
+ {
+ error.SetErrorString ("Can't read memory (no execution context).");
+ }
+ else if (exe_ctx->process == NULL)
+ {
+ error.SetErrorString ("Can't read memory (invalid process).");
+ }
+ else
+ {
+ address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ address_type = eAddressTypeLoad;
+ data.SetByteOrder(exe_ctx->process->GetByteOrder());
+ data.SetAddressByteSize(exe_ctx->process->GetAddressByteSize());
+ }
+ break;
+
+ case eValueTypeFileAddress:
+ {
+ // 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 (GetVariable())
+ {
+ lldb::addr_t file_addr = m_value.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());
+ address = so_addr.GetLoadAddress (exe_ctx->process);
+ if (address != LLDB_INVALID_ADDRESS)
+ address_type = eAddressTypeLoad;
+ }
+ if (address_type == eAddressTypeFile)
+ error.SetErrorStringWithFormat ("%s is not loaded.\n", var_sc.module_sp->GetFileSpec().GetFilename().AsCString());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Unable to resolve the module for file address 0x%llx for variable '%s'.\n", file_addr, variable->GetName().AsCString(""));
+ }
+ }
+ else
+ {
+ error.SetErrorString ("Invalid file 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);
+ data.SetByteOrder(eByteOrderHost);
+ data.SetAddressByteSize(sizeof(void *));
+ address_type = eAddressTypeHost;
+ break;
+ }
+
+ // Bail if we encountered any errors
+ if (error.Fail())
+ return error;
+
+ if (address == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorStringWithFormat ("Invalid %s address.\n", address_type == eAddressTypeHost ? "host" : "load");
+ return error;
+ }
+
+ // If we got here, we need to read the value from memory
+ uint32_t byte_size = GetValueByteSize (ast_context, &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 = (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)
+ {
+ if (exe_ctx->process->ReadMemory(address, dst, byte_size, error) != byte_size)
+ {
+ if (error.Success())
+ error.SetErrorStringWithFormat("read %u bytes of memory from 0x%llx failed", (uint64_t)address, byte_size);
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Unsupported lldb::AddressType value (%i).\n", address_type);
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Out of memory.\n");
+ }
+
+ return error;
+}
+
+Scalar &
+Value::ResolveValue(ExecutionContext *exe_ctx, clang::ASTContext *ast_context)
+{
+ Scalar scalar;
+ if (m_context_type == eContextTypeValue)
+ {
+ // Resolve the proxy
+
+ Value * v = (Value*)m_context;
+
+ m_value = v->m_value;
+ m_value_type = v->m_value_type;
+ m_context = v->m_context;
+ m_context_type = v->m_context_type;
+
+ 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();
+ }
+ }
+
+ if (m_context_type == eContextTypeOpaqueClangQualType)
+ {
+ void *opaque_clang_qual_type = GetOpaqueClangQualType();
+ switch (m_value_type)
+ {
+ case eValueTypeScalar: // raw scalar value
+ break;
+
+ default:
+ case eValueTypeFileAddress:
+ m_value.Clear();
+ break;
+
+ case eValueTypeLoadAddress: // load address value
+ case eValueTypeHostAddress: // host address value (for memory in the process that is using liblldb)
+ {
+ lldb::AddressType address_type = m_value_type == eValueTypeLoadAddress ? eAddressTypeLoad : eAddressTypeHost;
+ lldb::addr_t addr = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ DataExtractor data;
+ if (Type::ReadFromMemory (exe_ctx, ast_context, opaque_clang_qual_type, addr, address_type, data))
+ {
+ if (Type::GetValueAsScalar (ast_context, opaque_clang_qual_type, 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 == eContextTypeValue)
+ return ((Value*)m_context)->GetVariable();
+
+ if (m_context_type == eContextTypeDCVariable)
+ return static_cast<Variable *> (m_context);
+ return NULL;
+}
+
+
+
+const char *
+Value::GetValueTypeAsCString (ValueType value_type)
+{
+ switch (value_type)
+ {
+ case eValueTypeScalar: return "scalar";
+ 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 eContextTypeOpaqueClangQualType: return "clang::Type *";
+ case eContextTypeDCRegisterInfo: return "RegisterInfo *";
+ case eContextTypeDCType: return "Type *";
+ case eContextTypeDCVariable: 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/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
new file mode 100644
index 00000000000..93511febe8a
--- /dev/null
+++ b/lldb/source/Core/ValueObject.cpp
@@ -0,0 +1,678 @@
+//===-- 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/Core/ValueObject.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "clang/AST/Type.h"
+#include "llvm/Support/raw_ostream.h"
+
+// Project includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Core/ValueObjectList.h"
+
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Type.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static lldb::user_id_t g_value_obj_uid = 0;
+
+//----------------------------------------------------------------------
+// ValueObject constructor
+//----------------------------------------------------------------------
+ValueObject::ValueObject () :
+ UserID (++g_value_obj_uid), // Unique identifier for every value object
+ m_update_id (0), // Value object lists always start at 1, value objects start at zero
+ m_name (),
+ m_data (),
+ m_value (),
+ m_error (),
+ m_flags (),
+ m_value_str(),
+ m_location_str(),
+ m_summary_str(),
+ m_children(),
+ m_synthetic_children()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ValueObject::~ValueObject ()
+{
+}
+
+user_id_t
+ValueObject::GetUpdateID() const
+{
+ return m_update_id;
+}
+
+bool
+ValueObject::UpdateValueIfNeeded (ExecutionContextScope *exe_scope)
+{
+ if (exe_scope)
+ {
+ Process *process = exe_scope->CalculateProcess();
+ if (process)
+ {
+ const user_id_t stop_id = process->GetStopID();
+ if (m_update_id != stop_id)
+ {
+ m_value_str.clear();
+ m_location_str.clear();
+ m_summary_str.clear();
+
+ UpdateValue (exe_scope);
+ if (m_error.Success())
+ m_update_id = stop_id;
+ }
+ }
+ }
+ return m_error.Success();
+}
+
+const DataExtractor &
+ValueObject::GetDataExtractor () const
+{
+ return m_data;
+}
+
+DataExtractor &
+ValueObject::GetDataExtractor ()
+{
+ return m_data;
+}
+
+const Error &
+ValueObject::GetError() const
+{
+ return m_error;
+}
+
+const ConstString &
+ValueObject::GetName() const
+{
+ return m_name;
+}
+
+const char *
+ValueObject::GetLocationAsCString (ExecutionContextScope *exe_scope)
+{
+ if (UpdateValueIfNeeded(exe_scope))
+ {
+ if (m_location_str.empty())
+ {
+ StreamString sstr;
+
+ switch (m_value.GetValueType())
+ {
+ default:
+ break;
+
+ case Value::eValueTypeScalar:
+ if (m_value.GetContextType() == Value::eContextTypeDCRegisterInfo)
+ {
+ RegisterInfo *reg_info = m_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;
+ break;
+ }
+ }
+ m_location_str = "scalar";
+ break;
+
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeHostAddress:
+ {
+ uint32_t addr_nibble_size = m_data.GetAddressByteSize() * 2;
+ sstr.Printf("0x%*.*llx", addr_nibble_size, addr_nibble_size, m_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::GetValueIsValid ()
+{
+ return m_flags.IsSet(eValueIsValid);
+}
+
+
+void
+ValueObject::SetValueIsValid (bool b)
+{
+ if (b)
+ m_flags.Set(eValueIsValid);
+ else
+ m_flags.Clear(eValueIsValid);
+}
+
+bool
+ValueObject::GetValueDidChange () const
+{
+ return m_flags.IsSet(eValueChanged);
+}
+
+void
+ValueObject::SetValueDidChange (bool value_changed)
+{
+ m_flags.Set(eValueChanged);
+}
+
+ValueObjectSP
+ValueObject::GetChildAtIndex (uint32_t idx, bool can_create)
+{
+ ValueObjectSP child_sp;
+ if (idx < GetNumChildren())
+ {
+ // Check if we have already made the child value object?
+ if (can_create && m_children[idx].get() == NULL)
+ {
+ // 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[idx] = CreateChildAtIndex (idx, false, 0);
+ }
+
+ child_sp = m_children[idx];
+ }
+ return child_sp;
+}
+
+uint32_t
+ValueObject::GetIndexOfChildWithName (const ConstString &name)
+{
+ bool omit_empty_base_classes = true;
+ return ClangASTContext::GetIndexOfChildWithName (GetClangAST(),
+ GetOpaqueClangQualType(),
+ name.AsCString(),
+ omit_empty_base_classes);
+}
+
+ValueObjectSP
+ValueObject::GetChildMemberWithName (const ConstString &name, bool can_create)
+{
+ // when getting a child by name, it could be burried 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
+ std::vector<uint32_t> child_indexes;
+ clang::ASTContext *clang_ast = GetClangAST();
+ void *clang_type = GetOpaqueClangQualType();
+ bool omit_empty_base_classes = true;
+ const size_t num_child_indexes = ClangASTContext::GetIndexOfChildMemberWithName (clang_ast,
+ clang_type,
+ name.AsCString(),
+ omit_empty_base_classes,
+ child_indexes);
+ ValueObjectSP child_sp;
+ 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;
+}
+
+
+uint32_t
+ValueObject::GetNumChildren ()
+{
+ if (m_flags.IsClear(eNumChildrenHasBeenSet))
+ {
+ SetNumChildren (CalculateNumChildren());
+ }
+ return m_children.size();
+}
+void
+ValueObject::SetNumChildren (uint32_t num_children)
+{
+ m_flags.Set(eNumChildrenHasBeenSet);
+ m_children.resize(num_children);
+}
+
+void
+ValueObject::SetName (const char *name)
+{
+ m_name.SetCString(name);
+}
+
+void
+ValueObject::SetName (const ConstString &name)
+{
+ m_name = name;
+}
+
+ValueObjectSP
+ValueObject::CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ ValueObjectSP valobj_sp;
+ bool omit_empty_base_classes = true;
+
+ 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;
+ const bool transparent_pointers = synthetic_array_member == false;
+ clang::ASTContext *clang_ast = GetClangAST();
+ void *clang_type = GetOpaqueClangQualType();
+ void *child_clang_type;
+ child_clang_type = ClangASTContext::GetChildClangTypeAtIndex (clang_ast,
+ GetName().AsCString(),
+ clang_type,
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ child_name_str,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset);
+ 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_sp.reset (new ValueObjectChild (this,
+ clang_ast,
+ child_clang_type,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset));
+ }
+ return valobj_sp;
+}
+
+const char *
+ValueObject::GetSummaryAsCString (ExecutionContextScope *exe_scope)
+{
+ if (UpdateValueIfNeeded (exe_scope))
+ {
+ if (m_summary_str.empty())
+ {
+ void *clang_type = GetOpaqueClangQualType();
+
+ // See if this is a pointer to a C string?
+ uint32_t fixed_length = 0;
+ if (clang_type && ClangASTContext::IsCStringType (clang_type, fixed_length))
+ {
+ Process *process = exe_scope->CalculateProcess();
+ if (process != NULL)
+ {
+ StreamString sstr;
+ lldb::addr_t cstr_address = LLDB_INVALID_ADDRESS;
+ lldb::AddressType cstr_address_type = eAddressTypeInvalid;
+ switch (GetValue().GetValueType())
+ {
+ case Value::eValueTypeScalar:
+ cstr_address = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ cstr_address_type = eAddressTypeLoad;
+ break;
+
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeHostAddress:
+ {
+ uint32_t data_offset = 0;
+ cstr_address = m_data.GetPointer(&data_offset);
+ cstr_address_type = m_value.GetValueAddressType();
+ if (cstr_address_type == eAddressTypeInvalid)
+ cstr_address_type = eAddressTypeLoad;
+ }
+ break;
+ }
+
+ if (cstr_address != LLDB_INVALID_ADDRESS)
+ {
+ DataExtractor data;
+ size_t bytes_read = 0;
+ std::vector<char> data_buffer;
+ std::vector<char> cstr_buffer;
+ size_t cstr_length;
+ Error error;
+ if (fixed_length > 0)
+ {
+ data_buffer.resize(fixed_length);
+ // Resize the formatted buffer in case every character
+ // uses the "\xXX" format and one extra byte for a NULL
+ cstr_buffer.resize(data_buffer.size() * 4 + 1);
+ data.SetData (data_buffer.data(), data_buffer.size(), eByteOrderHost);
+ bytes_read = process->ReadMemory (cstr_address, data_buffer.data(), fixed_length, error);
+ if (bytes_read > 0)
+ {
+ sstr << '"';
+ cstr_length = data.Dump (&sstr,
+ 0, // Start offset in "data"
+ eFormatChar, // Print as characters
+ 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
+ sstr << '"';
+ }
+ }
+ else
+ {
+ const size_t k_max_buf_size = 256;
+ data_buffer.resize (k_max_buf_size + 1);
+ // NULL terminate in case we don't get the entire C string
+ data_buffer.back() = '\0';
+ // Make a formatted buffer that can contain take 4
+ // bytes per character in case each byte uses the
+ // "\xXX" format and one extra byte for a NULL
+ cstr_buffer.resize (k_max_buf_size * 4 + 1);
+
+ data.SetData (data_buffer.data(), data_buffer.size(), eByteOrderHost);
+ size_t total_cstr_len = 0;
+ while ((bytes_read = process->ReadMemory (cstr_address, data_buffer.data(), k_max_buf_size, error)) > 0)
+ {
+ size_t len = strlen(data_buffer.data());
+ if (len == 0)
+ break;
+ if (len > bytes_read)
+ len = bytes_read;
+ if (sstr.GetSize() == 0)
+ sstr << '"';
+
+ cstr_length = data.Dump (&sstr,
+ 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
+
+ if (len < k_max_buf_size)
+ break;
+ cstr_address += total_cstr_len;
+ }
+ if (sstr.GetSize() > 0)
+ sstr << '"';
+ }
+
+ if (sstr.GetSize() > 0)
+ m_summary_str.assign (sstr.GetData(), sstr.GetSize());
+ }
+ }
+ }
+ }
+ }
+ if (m_summary_str.empty())
+ return NULL;
+ return m_summary_str.c_str();
+}
+
+
+const char *
+ValueObject::GetValueAsCString (ExecutionContextScope *exe_scope)
+{
+ // If our byte size is zero this is an aggregate type that has children
+ if (ClangASTContext::IsAggregateType (GetOpaqueClangQualType()) == false)
+ {
+ if (UpdateValueIfNeeded(exe_scope))
+ {
+ if (m_value_str.empty())
+ {
+ const Value::ContextType context_type = m_value.GetContextType();
+
+ switch (context_type)
+ {
+ case Value::eContextTypeOpaqueClangQualType:
+ case Value::eContextTypeDCType:
+ case Value::eContextTypeDCVariable:
+ {
+ void *clang_type = GetOpaqueClangQualType ();
+ if (clang_type)
+ {
+ StreamString sstr;
+ lldb::Format format = Type::GetFormat(clang_type);
+ if (Type::DumpTypeValue(&sstr,
+ GetClangAST(), // The clang AST
+ clang_type, // The clang type to display
+ format, // Format to display this type with
+ 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
+ m_value_str.swap(sstr.GetString());
+ else
+ m_value_str.clear();
+ }
+ }
+ break;
+
+ case Value::eContextTypeDCRegisterInfo:
+ {
+ const RegisterInfo *reg_info = m_value.GetRegisterInfo();
+ if (reg_info)
+ {
+ StreamString reg_sstr;
+ m_data.Dump(&reg_sstr, 0, reg_info->format, reg_info->byte_size, 1, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0);
+ m_value_str.swap(reg_sstr.GetString());
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (m_value_str.empty())
+ return NULL;
+ return m_value_str.c_str();
+}
+
+bool
+ValueObject::SetValueFromCString (ExecutionContextScope *exe_scope, const char *value_str)
+{
+ // Make sure our value is up to date first so that our location and location
+ // type is valid.
+ if (!UpdateValueIfNeeded(exe_scope))
+ return false;
+
+ uint32_t count = 0;
+ lldb::Encoding encoding = Type::GetEncoding (GetOpaqueClangQualType(), count);
+
+ char *end = NULL;
+ size_t byte_size = GetByteSize();
+ switch (encoding)
+ {
+ case eEncodingInvalid:
+ return false;
+
+ case eEncodingUint:
+ if (byte_size > sizeof(unsigned long long))
+ {
+ return false;
+ }
+ else
+ {
+ unsigned long long ull_val = strtoull(value_str, &end, 0);
+ if (end && *end != '\0')
+ return false;
+ m_value = ull_val;
+ // Limit the bytes in our m_data appropriately.
+ m_value.GetScalar().GetData (m_data, byte_size);
+ }
+ break;
+
+ case eEncodingSint:
+ if (byte_size > sizeof(long long))
+ {
+ return false;
+ }
+ else
+ {
+ long long sll_val = strtoll(value_str, &end, 0);
+ if (end && *end != '\0')
+ return false;
+ m_value = sll_val;
+ // Limit the bytes in our m_data appropriately.
+ m_value.GetScalar().GetData (m_data, byte_size);
+ }
+ break;
+
+ case eEncodingIEEE754:
+ {
+ const size_t byte_size = GetByteSize();
+ const off_t byte_offset = GetByteOffset();
+ uint8_t *dst = (uint8_t *)m_data.PeekData(byte_offset, byte_size);
+ if (dst != NULL)
+ {
+ // We are decoding a float into host byte order below, so make
+ // sure m_data knows what it contains.
+ m_data.SetByteOrder(eByteOrderHost);
+ const size_t converted_byte_size = ClangASTContext::ConvertStringToFloatValue (
+ GetClangAST(),
+ GetOpaqueClangQualType(),
+ value_str,
+ dst,
+ byte_size);
+
+ if (converted_byte_size == byte_size)
+ {
+ }
+ }
+ }
+ break;
+
+ case eEncodingVector:
+ return false;
+
+ default:
+ return false;
+ }
+
+ // If we have made it here the value is in m_data and we should write it
+ // out to the target
+ return Write ();
+}
+
+bool
+ValueObject::Write ()
+{
+ // Clear the update ID so the next time we try and read the value
+ // we try and read it again.
+ m_update_id = 0;
+
+ // TODO: when Value has a method to write a value back, call it from here.
+ return false;
+
+}
+
+void
+ValueObject::AddSyntheticChild (const ConstString &key, ValueObjectSP& valobj_sp)
+{
+ m_synthetic_children[key] = valobj_sp;
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticChild (const ConstString &key) const
+{
+ ValueObjectSP synthetic_child_sp;
+ std::map<ConstString, ValueObjectSP>::const_iterator pos = m_synthetic_children.find (key);
+ if (pos != m_synthetic_children.end())
+ synthetic_child_sp = pos->second;
+ return synthetic_child_sp;
+}
+
+bool
+ValueObject::IsPointerType ()
+{
+ return ClangASTContext::IsPointerType (GetOpaqueClangQualType());
+}
+
+bool
+ValueObject::IsPointerOrReferenceType ()
+{
+ return ClangASTContext::IsPointerOrReferenceType(GetOpaqueClangQualType());
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticArrayMemberFromPointer (int32_t index, bool can_create)
+{
+ ValueObjectSP synthetic_child_sp;
+ if (IsPointerType ())
+ {
+ char index_str[64];
+ snprintf(index_str, sizeof(index_str), "[%i]", 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)
+ {
+ // We haven't made a synthetic array member for INDEX yet, so
+ // lets make one and cache it for any future reference.
+ synthetic_child_sp = CreateChildAtIndex(0, true, index);
+
+ // Cache the value if we got one back...
+ if (synthetic_child_sp)
+ AddSyntheticChild(index_const_str, synthetic_child_sp);
+ }
+ }
+ return synthetic_child_sp;
+}
diff --git a/lldb/source/Core/ValueObjectChild.cpp b/lldb/source/Core/ValueObjectChild.cpp
new file mode 100644
index 00000000000..dc10bb09b4c
--- /dev/null
+++ b/lldb/source/Core/ValueObjectChild.cpp
@@ -0,0 +1,207 @@
+//===-- 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/dwarf.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.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,
+ clang::ASTContext *clang_ast,
+ void *clang_type,
+ const ConstString &name,
+ uint32_t byte_size,
+ int32_t byte_offset,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset
+) :
+ ValueObject (),
+ m_parent (parent),
+ m_clang_ast (clang_ast),
+ 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_name = name;
+}
+
+ValueObjectChild::~ValueObjectChild()
+{
+}
+
+void *
+ValueObjectChild::GetOpaqueClangQualType()
+{
+ return m_clang_type;
+}
+
+lldb::ValueType
+ValueObjectChild::GetValueType() const
+{
+ return m_parent->GetValueType();
+}
+
+uint32_t
+ValueObjectChild::CalculateNumChildren()
+{
+ return ClangASTContext::GetNumChildren (m_clang_type, true);
+}
+
+clang::ASTContext *
+ValueObjectChild::GetClangAST ()
+{
+ return m_clang_ast;
+}
+
+size_t
+ValueObjectChild::GetByteSize()
+{
+ return m_byte_size;
+}
+
+off_t
+ValueObjectChild::GetByteOffset()
+{
+ return m_byte_offset;
+}
+
+uint32_t
+ValueObjectChild::GetBitfieldBitSize()
+{
+ return m_bitfield_bit_size;
+}
+
+uint32_t
+ValueObjectChild::GetBitfieldBitOffset()
+{
+ return m_bitfield_bit_offset;
+}
+
+ConstString
+ValueObjectChild::GetTypeName()
+{
+ if (m_type_name.IsEmpty())
+ {
+ m_type_name = Type::GetClangTypeName (GetOpaqueClangQualType());
+ if (m_type_name)
+ {
+ if (m_bitfield_bit_size > 0)
+ {
+ const char *clang_type_name = m_type_name.AsCString();
+ if (clang_type_name)
+ {
+ char bitfield_type_name[strlen(clang_type_name) + 32];
+ ::snprintf (bitfield_type_name, sizeof(bitfield_type_name), "%s:%u", clang_type_name, m_bitfield_bit_size);
+ m_type_name.SetCString(bitfield_type_name);
+ }
+ }
+ }
+ }
+ return m_type_name;
+}
+
+void
+ValueObjectChild::UpdateValue (ExecutionContextScope *exe_scope)
+{
+ m_error.Clear();
+ SetValueIsValid (false);
+ ValueObject* parent = m_parent;
+ if (parent)
+ {
+ if (parent->UpdateValueIfNeeded(exe_scope))
+ {
+ m_value.SetContext(Value::eContextTypeOpaqueClangQualType, m_clang_type);
+
+ // 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 (ClangASTContext::IsPointerOrReferenceType (parent->GetOpaqueClangQualType()))
+ {
+ uint32_t offset = 0;
+ m_value.GetScalar() = parent->GetDataExtractor().GetPointer(&offset);
+ // For pointers, m_byte_offset should only ever be set if we
+ // ValueObject::GetSyntheticArrayMemberFromPointer() was called
+ if (ClangASTContext::IsPointerType (parent->GetOpaqueClangQualType()) && m_byte_offset)
+ m_value.GetScalar() += m_byte_offset;
+ if (value_type == Value::eValueTypeScalar ||
+ value_type == Value::eValueTypeFileAddress)
+ m_value.SetValueType (Value::eValueTypeLoadAddress);
+ }
+ 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 || addr == 0)
+ {
+ m_error.SetErrorStringWithFormat("Parent address is invalid: 0x%llx.\n", addr);
+ break;
+ }
+ // Set this object's scalar value to the address of its
+ // value be 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 (exe_scope);
+ m_error = m_value.GetValueAsData (&exe_ctx, GetClangAST (), m_data, 0);
+ }
+ }
+ else
+ {
+ m_error.SetErrorStringWithFormat("Parent failed to evaluate: %s.\n", parent->GetError().AsCString());
+ }
+ }
+ else
+ {
+ m_error.SetErrorString("ValueObjectChild has a NULL parent ValueObject.");
+ }
+}
+
+
+bool
+ValueObjectChild::IsInScope (StackFrame *frame)
+{
+ return m_parent->IsInScope (frame);
+}
+
diff --git a/lldb/source/Core/ValueObjectList.cpp b/lldb/source/Core/ValueObjectList.cpp
new file mode 100644
index 00000000000..50ae1de0985
--- /dev/null
+++ b/lldb/source/Core/ValueObjectList.cpp
@@ -0,0 +1,119 @@
+//===-- 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);
+}
+
+uint32_t
+ValueObjectList::GetSize() const
+{
+ return m_value_objects.size();
+}
+
+lldb::ValueObjectSP
+ValueObjectList::GetValueObjectAtIndex (uint32_t idx)
+{
+ lldb::ValueObjectSP valobj_sp;
+ if (idx < m_value_objects.size())
+ valobj_sp = m_value_objects[idx];
+ return 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)
+ {
+ if ((*pos)->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)
+ {
+ if ((*pos)->GetID() == uid)
+ {
+ valobj_sp = *pos;
+ break;
+ }
+ }
+ return valobj_sp;
+}
+
+
+ValueObjectSP
+ValueObjectList::FindValueObjectByPointer (ValueObject *valobj)
+{
+ ValueObjectSP valobj_sp;
+ collection::iterator pos, end = m_value_objects.end();
+
+ for (pos = m_value_objects.begin(); pos != end; ++pos)
+ {
+ if ((*pos).get() == valobj)
+ {
+ valobj_sp = *pos;
+ break;
+ }
+ }
+ return valobj_sp;
+}
diff --git a/lldb/source/Core/ValueObjectRegister.cpp b/lldb/source/Core/ValueObjectRegister.cpp
new file mode 100644
index 00000000000..aae818eadd6
--- /dev/null
+++ b/lldb/source/Core/ValueObjectRegister.cpp
@@ -0,0 +1,331 @@
+//===-- 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/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 (RegisterContext *reg_ctx) :
+ ValueObject (),
+ m_reg_ctx (reg_ctx)
+{
+ assert (reg_ctx);
+ m_name.SetCString("Registers");
+ SetValueIsValid (true);
+}
+
+ValueObjectRegisterContext::~ValueObjectRegisterContext()
+{
+}
+
+void *
+ValueObjectRegisterContext::GetOpaqueClangQualType ()
+{
+ return NULL;
+}
+
+ConstString
+ValueObjectRegisterContext::GetTypeName()
+{
+ ConstString empty_type_name;
+ return empty_type_name;
+}
+
+uint32_t
+ValueObjectRegisterContext::CalculateNumChildren()
+{
+ return m_reg_ctx->GetRegisterSetCount();
+}
+
+clang::ASTContext *
+ValueObjectRegisterContext::GetClangAST ()
+{
+ return NULL;
+}
+
+size_t
+ValueObjectRegisterContext::GetByteSize()
+{
+ return 0;
+}
+
+void
+ValueObjectRegisterContext::UpdateValue (ExecutionContextScope *exe_scope)
+{
+ m_error.Clear();
+ StackFrame *frame = exe_scope->CalculateStackFrame();
+ if (frame)
+ m_reg_ctx = frame->GetRegisterContext();
+ else
+ m_reg_ctx = NULL;
+
+ SetValueIsValid (m_reg_ctx != NULL);
+}
+
+ValueObjectSP
+ValueObjectRegisterContext::CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ ValueObjectSP valobj_sp;
+
+ const uint32_t num_children = GetNumChildren();
+ if (idx < num_children)
+ valobj_sp.reset (new ValueObjectRegisterSet(m_reg_ctx, idx));
+ return valobj_sp;
+}
+
+
+#pragma mark -
+#pragma mark ValueObjectRegisterSet
+
+ValueObjectRegisterSet::ValueObjectRegisterSet (RegisterContext *reg_ctx, uint32_t reg_set_idx) :
+ ValueObject (),
+ m_reg_ctx (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()
+{
+}
+
+void *
+ValueObjectRegisterSet::GetOpaqueClangQualType ()
+{
+ return NULL;
+}
+
+ConstString
+ValueObjectRegisterSet::GetTypeName()
+{
+ return ConstString();
+}
+
+uint32_t
+ValueObjectRegisterSet::CalculateNumChildren()
+{
+ const RegisterSet *reg_set = m_reg_ctx->GetRegisterSet(m_reg_set_idx);
+ if (reg_set)
+ return reg_set->num_registers;
+ return 0;
+}
+
+clang::ASTContext *
+ValueObjectRegisterSet::GetClangAST ()
+{
+ return NULL;
+}
+
+size_t
+ValueObjectRegisterSet::GetByteSize()
+{
+ return 0;
+}
+
+void
+ValueObjectRegisterSet::UpdateValue (ExecutionContextScope *exe_scope)
+{
+ m_error.Clear();
+ SetValueDidChange (false);
+ StackFrame *frame = exe_scope->CalculateStackFrame();
+ if (frame == NULL)
+ m_reg_ctx = NULL;
+ else
+ {
+ m_reg_ctx = frame->GetRegisterContext ();
+ if (m_reg_ctx)
+ {
+ const RegisterSet *reg_set = m_reg_ctx->GetRegisterSet (m_reg_set_idx);
+ if (reg_set == NULL)
+ m_reg_ctx = NULL;
+ else if (m_reg_set != reg_set)
+ {
+ SetValueDidChange (true);
+ m_name.SetCString(reg_set->name);
+ }
+ }
+ }
+ if (m_reg_ctx)
+ {
+ SetValueIsValid (true);
+ }
+ else
+ {
+ SetValueIsValid (false);
+ m_children.clear();
+ }
+}
+
+
+ValueObjectSP
+ValueObjectRegisterSet::CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ ValueObjectSP valobj_sp;
+ if (m_reg_ctx && m_reg_set)
+ {
+ const uint32_t num_children = GetNumChildren();
+ if (idx < num_children)
+ valobj_sp.reset (new ValueObjectRegister(m_reg_ctx, m_reg_set->registers[idx]));
+ }
+ return valobj_sp;
+}
+
+
+#pragma mark -
+#pragma mark ValueObjectRegister
+
+ValueObjectRegister::ValueObjectRegister (RegisterContext *reg_ctx, uint32_t reg_num) :
+ ValueObject (),
+ m_reg_ctx (reg_ctx),
+ m_reg_info (NULL),
+ m_reg_num (reg_num),
+ m_type_name (),
+ m_clang_type (NULL)
+{
+ assert (reg_ctx);
+ m_reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
+ if (m_reg_info)
+ {
+ if (m_reg_info->name)
+ m_name.SetCString(m_reg_info->name);
+ else if (m_reg_info->alt_name)
+ m_name.SetCString(m_reg_info->alt_name);
+ }
+}
+
+ValueObjectRegister::~ValueObjectRegister()
+{
+}
+
+void *
+ValueObjectRegister::GetOpaqueClangQualType ()
+{
+ if (m_clang_type == NULL && m_reg_info)
+ {
+ Process *process = m_reg_ctx->CalculateProcess ();
+ if (process)
+ {
+ Module *exe_module = process->GetTarget().GetExecutableModule ().get();
+ if (exe_module)
+ {
+ TypeList *type_list = exe_module->GetTypeList();
+ if (type_list)
+ m_clang_type = type_list->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 = Type::GetClangTypeName (GetOpaqueClangQualType());
+ return m_type_name;
+}
+
+uint32_t
+ValueObjectRegister::CalculateNumChildren()
+{
+ return 0;
+}
+
+clang::ASTContext *
+ValueObjectRegister::GetClangAST ()
+{
+ Process *process = m_reg_ctx->CalculateProcess ();
+ if (process)
+ {
+ Module *exe_module = process->GetTarget().GetExecutableModule ().get();
+ if (exe_module)
+ {
+ TypeList *type_list = exe_module->GetTypeList();
+ if (type_list)
+ return type_list->GetClangASTContext().getASTContext();
+ }
+ }
+ return NULL;
+}
+
+size_t
+ValueObjectRegister::GetByteSize()
+{
+ return m_reg_info->byte_size;
+}
+
+void
+ValueObjectRegister::UpdateValue (ExecutionContextScope *exe_scope)
+{
+ m_error.Clear();
+ StackFrame *frame = exe_scope->CalculateStackFrame();
+ if (frame)
+ {
+ m_reg_ctx = frame->GetRegisterContext();
+ if (m_reg_ctx)
+ {
+ const RegisterInfo *reg_info = m_reg_ctx->GetRegisterInfoAtIndex(m_reg_num);
+ if (m_reg_info != reg_info)
+ {
+ m_reg_info = reg_info;
+ if (m_reg_info)
+ {
+ if (m_reg_info->name)
+ m_name.SetCString(m_reg_info->name);
+ else if (m_reg_info->alt_name)
+ m_name.SetCString(m_reg_info->alt_name);
+ }
+ }
+ }
+ }
+ else
+ {
+ m_reg_ctx = NULL;
+ m_reg_info = NULL;
+ }
+
+
+ if (m_reg_ctx && m_reg_info)
+ {
+ if (m_reg_ctx->ReadRegisterBytes (m_reg_num, m_data))
+ {
+ m_value.SetContext(Value::eContextTypeDCRegisterInfo, (void *)m_reg_info);
+ m_value.SetValueType(Value::eValueTypeHostAddress);
+ m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
+ SetValueIsValid (true);
+ return;
+ }
+ }
+ SetValueIsValid (false);
+}
+
+
diff --git a/lldb/source/Core/ValueObjectVariable.cpp b/lldb/source/Core/ValueObjectVariable.cpp
new file mode 100644
index 00000000000..0b94535387f
--- /dev/null
+++ b/lldb/source/Core/ValueObjectVariable.cpp
@@ -0,0 +1,167 @@
+//===-- 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/ValueObjectList.h"
+#include "lldb/Core/Value.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"
+
+#include "clang/AST/Type.h"
+
+
+using namespace lldb_private;
+
+ValueObjectVariable::ValueObjectVariable (lldb::VariableSP &var_sp) :
+ ValueObject(),
+ 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()
+{
+}
+
+void *
+ValueObjectVariable::GetOpaqueClangQualType ()
+{
+ Type *var_type = m_variable_sp->GetType();
+ if (var_type)
+ return var_type->GetOpaqueClangQualType();
+ return NULL;
+}
+
+ConstString
+ValueObjectVariable::GetTypeName()
+{
+ Type * var_type = m_variable_sp->GetType();
+ if (var_type)
+ return var_type->GetName();
+ ConstString empty_type_name;
+ return empty_type_name;
+}
+
+uint32_t
+ValueObjectVariable::CalculateNumChildren()
+{
+ Type *var_type = m_variable_sp->GetType();
+ if (var_type)
+ return var_type->GetNumChildren(true);
+ return 0;
+}
+
+clang::ASTContext *
+ValueObjectVariable::GetClangAST ()
+{
+ return m_variable_sp->GetType()->GetClangAST();
+}
+
+size_t
+ValueObjectVariable::GetByteSize()
+{
+ return m_variable_sp->GetType()->GetByteSize();
+}
+
+lldb::ValueType
+ValueObjectVariable::GetValueType() const
+{
+ if (m_variable_sp)
+ return m_variable_sp->GetScope();
+ return lldb::eValueTypeInvalid;
+}
+
+
+
+void
+ValueObjectVariable::UpdateValue (ExecutionContextScope *exe_scope)
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ Variable *variable = m_variable_sp.get();
+ DWARFExpression &expr = variable->LocationExpression();
+ Value old_value(m_value);
+ ExecutionContext exe_ctx (exe_scope);
+ if (expr.Evaluate (&exe_ctx, GetClangAST(), NULL, m_value, &m_error))
+ {
+ m_value.SetContext(Value::eContextTypeDCVariable, variable);
+
+ 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, GetClangAST(), m_data, 0);
+ 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 (ClangASTContext::IsAggregateType (GetOpaqueClangQualType()))
+ {
+ // 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::eContextTypeDCVariable, variable);
+ m_error = value.GetValueAsData(&exe_ctx, GetClangAST(), m_data, 0);
+ }
+ break;
+ }
+
+ SetValueIsValid (m_error.Success());
+ }
+}
+
+
+
+bool
+ValueObjectVariable::IsInScope (StackFrame *frame)
+{
+ return m_variable_sp->IsInScope (frame);
+}
+
OpenPOWER on IntegriCloud