diff --git a/llvm/utils/lldbDataFormatters.py b/llvm/utils/lldbDataFormatters.py --- a/llvm/utils/lldbDataFormatters.py +++ b/llvm/utils/lldbDataFormatters.py @@ -5,18 +5,28 @@ """ import lldb +import json def __lldb_init_module(debugger, internal_dict): debugger.HandleCommand('type category define -e llvm -l c++') debugger.HandleCommand('type synthetic add -w llvm ' '-l lldbDataFormatters.SmallVectorSynthProvider ' '-x "^llvm::SmallVectorImpl<.+>$"') + debugger.HandleCommand('type summary add -w llvm ' + '-s "size=${svar%#}" ' + '-x "^llvm::SmallVectorImpl<.+>$"') debugger.HandleCommand('type synthetic add -w llvm ' '-l lldbDataFormatters.SmallVectorSynthProvider ' '-x "^llvm::SmallVector<.+,.+>$"') + debugger.HandleCommand('type summary add -w llvm ' + '-s "size=${svar%#}" ' + '-x "^llvm::SmallVector<.+,.+>$"') debugger.HandleCommand('type synthetic add -w llvm ' '-l lldbDataFormatters.ArrayRefSynthProvider ' '-x "^llvm::ArrayRef<.+>$"') + debugger.HandleCommand('type summary add -w llvm ' + '-s "size=${svar%#}" ' + '-x "^llvm::ArrayRef<.+>$"') debugger.HandleCommand('type synthetic add -w llvm ' '-l lldbDataFormatters.OptionalSynthProvider ' '-x "^llvm::Optional<.+>$"') @@ -32,6 +42,13 @@ debugger.HandleCommand('type summary add -w llvm ' '-F lldbDataFormatters.ConstStringSummaryProvider ' '-x "^lldb_private::ConstString$"') + debugger.HandleCommand('type synthetic add -w llvm ' + '-l lldbDataFormatters.PointerIntPairSynthProvider ' + '-x "^llvm::PointerIntPair<.+>$"') + debugger.HandleCommand('type synthetic add -w llvm ' + '-l lldbDataFormatters.PointerUnionSynthProvider ' + '-x "^llvm::PointerUnion<.+>$"') + # Pretty printer for llvm::SmallVector/llvm::SmallVectorImpl class SmallVectorSynthProvider: @@ -151,19 +168,122 @@ res += "\"" return res + def StringRefSummaryProvider(valobj, internal_dict): if valobj.GetNumChildren() == 2: # StringRef's are also used to point at binary blobs in memory, # so filter out suspiciously long strings. - max_length = 256 - length = valobj.GetChildAtIndex(1).GetValueAsUnsigned(max_length) + max_length = 1024 + actual_length = valobj.GetChildAtIndex(1).GetValueAsUnsigned() + truncate = actual_length > max_length + length = min(max_length, actual_length) if length == 0: - return "NULL" - if length < max_length: - return valobj.GetChildAtIndex(0).GetSummary() - return "" + return '""' + + data = valobj.GetChildAtIndex(0).GetPointeeData(item_count=length) + error = lldb.SBError() + string = data.ReadRawData(error, 0, data.GetByteSize()).decode() + if error.Fail(): + return "" % error.description + + # json.dumps conveniently escapes the string for us. + string = json.dumps(string) + if truncate: + string += "..." + return string + return None + def ConstStringSummaryProvider(valobj, internal_dict): if valobj.GetNumChildren() == 1: return valobj.GetChildAtIndex(0).GetSummary() return "" + + +def get_expression_path(val): + stream = lldb.SBStream() + if not val.GetExpressionPath(stream): + return None + return stream.GetData() + + +class PointerIntPairSynthProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + self.update() + + def num_children(self): + return 2 + + def get_child_index(self, name): + if name == 'Pointer': + return 0 + if name == 'Int': + return 1 + return None + + def get_child_at_index(self, index): + expr_path = get_expression_path(self.valobj) + if index == 0: + return self.valobj.CreateValueFromExpression('Pointer', f'({self.pointer_ty.name}){expr_path}.getPointer()') + if index == 1: + return self.valobj.CreateValueFromExpression('Int', f'({self.int_ty.name}){expr_path}.getInt()') + return None + + def update(self): + self.pointer_ty = self.valobj.GetType().GetTemplateArgumentType(0) + self.int_ty = self.valobj.GetType().GetTemplateArgumentType(2) + + +def parse_template_parameters(typename): + """ + LLDB doesn't support template parameter packs, so let's parse them manually. + """ + result = [] + start = typename.find('<') + end = typename.rfind('>') + if start < 1 or end < 2 or end - start < 2: + return result + + nesting_level = 0 + current_parameter_start = start + 1 + + for i in range(start + 1, end + 1): + c = typename[i] + if c == '<': + nesting_level += 1 + elif c == '>': + nesting_level -= 1 + elif c == ',' and nesting_level == 0: + result.append(typename[current_parameter_start:i].strip()) + current_parameter_start = i + 1 + + result.append(typename[current_parameter_start:i].strip()) + + return result + + +class PointerUnionSynthProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + self.update() + + def num_children(self): + return 1 + + def get_child_index(self, name): + if name == 'Ptr': + return 0 + return None + + def get_child_at_index(self, index): + if index != 0: + return None + ptr_type_name = self.template_args[self.active_type_tag] + return self.valobj.CreateValueFromExpression('Ptr', f'({ptr_type_name}){self.val_expr_path}.getPointer()') + + def update(self): + self.pointer_int_pair = self.valobj.GetChildMemberWithName('Val') + self.val_expr_path = get_expression_path(self.valobj.GetChildMemberWithName('Val')) + self.active_type_tag = self.valobj.CreateValueFromExpression('', f'(int){self.val_expr_path}.getInt()').GetValueAsSigned() + self.template_args = parse_template_parameters(self.valobj.GetType().name)