/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
/// extract its data payload. Return the size + payload pair.
+// TODO: Support big-endian architectures.
static llvm::Optional<std::pair<uint64_t, ValueObjectSP>>
ExtractLibcxxStringInfo(ValueObject &valobj) {
ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0}));
ConstString g_size_name("__size_");
bool short_mode = false; // this means the string is in short-mode and the
// data is stored inline
+ bool using_bitmasks = true; // Whether the class uses bitmasks for the mode
+ // flag (pre-D123580).
+ uint64_t size;
LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name)
? eLibcxxStringLayoutModeDSC
: eLibcxxStringLayoutModeCSD;
uint64_t size_mode_value = 0;
- if (layout == eLibcxxStringLayoutModeDSC) {
+ if (ValueObjectSP is_long = D->GetChildAtNamePath(
+ {ConstString("__s"), ConstString("__is_long_")})) {
+ using_bitmasks = false;
+ short_mode = !is_long->GetValueAsUnsigned(/*fail_value=*/0);
+ if (ValueObjectSP size_member =
+ D->GetChildAtNamePath({ConstString("__s"), ConstString("__size_")}))
+ size = size_member->GetValueAsUnsigned(/*fail_value=*/0);
+ else
+ return {};
+ } else if (layout == eLibcxxStringLayoutModeDSC) {
llvm::SmallVector<size_t, 3> size_mode_locations[] = {
- {1, 2}, // Post-c3d0205ee771 layout
+ {1, 2}, // Post-c3d0205ee771 layout. This was in use for only a brief
+ // period, so we can delete it if it becomes a burden.
{1, 1, 0},
{1, 1, 1},
};
return {};
ValueObjectSP location_sp = s->GetChildAtIndex(
(layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true);
- const uint64_t size = (layout == eLibcxxStringLayoutModeDSC)
- ? size_mode_value
- : ((size_mode_value >> 1) % 256);
+ if (using_bitmasks)
+ size = (layout == eLibcxxStringLayoutModeDSC)
+ ? size_mode_value
+ : ((size_mode_value >> 1) % 256);
// When the small-string optimization takes place, the data must fit in the
// inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's
if (!l)
return {};
// we can use the layout_decider object as the data pointer
- ValueObjectSP location_sp = (layout == eLibcxxStringLayoutModeDSC)
- ? layout_decider
- : l->GetChildAtIndex(2, true);
- ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
- const unsigned capacity_index =
- (layout == eLibcxxStringLayoutModeDSC) ? 2 : 0;
- ValueObjectSP capacity_vo(l->GetChildAtIndex(capacity_index, true));
+ ValueObjectSP location_sp =
+ l->GetChildMemberWithName(ConstString("__data_"), /*can_create=*/true);
+ ValueObjectSP size_vo =
+ l->GetChildMemberWithName(ConstString("__size_"), /*can_create=*/true);
+ ValueObjectSP capacity_vo =
+ l->GetChildMemberWithName(ConstString("__cap_"), /*can_create=*/true);
if (!size_vo || !location_sp || !capacity_vo)
return {};
- const uint64_t size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
- const uint64_t capacity =
- capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
+ size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
+ uint64_t capacity = capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
+ if (!using_bitmasks && layout == eLibcxxStringLayoutModeCSD)
+ capacity *= 2;
if (size == LLDB_INVALID_OFFSET || capacity == LLDB_INVALID_OFFSET ||
capacity < size)
return {};