diff options
Diffstat (limited to 'lldb/test/Shell/ScriptInterpreter/Python')
3 files changed, 206 insertions, 0 deletions
diff --git a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/MyOptional.cpp b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/MyOptional.cpp new file mode 100644 index 0000000..abba344 --- /dev/null +++ b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/MyOptional.cpp @@ -0,0 +1,23 @@ +// A bare-bones llvm::Optional reimplementation. + +template <typename T> struct MyOptionalStorage { + MyOptionalStorage(T val) : value(val), hasVal(true) {} + MyOptionalStorage() {} + T value; + bool hasVal = false; +}; + +template <typename T> struct MyOptional { + MyOptionalStorage<T> Storage; + MyOptional(T val) : Storage(val) {} + MyOptional() {} + T &operator*() { return Storage.value; } +}; + +void stop() {} + +int main(int argc, char **argv) { + MyOptional<int> x, y = 42; + stop(); // break here + return *y; +} diff --git a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/formatter.py b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/formatter.py new file mode 100644 index 0000000..cc8778b --- /dev/null +++ b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/formatter.py @@ -0,0 +1,167 @@ +""" +This is the llvm::Optional data formatter from llvm/utils/lldbDataFormatters.py +with the implementation replaced by bytecode. +""" + +from __future__ import annotations +from formatter_bytecode import * +import lldb + + +def __lldb_init_module(debugger, internal_dict): + debugger.HandleCommand( + "type synthetic add -w llvm " + f"-l {__name__}.MyOptionalSynthProvider " + '-x "^MyOptional<.+>$"' + ) + debugger.HandleCommand( + "type summary add -w llvm " + f"-e -F {__name__}.MyOptionalSummaryProvider " + '-x "^MyOptional<.+>$"' + ) + + +def stringify(bytecode: bytearray) -> str: + s = "" + in_hex = False + for b in bytecode: + if (b < 32 or b > 127 or chr(b) in ['"', "`", "'"]) or ( + in_hex + and chr(b).lower() + in [ + "a", + "b", + "c", + "d", + "e", + "f", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + ] + ): + s += r"\x" + hex(b)[2:] + in_hex = True + else: + s += chr(b) + in_hex = False + return s + + +def evaluate(assembler: str, data: list): + bytecode = compile(assembler) + trace = True + if trace: + print( + "Compiled to {0} bytes of bytecode:\n{1}".format( + len(bytecode), stringify(bytecode) + ) + ) + result = interpret(bytecode, [], data, False) # trace) + if trace: + print("--> {0}".format(result)) + return result + + +# def GetOptionalValue(valobj): +# storage = valobj.GetChildMemberWithName("Storage") +# if not storage: +# storage = valobj +# +# failure = 2 +# hasVal = storage.GetChildMemberWithName("hasVal").GetValueAsUnsigned(failure) +# if hasVal == failure: +# return "<could not read MyOptional>" +# +# if hasVal == 0: +# return None +# +# underlying_type = storage.GetType().GetTemplateArgumentType(0) +# storage = storage.GetChildMemberWithName("value") +# return storage.Cast(underlying_type) + + +def MyOptionalSummaryProvider(valobj, internal_dict): + # val = GetOptionalValue(valobj) + # if val is None: + # return "None" + # if val.summary: + # return val.summary + # return val.GetValue() + summary = "" + summary += ' dup "Storage" @get_child_with_name call' # valobj storage + summary += " dup is_null ~ { swap } if drop" # storage + summary += ' dup "hasVal" @get_child_with_name call' # storage obj(hasVal) + summary += ' dup is_null { drop "<could not read MyOptional>" } {' + summary += " @get_value_as_unsigned call" # storage int(hasVal) + summary += ' 0u = { "None" } {' + summary += " dup @get_type call" + summary += " 0u @get_template_argument_type call" # storage type + summary += " swap" # type storage + summary += ' "value" @get_child_with_name call' # type value + summary += " swap @cast call" # type(value) + summary += ' dup is_null { "None" } {' + summary += ( + " dup @summary call dup @strlen call { @get_value call } { drop } ifelse" + ) + summary += " } ifelse" + summary += " } ifelse" + summary += " } ifelse" + return evaluate(summary, [valobj]) + + +class MyOptionalSynthProvider: + """Provides deref support to llvm::Optional<T>""" + + def __init__(self, valobj, internal_dict): + self.valobj = valobj + + def num_children(self): + # return self.valobj.num_children + num_children = " @get_num_children call" + return evaluate(num_children, [self.valobj]) + + def get_child_index(self, name): + # if name == "$$dereference$$": + # return self.valobj.num_children + # return self.valobj.GetIndexOfChildWithName(name) + get_child_index = ' dup "$$dereference$$" =' + get_child_index += " { drop @get_num_children call } {" # obj name + get_child_index += " @get_child_index call" # index + get_child_index += " } ifelse" + return evaluate(get_child_index, [self.valobj, name]) + + def get_child_at_index(self, index): + # if index < self.valobj.num_children: + # return self.valobj.GetChildAtIndex(index) + # return GetOptionalValue(self.valobj) or lldb.SBValue() + get_child_at_index = " over over swap" # obj index index obj + get_child_at_index += " @get_num_children call" # obj index index n + get_child_at_index += " < { @get_child_at_index call } {" # obj index + + get_opt_val = ' dup "Storage" @get_child_with_name call' # valobj storage + get_opt_val += " dup { swap } if drop" # storage + get_opt_val += ' dup "hasVal" @get_child_with_name call' # storage + get_opt_val += " @get_value_as_unsigned call" # storage int(hasVal) + get_opt_val += ' dup 2 = { drop "<could not read MyOptional>" } {' + get_opt_val += ' 0 = { "None" } {' + get_opt_val += ( + " dup @get_type call 0 @get_template_argument_type call" # storage type + ) + get_opt_val += " swap" # type storage + get_opt_val += ' "value" @get_child_with_name call' # type value + get_opt_val += " swap @cast call" # type(value) + get_opt_val += " } ifelse" + get_opt_val += " } ifelse" + + get_child_at_index += get_opt_val + get_child_at_index += " } ifelse" + + return evaluate(get_child_at_index, [self.valobj, index]) diff --git a/lldb/test/Shell/ScriptInterpreter/Python/bytecode.test b/lldb/test/Shell/ScriptInterpreter/Python/bytecode.test new file mode 100644 index 0000000..2745680 --- /dev/null +++ b/lldb/test/Shell/ScriptInterpreter/Python/bytecode.test @@ -0,0 +1,16 @@ +# RUN: %python %S/../../../../examples/python/formatter_bytecode.py --test +# RUN: %python %S/../../../../examples/python/formatter_bytecode.py --compile "1u dup" | FileCheck %s --check-prefix=COMPILE +# RUN: %python %S/../../../../examples/python/formatter_bytecode.py --disassemble "200101" | FileCheck %s --check-prefix=DISASSEMBLE +# COMPILE: 200101 +# DISASSEMBLE: 1u dup + +# RUN: %clang_host -std=c++17 -g %S/Inputs/FormatterBytecode/MyOptional.cpp -o %t.exe +# RUN: %lldb %t.exe -o "command script import %S/../../../../examples/python/formatter_bytecode.py" -o "command script import %S/Inputs/FormatterBytecode/formatter.py" -o "b -p here" -o "r" -o "v x" -o "v y" -o q | FileCheck %s --check-prefix=OPTIONAL +# OPTIONAL: (lldb) v x +# OPTIONAL: (MyOptional<int>) x = { +# OPTIONAL: hasVal = false +# OPTIONAL: } +# OPTIONAL: (lldb) v y +# OPTIONAL: (MyOptional<int>) y = { +# OPTIONAL: Storage = (value = 42, hasVal = true) +# OPTIONAL: } |