From 3b75974731ce3c2199978f8d21fd031d918f2327 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Mon, 21 Jan 2013 20:58:32 -0600 Subject: [PATCH] Add basic block and instruction position descriptors --- llvm/debuginfo.py | 60 +++++++++++++++++++++++++++++++++++++++--- test/test_debuginfo.py | 59 ++++++++++++++++++++++++++++------------- 2 files changed, 97 insertions(+), 22 deletions(-) diff --git a/llvm/debuginfo.py b/llvm/debuginfo.py index dfbdcac..8249aef 100644 --- a/llvm/debuginfo.py +++ b/llvm/debuginfo.py @@ -13,6 +13,7 @@ from llvm import _dwarf int32_t = llvm.core.Type.int(32) bool_t = llvm.core.Type.int(1) +p_int32_t = llvm.core.Type.pointer(int32_t) i32 = functools.partial(llvm.core.Constant.int, int32_t) i1 = functools.partial(llvm.core.Constant.int, bool_t) @@ -94,12 +95,16 @@ class DebugInfoDescriptor(object): idx2name = None # { "field_idx" : field_name } name2idx = None # { "field_name" : field_idx } + # Whether the debug descriptor is allowed to be incomplete + # The policy seems unclear ? + accept_optional_data = False + def __init__(self, *args, **kwargs): self.class_init() self.metadata_cache = {} operands = list(args) - if kwargs: + if kwargs or not self.accept_optional_data: operands = build_operand_list(self.type_descriptors, self.idx2name, operands, kwargs) @@ -184,6 +189,12 @@ class MDList(DebugInfoDescriptor): self.type_descriptors = [desc("op", get_md)] * len(operands) super(MDList, self).__init__(*operands) +class NULLDescriptor(DebugInfoDescriptor): + + type_descriptors = [] + + def build_metadata(self, llvm_module): + return llvm.core.Constant.null(p_int32_t) class CompileUnitDescriptor(DebugInfoDescriptor): """ @@ -205,6 +216,8 @@ class CompileUnitDescriptor(DebugInfoDescriptor): } """ + accept_optional_data = True + type_descriptors = [ desc("tag", get_i32), desc("unused", get_i32), @@ -254,7 +267,7 @@ class FileDescriptor(DebugInfoDescriptor): # Positional argument list starts here: desc("source_filename", get_mdstr), desc("source_filedir", get_mdstr), - desc("compile_unit", get_md), + desc("compile_unit", get_md, default=NULLDescriptor()), ] def __init__(self, *args, **kwargs): @@ -297,12 +310,14 @@ class SubprogramDescriptor(DebugInfoDescriptor): } """ + accept_optional_data = True + type_descriptors = [ desc("tag", get_i32), desc("unused", get_i32), # Positional argument list starts here: - desc("compile_unit", get_md), + desc("file_desc", get_md), desc("name", get_mdstr), desc("display_name", get_mdstr), desc("mips_linkage_name", get_mdstr), @@ -327,3 +342,42 @@ class SubprogramDescriptor(DebugInfoDescriptor): _dwarf.DW_TAG_subprogram + _dwarf.LLVMDebugVersion, # Tag 0, # Unused *args, **kwargs) + +class BlockDescriptor(DebugInfoDescriptor): + """ + !3 = metadata !{ + i32, ;; Tag = 11 + LLVMDebugVersion (DW_TAG_lexical_block) + metadata,;; Reference to context descriptor + i32, ;; Line number + i32 ;; Column number + } + """ + + type_descriptors = [ + desc("tag", get_i32), + + # Positional argument list starts here: + desc("context_descr", get_md), # FileDescr | BlockDescr | + # SubprogDescr | ComputeUnit + desc("line_number", get_i32), + desc("col_number", get_i32), + ] + + def __init__(self, *args, **kwargs): + super(BlockDescriptor, self).__init__( + _dwarf.DW_TAG_lexical_block + _dwarf.LLVMDebugVersion, + *args, **kwargs) + +class PositionInfoDescriptor(DebugInfoDescriptor): + """ + line number, column number, scope, and original scope + """ + + type_descriptors = [ + desc("line_number", get_i32), + desc("col_number", get_i32), + desc("context_descr", get_md), # Scope of instruction + # (FileDescr etc) + desc("original_context_descr", get_md, # The original scope if inlined + default=NULLDescriptor()), + ] diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py index 22d3deb..528ae6f 100644 --- a/test/test_debuginfo.py +++ b/test/test_debuginfo.py @@ -31,21 +31,15 @@ class TestDebugInfo(unittest.TestCase): bb = square.append_basic_block('entry') bldr = Builder.new(bb) - compile_unit = debuginfo.CompileUnitDescriptor( - # DW_LANG_Python segfaults: - # llvm/ADT/StringRef.h:79: llvm::StringRef::StringRef(const char*): - # Assertion `Str && "StringRef cannot be built from a NULL argument"' - # _dwarf.DW_LANG_Python, - _dwarf.DW_LANG_C89, - "test_debug_info.py", - os.path.expanduser("~"), - "my_cool_compiler", - ) + source_filename = "test_debug_info.py" + source_filedir = os.path.expanduser("~") - filedesc = debuginfo.FileDescriptor.from_compileunit(compile_unit) + # Debug info for our file + filedesc = debuginfo.FileDescriptor(source_filename, source_filedir) + # Debug info for our function subprogram = debuginfo.SubprogramDescriptor( - compile_unit, + filedesc, "some_function", "some_function", "some_function", @@ -56,26 +50,53 @@ class TestDebugInfo(unittest.TestCase): ) subprograms = debuginfo.MDList([subprogram]) - # compile_unit.add_metadata("subprograms", subprograms) - compile_unit.define(mod) - subprogram.define(mod) + # Debug info for our basic blocks + blockdescr1 = debuginfo.BlockDescriptor(subprogram, 2, 4) # lineno, col + blockdescr2 = debuginfo.BlockDescriptor(blockdescr1, 3, 4) # lineno, col + # Debug info for our instructions + posinfo1 = debuginfo.PositionInfoDescriptor(2, 4, blockdescr1) + posinfo2 = debuginfo.PositionInfoDescriptor(2, 4, blockdescr2) + + # Debug info for our module + compile_unit = debuginfo.CompileUnitDescriptor( + # DW_LANG_Python segfaults: + # llvm/ADT/StringRef.h:79: llvm::StringRef::StringRef(const char*): + # Assertion `Str && "StringRef cannot be built from a NULL argument"' + # _dwarf.DW_LANG_Python, + _dwarf.DW_LANG_C89, + source_filename, + source_filedir, + "my_cool_compiler", + subprograms=subprograms, + ) + + # Define our module debug data + compile_unit.define(mod) + + # Build some instructions value = square.args[0] result = bldr.fmul(value, value) - bldr.ret(result) + ret = bldr.ret(result) - print mod + # Annotate instructions with source position + result.set_metadata("dbg", posinfo1.get_metadata(mod)) + ret.set_metadata("dbg", posinfo2.get_metadata(mod)) + + # ... Aaaand, test... + # print mod modstr = str(mod) # Test compile unit self.assertIn("my_cool_compiler", modstr) - self.assertIn("test_debug_info.py", modstr) - self.assertIn(os.path.expanduser("~"), modstr) + self.assertIn(source_filename, modstr) + self.assertIn(source_filedir, modstr) self.assertIn("my_cool_compiler", modstr) # Test subprogram self.assertIn("some_function", modstr) + self.assertIn("float (float)* @square", modstr) if __name__ == '__main__': # TestDebugInfo("test_dwarf_constants").debug()