Re-organized the contents of RangeMap.h to be more concise and also allow for a Range, RangeArray, RangeData (range + data), or a RangeDataArray. We have many range implementations in LLDB and I will be converting over to using the classes in RangeMap.h so we can have one set of code that does ranges and searching of ranges.

Fixed up DWARFDebugAranges to use the new range classes.

Fixed the enumeration parsing to take a lldb_private::Error to avoid a lot of duplicated code. Now when an invalid enumeration is supplied, an error will be returned and that error will contain a list of the valid enumeration values.

llvm-svn: 141382
This commit is contained in:
Greg Clayton 2011-10-07 18:58:12 +00:00
parent 08d0491006
commit cf0e4f0daf
11 changed files with 411 additions and 282 deletions

View File

@ -15,22 +15,24 @@
namespace lldb_private {
//----------------------------------------------------------------------
// A vm address range. These can represent offsets ranges or actual
// addresses.
//----------------------------------------------------------------------
template <typename B, typename S, class T>
class RangeMap
{
public:
typedef B RangeBaseType;
typedef S RangeSizeType;
typedef T EntryDataType;
//----------------------------------------------------------------------
// Templatized classes for dealing with generic ranges and also
// collections of ranges, or collections of ranges that have associated
// data.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// A simple range class where you get to define the type of the range
// base "B", and the type used for the range byte size "S".
//----------------------------------------------------------------------
template <typename B, typename S>
struct Range
{
RangeBaseType base;
RangeSizeType size;
typedef B BaseType;
typedef S SizeType;
BaseType base;
SizeType size;
Range () :
base (0),
@ -38,33 +40,33 @@ public:
{
}
Range (RangeBaseType b, RangeSizeType s) :
Range (BaseType b, SizeType s) :
base (b),
size (s)
{
}
// Set the start value for the range, and keep the same size
RangeBaseType
GetBase () const
BaseType
GetRangeBase () const
{
return base;
}
void
SetBase (RangeBaseType b)
SetRangeBase (BaseType b)
{
base = b;
}
RangeBaseType
GetEnd () const
BaseType
GetRangeEnd () const
{
return base + size;
}
void
SetEnd (RangeBaseType end)
SetRangeEnd (BaseType end)
{
if (end > base)
size = end - base;
@ -72,14 +74,14 @@ public:
size = 0;
}
RangeSizeType
GetSize () const
SizeType
GetByteSize () const
{
return size;
}
void
SetSize (RangeSizeType s)
SetByteSize (SizeType s)
{
size = s;
}
@ -91,21 +93,21 @@ public:
}
bool
Contains (RangeBaseType r) const
Contains (BaseType r) const
{
return (GetBase() <= r) && (r < GetEnd());
return (GetRangeBase() <= r) && (r < GetRangeEnd());
}
bool
ContainsEndInclusive (RangeBaseType r) const
ContainsEndInclusive (BaseType r) const
{
return (GetBase() <= r) && (r <= GetEnd());
return (GetRangeBase() <= r) && (r <= GetRangeEnd());
}
bool
Contains (const Range& range) const
{
return Contains(range.GetBase()) && ContainsEndInclusive(range.GetEnd());
return Contains(range.GetRangeBase()) && ContainsEndInclusive(range.GetRangeEnd());
}
bool
@ -128,179 +130,318 @@ public:
return base != rhs.base || size != rhs.size;
}
};
struct Entry
{
Range range;
EntryDataType data;
Entry () :
range (),
data ()
{
}
Entry (RangeBaseType base, RangeSizeType size, EntryDataType d) :
range (base, size),
data (d)
{
}
bool
operator < (const Entry &rhs) const
{
const RangeBaseType lhs_base = range.GetBase();
const RangeBaseType rhs_base = rhs.range.GetBase();
if (lhs_base == rhs_base)
{
const RangeBaseType lhs_size = range.GetSize();
const RangeBaseType rhs_size = rhs.range.GetSize();
if (lhs_size == rhs_size)
return data < rhs.data;
else
return lhs_size < rhs_size;
}
return lhs_base < rhs_base;
}
bool
operator == (const Entry &rhs) const
{
return range.GetBase() == rhs.range.GetBase() &&
range.GetSize() == rhs.range.GetSize() &&
data == rhs.data;
}
bool
operator != (const Entry &rhs) const
//----------------------------------------------------------------------
// A range array class where you get to define the type of the ranges
// that the collection contains.
//----------------------------------------------------------------------
template <typename B, typename S>
class RangeArray
{
typedef Range<B,S> Entry;
RangeArray ()
{
return range.GetBase() != rhs.range.GetBase() ||
range.GetSize() != rhs.range.GetSize() ||
data != rhs.data;
}
};
RangeMap ()
{
}
~RangeMap()
{
}
void
Append (const Entry &entry)
{
m_entries.push_back (entry);
}
void
Sort ()
{
if (m_entries.size() > 1)
std::stable_sort (m_entries.begin(), m_entries.end());
}
void
CombineConsecutiveEntriesWithEqualData ()
{
typename std::vector<Entry>::iterator pos;
typename std::vector<Entry>::iterator end;
typename std::vector<Entry>::iterator prev;
bool can_combine = false;
// First we determine if we can combine any of the Entry objects so we
// don't end up allocating and making a new collection for no reason
for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
{
if (prev != end && prev->data == pos->data)
{
can_combine = true;
break;
}
}
// We we can combine at least one entry, then we make a new collection
// and populate it accordingly, and then swap it into place.
if (can_combine)
~RangeArray()
{
std::vector<Entry> minimal_ranges;
}
void
Append (const Entry &entry)
{
m_entries.push_back (entry);
}
void
Sort ()
{
if (m_entries.size() > 1)
std::stable_sort (m_entries.begin(), m_entries.end());
}
void
CombineConsecutiveEntriesWithEqualData ()
{
typename std::vector<Entry>::iterator pos;
typename std::vector<Entry>::iterator end;
typename std::vector<Entry>::iterator prev;
bool can_combine = false;
// First we determine if we can combine any of the Entry objects so we
// don't end up allocating and making a new collection for no reason
for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
{
if (prev != end && prev->data == pos->data)
minimal_ranges.back().range.SetEnd (pos->range.GetEnd());
else
minimal_ranges.push_back (*pos);
{
can_combine = true;
break;
}
}
// Use the swap technique in case our new vector is much smaller.
// We must swap when using the STL because std::vector objects never
// release or reduce the memory once it has been allocated/reserved.
m_entries.swap (minimal_ranges);
}
}
void
Clear ()
{
m_entries.clear();
}
bool
IsEmpty () const
{
return m_entries.empty();
}
size_t
GetNumEntries () const
{
return m_entries.size();
}
const Entry *
GetEntryAtIndex (uint32_t i) const
{
if (i<m_entries.size())
return &m_entries[i];
return NULL;
}
static bool
BaseLessThan (const Entry& lhs, const Entry& rhs)
{
return lhs.range.GetBase() < rhs.range.GetBase();
}
const Entry *
FindEntryThatContains (RangeBaseType addr) const
{
if ( !m_entries.empty() )
{
Entry entry;
entry.range.SetBase(addr);
typename std::vector<Entry>::const_iterator begin = m_entries.begin();
typename std::vector<Entry>::const_iterator end = m_entries.end();
typename std::vector<Entry>::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
if ((pos != end) && (pos->range.GetBase() <= addr && addr < pos->range.GetEnd()))
// We we can combine at least one entry, then we make a new collection
// and populate it accordingly, and then swap it into place.
if (can_combine)
{
return &(*pos);
std::vector<Entry> minimal_ranges;
for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
{
if (prev != end && prev->data == pos->data)
minimal_ranges.back().range.SetEnd (pos->range.GetRangeEnd());
else
minimal_ranges.push_back (*pos);
}
// Use the swap technique in case our new vector is much smaller.
// We must swap when using the STL because std::vector objects never
// release or reduce the memory once it has been allocated/reserved.
m_entries.swap (minimal_ranges);
}
else if (pos != begin)
}
void
Clear ()
{
m_entries.clear();
}
bool
IsEmpty () const
{
return m_entries.empty();
}
size_t
GetNumEntries () const
{
return m_entries.size();
}
const Entry *
GetEntryAtIndex (uint32_t i) const
{
if (i<m_entries.size())
return &m_entries[i];
return NULL;
}
static bool
BaseLessThan (const Entry& lhs, const Entry& rhs)
{
return lhs.GetRangeBase() < rhs.GetRangeBase();
}
const Entry *
FindEntryThatContains (B addr) const
{
if ( !m_entries.empty() )
{
--pos;
if ((pos->range.GetBase() <= addr) && (addr < pos->range.GetEnd()))
Entry entry (addr, 1);
typename std::vector<Entry>::const_iterator begin = m_entries.begin();
typename std::vector<Entry>::const_iterator end = m_entries.end();
typename std::vector<Entry>::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
if (pos != end && pos->Contains(addr))
{
return &(*pos);
}
else if (pos != begin)
{
--pos;
if (pos->Contains(addr))
{
return &(*pos);
}
}
}
return NULL;
}
protected:
std::vector<Entry> m_entries;
};
//----------------------------------------------------------------------
// A simple range with data class where you get to define the type of
// the range base "B", the type used for the range byte size "S", and
// the type for the associated data "T".
//----------------------------------------------------------------------
template <typename B, typename S, typename T>
struct RangeData : public Range<B,S>
{
typedef T DataType;
DataType data;
RangeData () :
Range<B,S> (),
data ()
{
}
RangeData (B base, S size, DataType d) :
Range<B,S> (base, size),
data (d)
{
}
bool
operator < (const RangeData &rhs) const
{
if (this->base == rhs.base)
{
if (this->size == rhs.size)
return this->data < rhs.data;
else
return this->size < rhs.size;
}
return this->base < rhs.base;
}
bool
operator == (const RangeData &rhs) const
{
return this->GetRangeBase() == rhs.GetRangeBase() &&
this->GetByteSize() == rhs.GetByteSize() &&
this->data == rhs.data;
}
bool
operator != (const RangeData &rhs) const
{
return this->GetRangeBase() != rhs.GetRangeBase() ||
this->GetByteSize() != rhs.GetByteSize() ||
this->data != rhs.data;
}
};
template <typename B, typename S, typename T>
class RangeDataArray
{
public:
typedef RangeData<B,S,T> Entry;
RangeDataArray ()
{
}
~RangeDataArray()
{
}
void
Append (const Entry &entry)
{
m_entries.push_back (entry);
}
void
Sort ()
{
if (m_entries.size() > 1)
std::stable_sort (m_entries.begin(), m_entries.end());
}
void
CombineConsecutiveEntriesWithEqualData ()
{
typename std::vector<Entry>::iterator pos;
typename std::vector<Entry>::iterator end;
typename std::vector<Entry>::iterator prev;
bool can_combine = false;
// First we determine if we can combine any of the Entry objects so we
// don't end up allocating and making a new collection for no reason
for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
{
if (prev != end && prev->data == pos->data)
{
can_combine = true;
break;
}
}
// We we can combine at least one entry, then we make a new collection
// and populate it accordingly, and then swap it into place.
if (can_combine)
{
std::vector<Entry> minimal_ranges;
for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
{
if (prev != end && prev->data == pos->data)
minimal_ranges.back().SetRangeEnd (pos->GetRangeEnd());
else
minimal_ranges.push_back (*pos);
}
// Use the swap technique in case our new vector is much smaller.
// We must swap when using the STL because std::vector objects never
// release or reduce the memory once it has been allocated/reserved.
m_entries.swap (minimal_ranges);
}
}
return NULL;
}
protected:
std::vector<Entry> m_entries;
};
void
Clear ()
{
m_entries.clear();
}
bool
IsEmpty () const
{
return m_entries.empty();
}
size_t
GetNumEntries () const
{
return m_entries.size();
}
const Entry *
GetEntryAtIndex (uint32_t i) const
{
if (i<m_entries.size())
return &m_entries[i];
return NULL;
}
static bool
BaseLessThan (const Entry& lhs, const Entry& rhs)
{
return lhs.GetRangeBase() < rhs.GetRangeBase();
}
const Entry *
FindEntryThatContains (B addr) const
{
if ( !m_entries.empty() )
{
Entry entry;
entry.SetRangeBase(addr);
entry.SetByteSize(1);
typename std::vector<Entry>::const_iterator begin = m_entries.begin();
typename std::vector<Entry>::const_iterator end = m_entries.end();
typename std::vector<Entry>::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
if (pos != end && pos->Contains(addr))
{
return &(*pos);
}
else if (pos != begin)
{
--pos;
if (pos->Contains(addr))
{
return &(*pos);
}
}
}
return NULL;
}
protected:
std::vector<Entry> m_entries;
};
} // namespace lldb_private

