*,
The ArchSpec class has been giving me a few problems on linux lately.
There were two main issues:
1) The default "personality" for an ArchSpec is MachO. This
assumption was causing a few issues when the linux plugins were
being handed an ArchSpec they could not deal with.
2) We have an llvm::Triple embedded in an ArchSpec. For MachO
ArchSpec's it makes sense to have a vendor-os component of
"apple-darwin" as default, but for ELF there is no way to guess
what the operating system might be. Since we do not have the
logic in LLDB yet to create an ArchSpec's with the appropriate OS
bits resolved we were failing during plugin lookup on linux.
So basically what I think we need is:
A) An ArchSpec which does not assume much.
B) An ArchSpec that is free of "magic" cpu type and subtype numbers,
feature flags, etc. Use generic values like ArchSpec::CPU,
llvm::Triples, or plain strings instead.
C) A bit more logic at the points where ArchSpecs are instantiated
to figure out what the ArchSpec should be.
Attached is a almost entirely rewritten ArchSpec that tries to address
point A, but with a view towards implementing point B down the road. I
have been testing it on linux with a few modifications to LLDB that help
with point C, but before I do any more work on this I thought I'd run
what I have past everyone first.
This "new" ArchSpec certainly borrows from the original version and
looks similar as far as the API goes. However, some things have been
moved around to help make a migration to a generic interface a bit
easier.
The major differences are:
- Constructor that accepts an llvm::Triple as argument.
- No more constructors that take cpu or cpu subtypes as arguments.
- The cpu subtype is settable via SetCPUSubtype or implicitly set via
an architecture name. We could also resolve it if given a detailed
llvm::Triple. Eventually it would be nice to use a generic
enumeration value here.
- The feature flags are now independent of the cpu subtype.
Eventually it would be nice to provide a set of generic flags to
provide things like ABI info and anything else we might need.
- The implementation is fairly generic. It is driven by table
lookups. There are only a few places where the code does a "switch"
or an "if" over particular values. Eventually the table lookups
could be implemented over "generic" values instead of the current
"magic" ones.
- A little bit more work is done to try and ensure the ArchSpec
remains in a consistent state. All mutators can fail now if the
requested combination of properties does not make sense (except in
the case of feature flags as they are not yet modeled, and we can
still override the default endianess of an architecture).
- ArchSpec::AsCString has been reimplemented to use a caller supplied
buffer. Main reason being the old implementation was not thread
safe. For the common case where all you need is an architecture
name (instead of the fancy "macho-6-4" style triples)
ArchSpec::GetArchitectureName is provided.
Please not that this code is only lightly tested. All thoughts/comments
appreciated.
Thanks!
--
steve
//===-- ArchSpec.h ----------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_ArchSpec_h_
#define liblldb_ArchSpec_h_
#if defined(__cplusplus)
#include "lldb/lldb-private.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
namespace lldb_private {
//----------------------------------------------------------------------
/// @class ArchSpec ArchSpec.h "lldb/Core/ArchSpec.h"
/// @brief An architecture specification class.
///
/// A class designed to be created from a cpu type and subtype, a
/// string representation, or an llvm::Triple. Keeping all of the
/// conversions of strings to architecture enumeration values confined
/// to this class allows new architecture support to be added easily.
//----------------------------------------------------------------------
class ArchSpec
{
public:
// Forward declarations for internal ArchSpec structure types.
struct ArchDefinition;
struct ArchDefinitionEntry;
// Generic CPU types.
enum CPU
{
eCPU_Unknown,
eCPU_arm,
eCPU_i386,
eCPU_x86_64,
eCPU_ppc,
eCPU_ppc64,
eCPU_sparc,
eCPU_sparcv9,
eCPU_m32,
eCPU_68k,
eCPU_88k,
eCPU_mips,
eCPU_alpha
};
//------------------------------------------------------------------
/// Default constructor.
///
/// Default constructor that initializes the object with invalid
/// cpu type and subtype values.
//------------------------------------------------------------------
ArchSpec ();
//------------------------------------------------------------------
/// Constructor over triple.
///
/// Constructs an ArchSpec with properties consistent with the given
/// Triple.
//------------------------------------------------------------------
ArchSpec (const llvm::Triple &triple);
//------------------------------------------------------------------
/// Constructor over architecture name.
///
/// Constructs an ArchSpec with properties consistent with the given
/// object type and architecture name.
//------------------------------------------------------------------
ArchSpec (lldb::ArchitectureType arch_type, llvm::StringRef arch_name);
//------------------------------------------------------------------
/// Destructor.
///
/// The destructor is virtual in case this class is subclassed.
//------------------------------------------------------------------
virtual
~ArchSpec ();
//------------------------------------------------------------------
/// Assignment operator.
///
/// @param[in] rhs another ArchSpec object to copy.
///
/// @return A const reference to this object.
//------------------------------------------------------------------
const ArchSpec&
operator= (const ArchSpec& rhs);
//------------------------------------------------------------------
/// Get a detailed string representation of this ArchSpec.
///
/// @param[in,out] dst destination buffer to copy the string into.
///
/// @param[in] len length of the supplied buffer
///
/// @return The number of bytes successfully written to @p dst
/// excluding the terminating NULL character, or the number
/// of bytes written had @p dst been large enough.
/// Therefore, a return value of @p len or greater indicates
/// the string was truncated.
//------------------------------------------------------------------
size_t
GetAsCString (char *dst, size_t len) const;
//------------------------------------------------------------------
/// Returns a static string representing the current architecture.
///
/// @return A static string correcponding to the current
/// architecture.
//------------------------------------------------------------------
const char *
GetArchitectureName () const;
//------------------------------------------------------------------
/// Clears the object state.
///
/// Clears the object state back to a default invalid state.
//------------------------------------------------------------------
void
Clear ();
//------------------------------------------------------------------
/// Returns the size in bytes of an address of the current
/// architecture.
///
/// @return The byte size of an address of the current architecture.
//------------------------------------------------------------------
uint32_t
GetAddressByteSize () const;
//------------------------------------------------------------------
/// Returns a generic CPU encoding for the current architecture.
///
/// @return A generic CPU encoding.
//------------------------------------------------------------------
CPU
GetGenericCPUType () const;
//------------------------------------------------------------------
/// CPU type get accessor.
///
/// Returns a platform dependent encoding for the current CPU type.
///
/// @return The current value of the CPU type or
/// LLDB_INVALID_CPUTYPE if one has not been configured.
//------------------------------------------------------------------
uint32_t
GetCPUType () const;
//------------------------------------------------------------------
/// Sets the CPU subtype.
///
/// The ArchSpec must have a valid CPU type before the subtype can be
/// set.
///
/// @return True if the CPU subtype was successfully set and false
/// otherwise.
//------------------------------------------------------------------
bool
SetCPUSubtype (uint32_t sub);
//------------------------------------------------------------------
/// CPU subtype get accessor.
///
/// Returns a platform dependent encoding for the current CPU
/// subtype.
///
/// @return The current value of the CPU subtype or
/// LLDB_INVALID_CPUTYPE if one has not been configured.
//------------------------------------------------------------------
uint32_t
GetCPUSubtype () const;
//------------------------------------------------------------------
/// Feature flags get accessor.
///
/// Returns a set of platform dependent feature flags. These bits
/// typically yield information about the ABI implied by
/// this ArchSpec.
///
/// @return The current value of the CPU feature flags.
//------------------------------------------------------------------
uint32_t
GetFeatureFlags () const
{
return m_flags;
}
//------------------------------------------------------------------
/// Feature flags setter.
///
/// Sets the platform dependent feature flags for this ArchSpec.
//------------------------------------------------------------------
void
SetFeatureFlags (uint32_t flags)
{
m_flags = flags;
}
//------------------------------------------------------------------
/// Tests if this ArchSpec is valid.
///
/// @return True if the current architecture is valid, false
/// otherwise.
//------------------------------------------------------------------
bool
IsValid () const;
//------------------------------------------------------------------
/// Sets this ArchSpec according to the given architecture name.
///
/// The architecture name can be one of the generic system default
/// values:
///
/// @li \c LLDB_ARCH_DEFAULT - The arch the current system defaults
/// to when a program is launched without any extra
/// attributes or settings.
/// @li \c LLDB_ARCH_DEFAULT_32BIT - The default host architecture
/// for 32 bit (if any).
/// @li \c LLDB_ARCH_DEFAULT_64BIT - The default host architecture
/// for 64 bit (if any).
///
/// Alternatively, if the object type of this ArchSpec has been
/// configured, a concrete architecture can be specified to set
/// the CPU type ("x86_64" for example).
///
/// Finally, an encoded object and archetecture format is accepted.
/// The format contains an object type (like "macho" or "elf"),
/// followed by a platform dependent encoding of CPU type and
/// subtype. For example:
///
/// "macho" : Specifies an object type of MachO.
/// "macho-16-6" : MachO specific encoding for ARMv6.
/// "elf-43 : ELF specific encoding for Sparc V9.
///
/// @param[in] arch_name The name of an architecture.
///
/// @return True if @p arch_name was successfully translated, false
/// otherwise.
//------------------------------------------------------------------
bool
SetArch (llvm::StringRef arch_name);
//------------------------------------------------------------------
/// Change the architecture object type and CPU type given an
/// architecture name.
///
/// Unlike SetArch(llvm::StringRef arch_name), this method does not
/// accept the default architecture strings. A concrete
/// architecture name must be supplied.
///
/// @param[in] arch_type The object type of this ArchSpec.
///
/// @param[in] arch_name The name of an architecture.
///
/// @return True if object and CPU type were sucessfully set.
//------------------------------------------------------------------
bool
SetArch (lldb::ArchitectureType arch_type, llvm::StringRef arch_name);
//------------------------------------------------------------------
/// Change the architecture object type and CPU type.
///
/// @param[in] arch_type The object type of this ArchSpec.
///
/// @param[in] cpu The required CPU type.
///
/// @return True if the object and CPU type were sucessfully set.
//------------------------------------------------------------------
bool
SetArch (lldb::ArchitectureType arch_type, llvm::Triple::ArchType cpu);
//------------------------------------------------------------------
/// Returns the byte order for the architecture specification.
///
/// @return The endian enumeration for the current endianness of
/// the architecture specification
//------------------------------------------------------------------
lldb::ByteOrder
GetByteOrder () const;
//------------------------------------------------------------------
/// Sets this ArchSpec's byte order.
///
/// In the common case there is no need to call this method as the
/// byte order can almost always be determined by the architecture.
/// However, many CPU's are bi-endian (ARM, Alpha, PowerPC, etc)
/// and the default/assumed byte order may be incorrect.
///
/// @return true if the byte order was successfully set and false
/// otherwise.
//------------------------------------------------------------------
bool
SetByteOrder (lldb::ByteOrder byteorder);
//------------------------------------------------------------------
/// Architecture tripple accessor.
///
/// @return A triple describing this ArchSpec.
//------------------------------------------------------------------
llvm::Triple &
GetTriple ()
{
return m_triple;
}
//------------------------------------------------------------------
/// Architecture tripple accessor.
///
/// @return A triple describing this ArchSpec.
//------------------------------------------------------------------
const llvm::Triple &
GetTriple () const
{
return m_triple;
}
//------------------------------------------------------------------
/// Architecture tripple setter.
///
/// Configures this ArchSpec according to the given triple. At a
/// minimum, the given triple must describe a valid operating
/// system. If archetecture or environment components are present
/// they too will be used to further resolve the CPU type and
/// subtype, endian characteristics, etc.
///
/// @return A triple describing this ArchSpec.
//------------------------------------------------------------------
bool
SetTriple (const llvm::Triple &triple);
//------------------------------------------------------------------
/// Returns the default endianness of the architecture.
///
/// @return The endian enumeration for the default endianness of
/// the architecture.
//------------------------------------------------------------------
lldb::ByteOrder
GetDefaultEndian () const;
//------------------------------------------------------------------
/// Returns the object type of this ArchSpec.
///
/// @return The object type of this Archspec.
//------------------------------------------------------------------
lldb::ArchitectureType
GetType () const;
//------------------------------------------------------------------
/// @return The default architecture type or an invalid ArchSpec.
//------------------------------------------------------------------
static ArchSpec
GetDefaultArch (lldb::ArchitectureType arch_type);
//------------------------------------------------------------------
/// @return The default 32 bit architecture type or an invalid
/// ArchSpec.
//------------------------------------------------------------------
static ArchSpec
GetDefaultArch32 (lldb::ArchitectureType arch_type);
//------------------------------------------------------------------
/// @return The default 64 bit architecture type or an invalid
/// ArchSpec.
//------------------------------------------------------------------
static ArchSpec
GetDefaultArch64 (lldb::ArchitectureType arch_type);
protected:
const ArchDefinition *m_def;
const ArchDefinitionEntry *m_entry;
lldb::ByteOrder m_byte_order;
llvm::Triple m_triple;
uint32_t m_flags;
// Called when m_def or m_entry are changed. Fills in all remaining
// members with default values.
void ArchUpdated ();
};
//------------------------------------------------------------------
/// @fn bool operator== (const ArchSpec& lhs, const ArchSpec& rhs)
/// @brief Equal to operator.
///
/// Tests two ArchSpec objects to see if they are equal.
///
/// @param[in] lhs The Left Hand Side ArchSpec object to compare.
/// @param[in] rhs The Left Hand Side ArchSpec object to compare.
///
/// @return true if \a lhs is equal to \a rhs
//------------------------------------------------------------------
bool operator==(const ArchSpec& lhs, const ArchSpec& rhs);
//------------------------------------------------------------------
/// @fn bool operator!= (const ArchSpec& lhs, const ArchSpec& rhs)
/// @brief Not equal to operator.
///
/// Tests two ArchSpec objects to see if they are not equal.
///
/// @param[in] lhs The Left Hand Side ArchSpec object to compare.
/// @param[in] rhs The Left Hand Side ArchSpec object to compare.
///
/// @return true if \a lhs is not equal to \a rhs
//------------------------------------------------------------------
bool operator!=(const ArchSpec& lhs, const ArchSpec& rhs);
//------------------------------------------------------------------
/// @fn bool operator< (const ArchSpec& lhs, const ArchSpec& rhs)
/// @brief Less than operator.
///
/// Tests two ArchSpec objects to see if \a lhs is less than \a
/// rhs.
///
/// @param[in] lhs The Left Hand Side ArchSpec object to compare.
/// @param[in] rhs The Left Hand Side ArchSpec object to compare.
///
/// @return true if \a lhs is less than \a rhs
//------------------------------------------------------------------
bool operator< (const ArchSpec& lhs, const ArchSpec& rhs);
} // namespace lldb_private
#endif // #if defined(__cplusplus)
#endif // #ifndef liblldb_ArchSpec_h_
//===-- ArchSpec.cpp --------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/ArchSpec.h"
#include <stdio.h>
#include <string>
#include "llvm/Support/ELF.h"
#include "llvm/Support/MachO.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
using namespace lldb;
using namespace lldb_private;
#define ARCH_SPEC_SEPARATOR_CHAR '-'
struct ArchSpec::ArchDefinition
{
ArchitectureType type;
size_t num_entries;
const ArchDefinitionEntry *entries;
const char *name;
};
struct ArchSpec::ArchDefinitionEntry
{
ByteOrder byte_order;
uint32_t addr_byte_size;
ArchSpec::CPU generic_cpu;
uint32_t cpu;
uint32_t sub;
const char *name;
};
#define CPU_ANY (UINT32_MAX)
//===----------------------------------------------------------------------===//
// A table that gets searched linearly for matches. This table is used to
// convert cpu type and subtypes to architecture names, and to convert
// architecture names to cpu types and subtypes. The ordering is important and
// allows the precedence to be set when the table is built.
static const ArchSpec::ArchDefinitionEntry g_macho_arch_entries[] =
{
{ eByteOrderInvalid, 0, ArchSpec::eCPU_Unknown, CPU_ANY,
CPU_ANY , "all" },
{ eByteOrderLittle, 4, ArchSpec::eCPU_arm, llvm::MachO::CPUTypeARM,
CPU_ANY , "arm" },
{ eByteOrderLittle, 4, ArchSpec::eCPU_arm, llvm::MachO::CPUTypeARM,
0 , "arm" },
{ eByteOrderLittle, 4, ArchSpec::eCPU_arm, llvm::MachO::CPUTypeARM,
5 , "armv4" },
{ eByteOrderLittle, 4, ArchSpec::eCPU_arm, llvm::MachO::CPUTypeARM,
6 , "armv6" },
{ eByteOrderLittle, 4, ArchSpec::eCPU_arm, llvm::MachO::CPUTypeARM,
7 , "armv5" },
{ eByteOrderLittle, 4, ArchSpec::eCPU_arm, llvm::MachO::CPUTypeARM,
8 , "xscale" },
{ eByteOrderLittle, 4, ArchSpec::eCPU_arm, llvm::MachO::CPUTypeARM,
9 , "armv7" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, CPU_ANY , "ppc" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, 0 , "ppc" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, 1 , "ppc601" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, 2 , "ppc602" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, 3 , "ppc603" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, 4 , "ppc603e" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, 5 , "ppc603ev" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, 6 , "ppc604" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, 7 , "ppc604e" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, 8 , "ppc620" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, 9 , "ppc750" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, 10 , "ppc7400" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, 11 , "ppc7450" },
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc,
llvm::MachO::CPUTypePowerPC, 100 , "ppc970" },
{ eByteOrderBig, 8, ArchSpec::eCPU_ppc64,
llvm::MachO::CPUTypePowerPC64, 0 , "ppc64" },
{ eByteOrderBig, 8, ArchSpec::eCPU_ppc64,
llvm::MachO::CPUTypePowerPC64, 100 , "ppc970-64"},
{ eByteOrderLittle, 4, ArchSpec::eCPU_i386, llvm::MachO::CPUTypeI386,
3 , "i386" },
{ eByteOrderLittle, 4, ArchSpec::eCPU_i386, llvm::MachO::CPUTypeI386,
4 , "i486" },
{ eByteOrderLittle, 4, ArchSpec::eCPU_i386, llvm::MachO::CPUTypeI386,
0x84 , "i486sx" },
{ eByteOrderLittle, 4, ArchSpec::eCPU_i386, llvm::MachO::CPUTypeI386,
CPU_ANY , "i386" },
{ eByteOrderLittle, 8, ArchSpec::eCPU_x86_64, llvm::MachO::CPUTypeX86_64,
3 , "x86_64" },
{ eByteOrderLittle, 8, ArchSpec::eCPU_x86_64, llvm::MachO::CPUTypeX86_64,
CPU_ANY , "x86_64" },
};
static const ArchSpec::ArchDefinition g_macho_arch_def = {
eArchTypeMachO,
sizeof(g_macho_arch_entries)/sizeof(g_macho_arch_entries[0]),
g_macho_arch_entries,
"mach-o"
};
//===----------------------------------------------------------------------===//
// A table that gets searched linearly for matches. This table is used to
// convert cpu type and subtypes to architecture names, and to convert
// architecture names to cpu types and subtypes. The ordering is important and
// allows the precedence to be set when the table is built.
static const ArchSpec::ArchDefinitionEntry g_elf_arch_entries[] =
{
{ eByteOrderInvalid, 0, ArchSpec::eCPU_Unknown, llvm::ELF::EM_M32 ,
LLDB_INVALID_CPUTYPE, "m32" }, // AT&T WE 32100
{ eByteOrderBig, 4, ArchSpec::eCPU_Unknown, llvm::ELF::EM_SPARC ,
LLDB_INVALID_CPUTYPE, "sparc" }, // Sparc
{ eByteOrderLittle, 4, ArchSpec::eCPU_i386, llvm::ELF::EM_386 ,
LLDB_INVALID_CPUTYPE, "i386" }, // Intel 80386
{ eByteOrderBig, 4, ArchSpec::eCPU_Unknown, llvm::ELF::EM_68K ,
LLDB_INVALID_CPUTYPE, "68k" }, // Motorola 68000
{ eByteOrderBig, 4, ArchSpec::eCPU_Unknown, llvm::ELF::EM_88K ,
LLDB_INVALID_CPUTYPE, "88k" }, // Motorola 88000
{ eByteOrderLittle, 4, ArchSpec::eCPU_i386, llvm::ELF::EM_486 ,
LLDB_INVALID_CPUTYPE, "i486" }, // Intel 486 (deprecated)
{ eByteOrderLittle, 4, ArchSpec::eCPU_Unknown, llvm::ELF::EM_860 ,
LLDB_INVALID_CPUTYPE, "860" }, // Intel 80860
{ eByteOrderBig, 4, ArchSpec::eCPU_Unknown, llvm::ELF::EM_MIPS ,
LLDB_INVALID_CPUTYPE, "rs3000"}, // MIPS RS3000
{ eByteOrderBig, 4, ArchSpec::eCPU_ppc, llvm::ELF::EM_PPC ,
LLDB_INVALID_CPUTYPE, "ppc" }, // PowerPC
{ eByteOrderBig, 8, ArchSpec::eCPU_ppc64, llvm::ELF::EM_PPC64 ,
LLDB_INVALID_CPUTYPE, "ppc64" }, // PowerPC64
{ eByteOrderLittle, 4, ArchSpec::eCPU_arm, llvm::ELF::EM_ARM ,
LLDB_INVALID_CPUTYPE, "arm" }, // ARM
{ eByteOrderLittle, 8, ArchSpec::eCPU_Unknown, llvm::ELF::EM_ALPHA ,
LLDB_INVALID_CPUTYPE, "alpha" }, // DEC Alpha
{ eByteOrderLittle, 8, ArchSpec::eCPU_Unknown, llvm::ELF::EM_SPARCV9,
LLDB_INVALID_CPUTYPE, "sparc9"}, // SPARC V9
{ eByteOrderLittle, 8, ArchSpec::eCPU_x86_64, llvm::ELF::EM_X86_64 ,
LLDB_INVALID_CPUTYPE, "x86_64"}, // AMD64
};
static const ArchSpec::ArchDefinition g_elf_arch_def = {
eArchTypeELF,
sizeof(g_elf_arch_entries)/sizeof(g_elf_arch_entries[0]),
g_elf_arch_entries,
"elf",
};
//===----------------------------------------------------------------------===//
// Table of all ArchDefinitions
static const ArchSpec::ArchDefinition *g_arch_definitions[] = {
&g_macho_arch_def,
&g_elf_arch_def,
};
static const size_t k_num_arch_definitions =
sizeof(g_arch_definitions) / sizeof(g_arch_definitions[0]);
//===----------------------------------------------------------------------===//
// Static helper functions.
// Get the architecture definition for a given object type.
static const ArchSpec::ArchDefinition *
FindArchDefinition (ArchitectureType arch_type)
{
for (unsigned int i = 0; i < k_num_arch_definitions; ++i)
{
const ArchSpec::ArchDefinition *def = g_arch_definitions[i];
if (def->type == arch_type)
return def;
}
return NULL;
}
// Get an architecture definition by name.
static const ArchSpec::ArchDefinition *
FindArchDefinition (llvm::StringRef name)
{
for (unsigned int i = 0; i < k_num_arch_definitions; ++i)
{
const ArchSpec::ArchDefinition *def = g_arch_definitions[i];
if (name.compare_lower(def->name))
return def;
}
return NULL;
}
// Get a definition entry by cpu type and subtype.
static const ArchSpec::ArchDefinitionEntry *
FindArchDefinitionEntry (const ArchSpec::ArchDefinition *def, uint32_t cpu,
uint32_t sub)
{
if (def == NULL)
return NULL;
const ArchSpec::ArchDefinitionEntry *entries = def->entries;
for (size_t i = 0; i < def->num_entries; ++i)
{
if (entries[i].cpu == cpu && sub == entries[i].sub)
return &entries[i];
}
return NULL;
}
// Get a definition entry by architecture name.
static const ArchSpec::ArchDefinitionEntry *
FindArchDefinitionEntry (const ArchSpec::ArchDefinition *def, llvm::StringRef
arch_name)
{
if (def == NULL)
return NULL;
const ArchSpec::ArchDefinitionEntry *entries = def->entries;
for (size_t i = 0; i < def->num_entries; ++i)
{
if (arch_name.equals_lower(entries[i].name))
return &entries[i];
}
return NULL;
}
// Get the object type implied by the given triple.
static ArchitectureType
GetTripleArchitectureType (const llvm::Triple &triple)
{
ArchitectureType arch_type = eArchTypeInvalid;
switch (triple.getOS())
{
default:
break;
case llvm::Triple::Darwin:
arch_type = eArchTypeMachO;
break;
case llvm::Triple::AuroraUX:
case llvm::Triple::DragonFly:
case llvm::Triple::FreeBSD:
case llvm::Triple::Linux:
case llvm::Triple::NetBSD:
case llvm::Triple::OpenBSD:
case llvm::Triple::Solaris:
arch_type = eArchTypeELF;
break;
}
return arch_type;
}
//===----------------------------------------------------------------------===//
// Constructors and destructors.
ArchSpec::ArchSpec() :
m_def (NULL),
m_entry (NULL),
m_byte_order (eByteOrderInvalid),
m_triple (),
m_flags (0)
{
}
ArchSpec::ArchSpec(const llvm::Triple &triple) :
m_def (NULL),
m_entry (NULL),
m_byte_order (eByteOrderInvalid),
m_triple (),
m_flags (0)
{
SetTriple(triple);
}
ArchSpec::ArchSpec (ArchitectureType arch_type, llvm::StringRef arch_name) :
m_def (FindArchDefinition(arch_type)),
m_entry (NULL),
m_byte_order (eByteOrderInvalid),
m_triple (),
m_flags (0)
{
if (m_def != NULL)
{
m_entry = FindArchDefinitionEntry(m_def, arch_name);
ArchUpdated();
}
}
ArchSpec::~ArchSpec()
{
}
//===----------------------------------------------------------------------===//
// Assignment and initialization.
const ArchSpec&
ArchSpec::operator= (const ArchSpec& rhs)
{
if (this != &rhs)
{
m_def = rhs.m_def;
m_entry = rhs.m_entry;
m_flags = rhs.m_flags;
m_triple = rhs.m_triple;
m_byte_order = rhs.m_byte_order;
}
return *this;
}
void
ArchSpec::Clear()
{
m_def = NULL;
m_entry = NULL;
m_flags = 0;
m_triple = llvm::Triple();
m_byte_order = eByteOrderInvalid;
}
//===----------------------------------------------------------------------===//
// Predicates.
bool
ArchSpec::IsValid() const
{
return (m_def != NULL && m_entry != NULL);
}
//===----------------------------------------------------------------------===//
// Accessors.
ArchitectureType
ArchSpec::GetType () const
{
if (m_def == NULL)
return eArchTypeInvalid;
return m_def->type;
}
size_t
ArchSpec::GetAsCString(char *dst, size_t len) const
{
if (m_def != NULL && m_entry != NULL)
{
int ret = ::snprintf(dst, len, "%s%c%u%c%u",
m_def->name, ARCH_SPEC_SEPARATOR_CHAR,
m_entry->cpu, ARCH_SPEC_SEPARATOR_CHAR,
m_entry->sub);
assert(ret >= 0 && "snprintf failed?");
return ret;
}
if (m_def != NULL)
{
int ret = ::snprintf(dst, len, "%s", m_def->name);
assert(ret >= 0 && "snprintf failed?");
return ret;
}
return 0;
}
const char *
ArchSpec::GetArchitectureName () const
{
if (m_entry == NULL)
return "unknown";
return m_entry->name;
}
uint32_t
ArchSpec::GetCPUSubtype() const
{
if (m_entry == NULL)
return LLDB_INVALID_CPUTYPE;
return m_entry->sub;
}
uint32_t
ArchSpec::GetCPUType() const
{
if (m_entry == NULL)
return LLDB_INVALID_CPUTYPE;
return m_entry->cpu;
}
ArchSpec::CPU
ArchSpec::GetGenericCPUType () const
{
if (m_entry == NULL)
return eCPU_Unknown;
return m_entry->generic_cpu;
}
uint32_t
ArchSpec::GetAddressByteSize() const
{
if (m_entry == NULL)
return 0;
return m_entry->addr_byte_size;
}
ByteOrder
ArchSpec::GetDefaultEndian () const
{
if (m_entry == NULL)
return eByteOrderInvalid;
return m_entry->byte_order;
}
lldb::ByteOrder
ArchSpec::GetByteOrder () const
{
return m_byte_order;
}
ArchSpec
ArchSpec::GetDefaultArch (lldb::ArchitectureType arch_type)
{
return ArchSpec(arch_type, LLDB_ARCH_DEFAULT);
}
ArchSpec
ArchSpec::GetDefaultArch32(lldb::ArchitectureType arch_type)
{
return ArchSpec(arch_type, LLDB_ARCH_DEFAULT_32BIT);
}
ArchSpec
ArchSpec::GetDefaultArch64(lldb::ArchitectureType arch_type)
{
return ArchSpec(arch_type, LLDB_ARCH_DEFAULT_64BIT);
}
//===----------------------------------------------------------------------===//
// Mutators.
bool
ArchSpec::SetTriple (const llvm::Triple &triple)
{
ArchitectureType arch_type = GetTripleArchitectureType(triple);
if ((m_def = FindArchDefinition(arch_type)) == NULL)
return false;
// FIXME: Triples can contain endian and ABI info too (little endian armv5
// using the GNU EABI with uClibc runtime would be written
// "armv5l-unknown-linux-uclibceabi" for example). Consider teaching
// llvm::Triple to parse these types of specifications completely.
m_entry = FindArchDefinitionEntry(m_def, triple.getArchName());
m_triple = triple;
// Can't call ArchUpdated here or we would reset the triple.
m_flags = 0;
if (m_entry != NULL)
m_byte_order = m_entry->byte_order;
}
bool
ArchSpec::SetArch (llvm::StringRef arch_name)
{
if (arch_name.empty())
return false;
// All default architecture names start with LLDB_ARCH_DEFAULT.
if (arch_name.startswith (LLDB_ARCH_DEFAULT))
{
const ArchSpec *host_spec;
// Special case for the current host default architectures...
if (arch_name.equals (LLDB_ARCH_DEFAULT_32BIT))
host_spec = &Host::GetArchitecture
(Host::eSystemDefaultArchitecture32);
else if (arch_name.equals (LLDB_ARCH_DEFAULT_64BIT))
host_spec = &Host::GetArchitecture
(Host::eSystemDefaultArchitecture64);
else
host_spec = &Host::GetArchitecture
(Host::eSystemDefaultArchitecture);
if (host_spec->IsValid())
{
*this = *host_spec;
return true;
}
else
return false;
}
// Check for a simple match over the architecture name.
if (m_def != NULL)
{
const ArchDefinitionEntry *entry = FindArchDefinitionEntry(m_def,
arch_name);
if (entry != NULL)
{
m_entry = entry;
ArchUpdated();
return true;
}
}
// Check for a numeric cpu followed by an optional separator char and
// numeric subtype. This allows for support of new cpu type/subtypes
// without having to have a recompiled debug core. Examples:
//
// "macho-12-6" : armv6 on darwin
// "macho-0x0000000c-0x00000006" : likewise
//
size_t pos = arch_name.find(ARCH_SPEC_SEPARATOR_CHAR);
llvm::StringRef prefix = arch_name.substr(0, pos);
const ArchDefinition *def = FindArchDefinition(arch_name);
if (def == NULL)
return false;
// If all we have is a prefix do not worry about the cpu type and subtype.
if (pos == llvm::StringRef::npos)
{
Clear();
m_def = def;
m_entry = NULL;
ArchUpdated();
return true;
}
// Parse the numeric cpu type and subtype encodings.
size_t cpu_start = ++pos;
size_t sub_start = arch_name.find(ARCH_SPEC_SEPARATOR_CHAR, cpu_start);
sub_start += (sub_start == llvm::StringRef::npos) ? 0 : 1;
llvm::StringRef cpu_number = arch_name.substr(cpu_start, sub_start);
llvm::StringRef sub_number = arch_name.substr(sub_start);
uint32_t cpu;
uint32_t sub;
if (!cpu_number.getAsInteger(0, cpu))
{
Clear();
m_def = def;
m_entry = NULL;
ArchUpdated();
return true;
}
if (!sub_number.getAsInteger(0, sub))
sub = CPU_ANY;
const ArchDefinitionEntry *entry = FindArchDefinitionEntry(def, cpu, sub);
if (entry == NULL)
return false;
// Looks good. Commit.
Clear();
m_def = def;
m_entry = entry;
ArchUpdated();
return true;
}
bool
ArchSpec::SetArch (lldb::ArchitectureType arch_type, llvm::StringRef arch_name)
{
const ArchDefinition *def;
const ArchDefinitionEntry *entry;
if ((def = FindArchDefinition(arch_type)) == NULL)
return false;
if ((entry = FindArchDefinitionEntry(def, arch_name)) == NULL)
return false;
Clear();
m_def = def;
m_entry = entry;
ArchUpdated();
return true;
}
bool
ArchSpec::SetArch (lldb::ArchitectureType arch_type, llvm::Triple::ArchType cpu)
{
const ArchDefinition *def;
const ArchDefinitionEntry *entry;
if ((def = FindArchDefinition(arch_type)) == NULL)
return false;
if ((entry = FindArchDefinitionEntry(def, cpu, CPU_ANY)) == NULL)
return false;
Clear();
m_def = def;
m_entry = entry;
ArchUpdated();
return true;
}
bool
ArchSpec::SetCPUSubtype (uint32_t sub)
{
if (m_def == NULL || m_entry == NULL)
return false;
uint32_t cpu = m_entry->cpu;
const ArchDefinitionEntry *entry = FindArchDefinitionEntry(m_def, cpu, sub);
if (entry == NULL)
return false;
// FIXME: Update the target triple.
m_entry = entry;
m_byte_order = entry->byte_order;
return true;
}
bool
ArchSpec::SetByteOrder (lldb::ByteOrder byte_order)
{
if (m_entry == NULL)
return false;
m_byte_order = byte_order;
return true;
}
//===----------------------------------------------------------------------===//
// Helper methods.
void
ArchSpec::ArchUpdated ()
{
if (m_def == NULL || m_entry == NULL)
return;
if (m_def->type == eArchTypeMachO)
m_triple = llvm::Triple(m_entry->name, "apple", "darwin");
else
m_triple = llvm::Triple(m_entry->name, "unknown", "unknown");
m_byte_order = m_entry->byte_order;
m_flags = 0;
}
//===----------------------------------------------------------------------===//
// Operators.
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_ANY || rhs_cpu == CPU_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_ANY || rhs_subtype == CPU_ANY)
return true;
return lhs_subtype == rhs_subtype;
}
return false;
}
bool
lldb_private::operator!= (const ArchSpec& lhs, const ArchSpec& rhs)
{
return !(lhs == rhs);
}
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;
}
_______________________________________________
lldb-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev