aboutsummaryrefslogtreecommitdiff
path: root/lldb/test/Shell/ScriptInterpreter/Python
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/test/Shell/ScriptInterpreter/Python')
-rw-r--r--lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/MyOptional.cpp23
-rw-r--r--lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/formatter.py167
-rw-r--r--lldb/test/Shell/ScriptInterpreter/Python/bytecode.test16
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: }