View File

@ -381,7 +381,7 @@ public:
StringToBoolean (const char *s, bool fail_value, bool *success_ptr);
static int32_t
StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, int32_t fail_value, bool *success_ptr);
StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, int32_t fail_value, Error &error);
static lldb::ScriptLanguage
StringToScriptLanguage (const char *s, lldb::ScriptLanguage fail_value, bool *success_ptr);

View File

@ -91,45 +91,42 @@ CommandObjectBreakpointCommandAdd::CommandOptions::SetOptionValue
char short_option = (char) m_getopt_table[option_idx].val;
switch (short_option)
{
case 'o':
m_use_one_liner = true;
m_one_liner = option_arg;
break;
break;
case 's':
{
bool found_one = false;
m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg,
g_option_table[option_idx].enum_values,
eScriptLanguageNone,
&found_one);
if (!found_one)
error.SetErrorStringWithFormat("Invalid enumeration value '%s' for option '%c'.\n",
option_arg,
short_option);
{
case 'o':
m_use_one_liner = true;
m_one_liner = option_arg;
break;
if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault)
{
m_use_commands = false;
m_use_script_language = true;
}
else
{
m_use_commands = true;
m_use_script_language = false;
}
}
break;
case 'e':
bool success_ptr;
m_stop_on_error = Args::StringToBoolean(option_arg, false, &success_ptr);
if (!success_ptr)
error.SetErrorStringWithFormat("Invalid value for stop-on-error: \"%s\".\n", option_arg);
break;
default:
break;
}
case 's':
m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg,
g_option_table[option_idx].enum_values,
eScriptLanguageNone,
error);
if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault)
{
m_use_commands = false;
m_use_script_language = true;
}
else
{
m_use_commands = true;
m_use_script_language = false;
}
break;
case 'e':
{
bool success = false;
m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
if (!success)
error.SetErrorStringWithFormat("Invalid value for stop-on-error: \"%s\".\n", option_arg);
}
break;
default:
break;
}
return error;
}

View File

@ -1876,17 +1876,10 @@ public:
switch (short_option)
{
case 's':
{
bool found_one = false;
m_sort_order = (SortOrder) Args::StringToOptionEnum (option_arg,
g_option_table[option_idx].enum_values,
eSortOrderNone,
&found_one);
if (!found_one)
error.SetErrorStringWithFormat("Invalid enumeration value '%s' for option '%c'.\n",
option_arg,
short_option);
}
error);
break;
default:

View File

@ -307,11 +307,8 @@ public:
case 'm':
{
bool found_one = false;
OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
m_run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one);
if (!found_one)
error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option);
m_run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, error);
}
break;
@ -807,17 +804,16 @@ public:
break;
case 'm':
{
bool found_one = false;
OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
lldb::RunMode run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one);
lldb::RunMode run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, error);
if (!found_one)
error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option);
else if (run_mode == eAllThreads)
m_stop_others = false;
else
m_stop_others = true;
if (error.Success())
{
if (run_mode == eAllThreads)
m_stop_others = false;
else
m_stop_others = true;
}
}
break;
default:

View File

@ -2381,14 +2381,9 @@ void
UserSettingsController::UpdateEnumVariable (OptionEnumValueElement *enum_values,
int *enum_var,
const char *new_value,
Error &err)
Error &error)
{
bool found_one;
*enum_var = Args::StringToOptionEnum (new_value, enum_values, enum_values[0].value, &found_one);
if (!found_one)
err.SetErrorString ("Invalid enumeration value; cannot update variable.\n");
*enum_var = Args::StringToOptionEnum (new_value, enum_values, enum_values[0].value, error);
}
void

View File

@ -834,21 +834,36 @@ Args::StringToVersion (const char *s, uint32_t &major, uint32_t &minor, uint32_t
int32_t
Args::StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, int32_t fail_value, bool *success_ptr)
Args::StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, int32_t fail_value, Error &error)
{
if (enum_values && s && s[0])
if (enum_values)
{
for (int i = 0; enum_values[i].string_value != NULL ; i++)
if (s && s[0])
{
if (strstr(enum_values[i].string_value, s) == enum_values[i].string_value)
for (int i = 0; enum_values[i].string_value != NULL ; i++)
{
if (success_ptr) *success_ptr = true;
return enum_values[i].value;
if (strstr(enum_values[i].string_value, s) == enum_values[i].string_value)
{
error.Clear();
return enum_values[i].value;
}
}
}
StreamString strm;
strm.PutCString ("invalid enumeration value, valid values are: ");
for (int i = 0; enum_values[i].string_value != NULL; i++)
{
strm.Printf ("%s\"%s\"",
i > 0 ? ", " : "",
enum_values[i].string_value);
}
error.SetErrorString(strm.GetData());
}
else
{
error.SetErrorString ("invalid enumeration argument");
}
if (success_ptr) *success_ptr = false;
return fail_value;
}

View File

@ -72,12 +72,9 @@ OptionGroupValueObjectDisplay::SetOptionValue (CommandInterpreter &interpreter,
{
case 'd':
{
bool success;
int32_t result;
result = Args::StringToOptionEnum (option_arg, TargetInstanceSettings::g_dynamic_value_types, 2, &success);
if (!success)
error.SetErrorStringWithFormat("Invalid dynamic value setting: \"%s\".\n", option_arg);
else
result = Args::StringToOptionEnum (option_arg, TargetInstanceSettings::g_dynamic_value_types, 2, error);
if (error.Success())
use_dynamic = (lldb::DynamicValueType) result;
}
break;

View File

@ -64,21 +64,16 @@ OptionGroupWatchpoint::SetOptionValue (CommandInterpreter &interpreter,
char short_option = (char) g_option_table[option_idx].short_option;
switch (short_option)
{
case 'w': {
OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
watch_type = (WatchType) Args::StringToOptionEnum(option_arg, enum_values, 0, &watch_variable);
if (!watch_variable)
error.SetErrorStringWithFormat("Invalid option arg for '-w': '%s'.\n", option_arg);
case 'w':
watch_type = (WatchType) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error);
if (error.Success())
watch_variable = true;
break;
}
case 'x': {
bool success = false;
OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
watch_size = (WatchType) Args::StringToOptionEnum(option_arg, enum_values, 0, &success);
if (!success)
error.SetErrorStringWithFormat("Invalid option arg for '-x': '%s'.\n", option_arg);
case 'x':
watch_size = (WatchType) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error);
break;
}
default:
error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
break;
@ -91,8 +86,8 @@ void
OptionGroupWatchpoint::OptionParsingStarting (CommandInterpreter &interpreter)
{
watch_variable = false;
watch_type = eWatchInvalid;
watch_size = 0;
watch_type = eWatchInvalid;
watch_size = 0;
}

View File

@ -119,8 +119,8 @@ DWARFDebugAranges::Dump (Log *log) const
const RangeToDIE::Entry *entry = m_aranges.GetEntryAtIndex(i);
log->Printf ("0x%8.8x: [0x%llx - 0x%llx)",
entry->data,
entry->range.GetBase(),
entry->range.GetEnd());
entry->GetRangeBase(),
entry->GetRangeEnd());
}
}

View File

@ -20,7 +20,7 @@ class SymbolFileDWARF;
class DWARFDebugAranges
{
protected:
typedef lldb_private::RangeMap<dw_addr_t, uint32_t, dw_offset_t> RangeToDIE;
typedef lldb_private::RangeDataArray<dw_addr_t, uint32_t, dw_offset_t> RangeToDIE;
public:
typedef RangeToDIE::Entry Range;