commit
1ccda1ca5c
5 changed files with 695 additions and 1 deletions
86
llvm/_dwarf.cpp
Normal file
86
llvm/_dwarf.cpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#include <Python.h>
|
||||
#include <llvm/Support/Dwarf.h>
|
||||
|
||||
namespace llvmpy {
|
||||
namespace dwarf {
|
||||
|
||||
using namespace llvm::dwarf;
|
||||
|
||||
const char *constant_names[] = {
|
||||
"LLVMDebugVersion",
|
||||
|
||||
#define define(x) #x,
|
||||
#include "_dwarf.h"
|
||||
#undef define
|
||||
};
|
||||
|
||||
int constant_values[] = {
|
||||
llvm::LLVMDebugVersion,
|
||||
|
||||
#define define(x) x,
|
||||
#include "_dwarf.h"
|
||||
#undef define
|
||||
};
|
||||
|
||||
enum enum_values {
|
||||
__llvmpy_LLVMDebugVersion,
|
||||
|
||||
#define define(x) __llvmpy_##x,
|
||||
#include "_dwarf.h"
|
||||
#undef define
|
||||
|
||||
NVALUES /* Get the number of constants */
|
||||
};
|
||||
|
||||
} // End namespace dwarf
|
||||
|
||||
int
|
||||
set_dwarf_constants(PyObject *module)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < dwarf::NVALUES; i++) {
|
||||
if (PyModule_AddIntConstant(module, dwarf::constant_names[i],
|
||||
dwarf::constant_values[i]) > 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End namespace llvmpy
|
||||
|
||||
#if (PY_MAJOR_VERSION >= 3)
|
||||
struct PyModuleDef module_def = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_dwarf",
|
||||
NULL,
|
||||
-1,
|
||||
NULL, /* m_methods */
|
||||
NULL, /* m_reload */
|
||||
NULL, /* m_traverse */
|
||||
NULL, /* m_clear */
|
||||
NULL, /* m_free */
|
||||
};
|
||||
|
||||
#define INITERROR return NULL
|
||||
PyObject *PyInit__dwarf(void)
|
||||
#else
|
||||
#define INITERROR return
|
||||
PyMODINIT_FUNC init_dwarf(void)
|
||||
#endif
|
||||
{
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *module = PyModule_Create( &module_def );
|
||||
#else
|
||||
PyObject *module = Py_InitModule("_dwarf", NULL);
|
||||
#endif
|
||||
if (module == NULL)
|
||||
INITERROR;
|
||||
|
||||
if (llvmpy::set_dwarf_constants(module) < 0)
|
||||
INITERROR;
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return module;
|
||||
#endif
|
||||
}
|
||||
101
llvm/_dwarf.h
Normal file
101
llvm/_dwarf.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/* Dwarf constant wrapping. See include/llvm/Support/Dwarf.h */
|
||||
|
||||
define(DWARF_VERSION)
|
||||
|
||||
/* Dwarf tags */
|
||||
define(DW_TAG_array_type)
|
||||
define(DW_TAG_class_type)
|
||||
define(DW_TAG_entry_point)
|
||||
define(DW_TAG_enumeration_type)
|
||||
define(DW_TAG_formal_parameter)
|
||||
define(DW_TAG_imported_declaration)
|
||||
define(DW_TAG_label)
|
||||
define(DW_TAG_lexical_block)
|
||||
define(DW_TAG_member)
|
||||
define(DW_TAG_pointer_type)
|
||||
define(DW_TAG_reference_type)
|
||||
define(DW_TAG_compile_unit)
|
||||
define(DW_TAG_string_type)
|
||||
define(DW_TAG_structure_type)
|
||||
define(DW_TAG_subroutine_type)
|
||||
define(DW_TAG_typedef)
|
||||
define(DW_TAG_union_type)
|
||||
define(DW_TAG_unspecified_parameters)
|
||||
define(DW_TAG_variant)
|
||||
define(DW_TAG_common_block)
|
||||
define(DW_TAG_common_inclusion)
|
||||
define(DW_TAG_inheritance)
|
||||
define(DW_TAG_inlined_subroutine)
|
||||
define(DW_TAG_module)
|
||||
define(DW_TAG_ptr_to_member_type)
|
||||
define(DW_TAG_set_type)
|
||||
define(DW_TAG_subrange_type)
|
||||
define(DW_TAG_with_stmt)
|
||||
define(DW_TAG_access_declaration)
|
||||
define(DW_TAG_base_type)
|
||||
define(DW_TAG_catch_block)
|
||||
define(DW_TAG_const_type)
|
||||
define(DW_TAG_constant)
|
||||
define(DW_TAG_enumerator)
|
||||
define(DW_TAG_file_type)
|
||||
define(DW_TAG_friend)
|
||||
define(DW_TAG_namelist)
|
||||
define(DW_TAG_namelist_item)
|
||||
define(DW_TAG_packed_type)
|
||||
define(DW_TAG_subprogram)
|
||||
define(DW_TAG_template_type_parameter)
|
||||
define(DW_TAG_template_value_parameter)
|
||||
define(DW_TAG_thrown_type)
|
||||
define(DW_TAG_try_block)
|
||||
define(DW_TAG_variant_part)
|
||||
define(DW_TAG_variable)
|
||||
define(DW_TAG_volatile_type)
|
||||
define(DW_TAG_dwarf_procedure)
|
||||
define(DW_TAG_restrict_type)
|
||||
define(DW_TAG_interface_type)
|
||||
define(DW_TAG_namespace)
|
||||
define(DW_TAG_imported_module)
|
||||
define(DW_TAG_unspecified_type)
|
||||
define(DW_TAG_partial_unit)
|
||||
define(DW_TAG_imported_unit)
|
||||
define(DW_TAG_condition)
|
||||
define(DW_TAG_shared_type)
|
||||
define(DW_TAG_type_unit)
|
||||
define(DW_TAG_rvalue_reference_type)
|
||||
define(DW_TAG_template_alias)
|
||||
define(DW_TAG_MIPS_loop)
|
||||
define(DW_TAG_format_label)
|
||||
define(DW_TAG_function_template)
|
||||
define(DW_TAG_class_template)
|
||||
define(DW_TAG_GNU_template_template_param)
|
||||
define(DW_TAG_GNU_template_parameter_pack)
|
||||
define(DW_TAG_GNU_formal_parameter_pack)
|
||||
define(DW_TAG_lo_user)
|
||||
define(DW_TAG_APPLE_property)
|
||||
define(DW_TAG_hi_user)
|
||||
|
||||
/* Dwarf language constants */
|
||||
define(DW_LANG_C89)
|
||||
define(DW_LANG_C)
|
||||
define(DW_LANG_Ada83)
|
||||
define(DW_LANG_C_plus_plus)
|
||||
define(DW_LANG_Cobol74)
|
||||
define(DW_LANG_Cobol85)
|
||||
define(DW_LANG_Fortran77)
|
||||
define(DW_LANG_Fortran90)
|
||||
define(DW_LANG_Pascal83)
|
||||
define(DW_LANG_Modula2)
|
||||
define(DW_LANG_Java)
|
||||
define(DW_LANG_C99)
|
||||
define(DW_LANG_Ada95)
|
||||
define(DW_LANG_Fortran95)
|
||||
define(DW_LANG_PLI)
|
||||
define(DW_LANG_ObjC)
|
||||
define(DW_LANG_ObjC_plus_plus)
|
||||
define(DW_LANG_UPC)
|
||||
define(DW_LANG_D)
|
||||
define(DW_LANG_Python)
|
||||
define(DW_LANG_lo_user)
|
||||
define(DW_LANG_Mips_Assembler)
|
||||
define(DW_LANG_hi_user)
|
||||
|
||||
398
llvm/debuginfo.py
Normal file
398
llvm/debuginfo.py
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
"""
|
||||
Support for debug info metadata.
|
||||
"""
|
||||
|
||||
import functools
|
||||
|
||||
import llvm.core
|
||||
from llvm import _dwarf
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Some types and type checking functions
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
int32_t = llvm.core.Type.int(32)
|
||||
bool_t = llvm.core.Type.int(1)
|
||||
p_int32_t = llvm.core.Type.pointer(int32_t)
|
||||
null = llvm.core.Constant.null(p_int32_t)
|
||||
|
||||
i32 = functools.partial(llvm.core.Constant.int, int32_t)
|
||||
i1 = functools.partial(llvm.core.Constant.int, bool_t)
|
||||
|
||||
def is_md(value):
|
||||
return isinstance(value, (llvm.core.MetaData, llvm.core.NamedMetaData,
|
||||
llvm.core.Value))
|
||||
|
||||
def is_mdstr(value):
|
||||
return isinstance(value, (llvm.core.MetaDataString, llvm.core.Value))
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Callbacks for debug type descriptors
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
def get_i32(llvm_module, value):
|
||||
return i32(value)
|
||||
|
||||
def get_i1(llvm_module, value):
|
||||
return i1(value)
|
||||
|
||||
def get_md(llvm_module, value):
|
||||
if is_md(value):
|
||||
return value
|
||||
return value.get_metadata(llvm_module)
|
||||
|
||||
def get_mdstr(llvm_module, value):
|
||||
if is_mdstr(value):
|
||||
return value
|
||||
return llvm.core.MetaDataString.get(llvm_module, value)
|
||||
|
||||
def get_mdlist(llvm_module, value):
|
||||
if isinstance(value, list):
|
||||
value = MDList([value])
|
||||
return get_md(llvm_module, value)
|
||||
|
||||
def get_lfunc(llvm_module, lfunc):
|
||||
assert lfunc.module is llvm_module
|
||||
return lfunc
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Debug descriptors that generate LLVM Metadata
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
class desc(object):
|
||||
"""
|
||||
Descriptor of a debug field.
|
||||
|
||||
field_name:
|
||||
name of the field (keyword argument name)
|
||||
build_metadata:
|
||||
metadata callback :: (llvm_module, Python value) -> LLVM Value
|
||||
default:
|
||||
default value for this field
|
||||
"""
|
||||
|
||||
def __init__(self, field_name, build_metadata, default=None):
|
||||
self.field_name = field_name
|
||||
self.build_metadata = build_metadata
|
||||
self.default = default
|
||||
|
||||
|
||||
def build_operand_list(type_descriptors, idx2name, operands, kwargs):
|
||||
"""
|
||||
Build the list of operands from the positional and keyword arguments
|
||||
to a DebugInfoDescriptor.
|
||||
|
||||
E.g. FileDescriptor("foo.c", "/path/to/file", compile_unit=compile_unit)
|
||||
|
||||
idx2name: {0 : 'source_filename',
|
||||
1 : 'source_filedir',
|
||||
2 : 'compile_unit' }
|
||||
operands: ["foo.c", "/path/to/file"]
|
||||
kwargs: { 'compile_unit' : compile_unit }
|
||||
"""
|
||||
for i in range(len(operands), len(type_descriptors)):
|
||||
name = idx2name[i]
|
||||
if name in kwargs:
|
||||
op = kwargs[name]
|
||||
else:
|
||||
typedesc = type_descriptors[i]
|
||||
assert typedesc.default is not None, (
|
||||
"No value found for field %s" % typedesc.field_name)
|
||||
op = typedesc.default
|
||||
|
||||
operands.append(op)
|
||||
|
||||
return operands
|
||||
|
||||
|
||||
class DebugInfoDescriptor(object):
|
||||
"""
|
||||
Base class to describe a debug info descriptor.
|
||||
|
||||
See http://llvm.org/docs/SourceLevelDebugging.html
|
||||
"""
|
||||
|
||||
type_descriptors = None # [desc(...)]
|
||||
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 or not self.accept_optional_data:
|
||||
operands = build_operand_list(self.type_descriptors,
|
||||
self.idx2name, operands, kwargs)
|
||||
|
||||
self.operands = operands
|
||||
self.operands_dict = dict(
|
||||
(typedesc.field_name, operand)
|
||||
for typedesc, operand in zip(self.type_descriptors, operands))
|
||||
|
||||
@classmethod
|
||||
def class_init(cls):
|
||||
if cls.idx2name is None and cls.type_descriptors is not None:
|
||||
cls.name2idx = {}
|
||||
cls.idx2name = {}
|
||||
|
||||
for i, typedesc in enumerate(cls.type_descriptors):
|
||||
cls.name2idx[typedesc.field_name] = i
|
||||
cls.idx2name[i] = typedesc.field_name
|
||||
|
||||
def add_metadata(self, metadata_name, metadata):
|
||||
"""
|
||||
Replace a metadata value in the operand list.
|
||||
"""
|
||||
idx = self.name2idx[metadata_name]
|
||||
self.operands[idx] = metadata
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# Define metadata in a module
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
def get_metadata(self, llvm_module):
|
||||
"""
|
||||
Get an existing metadata node for the given LLVM module, or build
|
||||
one from this instance.
|
||||
"""
|
||||
if llvm_module in self.metadata_cache:
|
||||
node = self.metadata_cache[llvm_module]
|
||||
else:
|
||||
node = self.build_metadata(llvm_module)
|
||||
self.metadata_cache[llvm_module] = node
|
||||
|
||||
return node
|
||||
|
||||
def build_metadata(self, llvm_module):
|
||||
"Build a metadata node for the given LLVM module"
|
||||
mdops = []
|
||||
for type_desc, operand in zip(self.type_descriptors, self.operands):
|
||||
try:
|
||||
field_value = type_desc.build_metadata(llvm_module, operand)
|
||||
except Exception, e:
|
||||
if type_desc.build_metadata is get_md:
|
||||
raise
|
||||
|
||||
raise ValueError("Invalid value for field %r: %s" % (
|
||||
type_desc.field_name, e))
|
||||
|
||||
mdops.append(field_value)
|
||||
|
||||
return llvm.core.MetaData.get(llvm_module, mdops)
|
||||
|
||||
def define(self, llvm_module):
|
||||
"""
|
||||
Define this debug descriptor as named debug metadata for the module.
|
||||
"""
|
||||
md = self.get_metadata(llvm_module)
|
||||
llvm.core.MetaData.add_named_operand(llvm_module, "dbg", md)
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Convenience descriptors
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
class MDList(DebugInfoDescriptor):
|
||||
"""
|
||||
[MetaData]
|
||||
"""
|
||||
|
||||
def __init__(self, operands):
|
||||
self.type_descriptors = [desc("op", get_md)] * len(operands)
|
||||
super(MDList, self).__init__(*operands)
|
||||
|
||||
empty = MDList([])
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Dwarf Debug descriptors
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
class CompileUnitDescriptor(DebugInfoDescriptor):
|
||||
"""
|
||||
!0 = metadata !{
|
||||
i32, ;; Tag = 17 + LLVMDebugVersion (DW_TAG_compile_unit)
|
||||
i32, ;; Unused field.
|
||||
i32, ;; DWARF language identifier (ex. DW_LANG_C89)
|
||||
metadata, ;; Source file name
|
||||
metadata, ;; Source file directory (includes trailing slash)
|
||||
metadata ;; Producer (ex. "4.0.1 LLVM (LLVM research group)")
|
||||
i1, ;; True if this is a main compile unit.
|
||||
i1, ;; True if this is optimized.
|
||||
metadata, ;; Flags
|
||||
i32 ;; Runtime version
|
||||
metadata ;; List of enums types
|
||||
metadata ;; List of retained types
|
||||
metadata ;; List of subprograms
|
||||
metadata ;; List of global variables
|
||||
}
|
||||
"""
|
||||
|
||||
accept_optional_data = True
|
||||
|
||||
type_descriptors = [
|
||||
desc("tag", get_i32),
|
||||
desc("unused", get_i32),
|
||||
|
||||
# Positional argument list starts here:
|
||||
desc("langid", get_i32),
|
||||
desc("source_filename", get_mdstr),
|
||||
desc("source_filedir", get_mdstr),
|
||||
desc("producer", get_mdstr),
|
||||
desc("is_main", get_i1, default=False),
|
||||
desc("is_optimized", get_i1, default=False),
|
||||
desc("compile_flags", get_mdstr, default=""),
|
||||
desc("runtime_version", get_i32, default=0),
|
||||
desc("enum_types", get_mdlist, default=empty),
|
||||
desc("retained_types", get_mdlist, default=empty),
|
||||
desc("subprograms", get_mdlist, default=empty),
|
||||
desc("global_vars", get_mdlist, default=empty),
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CompileUnitDescriptor, self).__init__(
|
||||
_dwarf.DW_TAG_compile_unit + _dwarf.LLVMDebugVersion, # tag
|
||||
0, # unused
|
||||
*args, **kwargs)
|
||||
|
||||
def define(self, llvm_module):
|
||||
"""
|
||||
Define this debug descriptor as named debug metadata for the module.
|
||||
"""
|
||||
md = self.get_metadata(llvm_module)
|
||||
llvm.core.MetaData.add_named_operand(llvm_module, "llvm.dbg.cu", md)
|
||||
|
||||
|
||||
class FileDescriptor(DebugInfoDescriptor):
|
||||
"""
|
||||
!0 = metadata !{
|
||||
i32, ;; Tag = 41 + LLVMDebugVersion (DW_TAG_file_type)
|
||||
metadata, ;; Source file name
|
||||
metadata, ;; Source file directory (includes trailing slash)
|
||||
metadata ;; Unused
|
||||
}
|
||||
"""
|
||||
|
||||
type_descriptors = [
|
||||
desc("tag", get_i32),
|
||||
|
||||
# Positional argument list starts here:
|
||||
desc("source_filename", get_mdstr),
|
||||
desc("source_filedir", get_mdstr),
|
||||
desc("compile_unit", get_md, default=null),
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FileDescriptor, self).__init__(
|
||||
_dwarf.DW_TAG_file_type + _dwarf.LLVMDebugVersion, # Tag
|
||||
*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def from_compileunit(cls, compile_unit_descriptor):
|
||||
return cls(compile_unit_descriptor.operands_dict["source_filename"],
|
||||
compile_unit_descriptor.operands_dict["source_filedir"],
|
||||
compile_unit_descriptor)
|
||||
|
||||
|
||||
class SubprogramDescriptor(DebugInfoDescriptor):
|
||||
"""
|
||||
!2 = metadata !{
|
||||
i32, ;; Tag = 46 + LLVMDebugVersion (DW_TAG_subprogram)
|
||||
i32, ;; Unused field.
|
||||
metadata, ;; Reference to context descriptor
|
||||
metadata, ;; Name
|
||||
metadata, ;; Display name (fully qualified C++ name)
|
||||
metadata, ;; MIPS linkage name (for C++)
|
||||
metadata, ;; Reference to file where defined
|
||||
i32, ;; Line number where defined
|
||||
metadata, ;; Reference to type descriptor
|
||||
i1, ;; True if the global is local to compile unit (static)
|
||||
i1, ;; True if the global is defined in the compile unit (not extern)
|
||||
i32, ;; Line number where the scope of the subprogram begins
|
||||
i32, ;; Virtuality, e.g. dwarf::DW_VIRTUALITY__virtual
|
||||
i32, ;; Index into a virtual function
|
||||
metadata, ;; indicates which base type contains the vtable pointer for the
|
||||
;; derived class
|
||||
i32, ;; Flags - Artifical, Private, Protected, Explicit, Prototyped.
|
||||
i1, ;; isOptimized
|
||||
Function * , ;; Pointer to LLVM function
|
||||
metadata, ;; Lists function template parameters
|
||||
metadata, ;; Function declaration descriptor
|
||||
metadata ;; List of function variables
|
||||
}
|
||||
"""
|
||||
|
||||
accept_optional_data = True
|
||||
|
||||
type_descriptors = [
|
||||
desc("tag", get_i32),
|
||||
desc("unused", get_i32),
|
||||
|
||||
# Positional argument list starts here:
|
||||
desc("file_desc", get_md),
|
||||
desc("name", get_mdstr),
|
||||
desc("display_name", get_mdstr),
|
||||
desc("mips_linkage_name", get_mdstr),
|
||||
desc("source_file_ref", get_md),
|
||||
desc("line_number", get_i32),
|
||||
desc("signature", get_md),
|
||||
desc("is_local", get_i1, default=False),
|
||||
desc("is_definition", get_i1, default=True),
|
||||
desc("virtual_attribute", get_i32, default=0),
|
||||
desc("virtual_index", get_i32, default=0),
|
||||
desc("virttab", get_i32, default=0),
|
||||
desc("flags", get_i32, default=0),
|
||||
desc("is_optimized", get_i1, default=False),
|
||||
desc("llvm_func", get_lfunc),
|
||||
# Template params
|
||||
# Func decl
|
||||
# Func vars
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SubprogramDescriptor, self).__init__(
|
||||
_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=null),
|
||||
]
|
||||
7
setup.py
7
setup.py
|
|
@ -116,7 +116,12 @@ kwds = dict(ext_modules = [Extension(
|
|||
library_dirs = [libdir],
|
||||
libraries = libs_core,
|
||||
extra_objects = objs_core,
|
||||
extra_link_args = extra_link_args)])
|
||||
extra_link_args = extra_link_args),
|
||||
|
||||
Extension(name='llvm._dwarf',
|
||||
sources=['llvm/_dwarf.cpp'],
|
||||
include_dirs=[incdir])
|
||||
])
|
||||
|
||||
def run_2to3():
|
||||
import lib2to3.refactor
|
||||
|
|
|
|||
104
test/test_debuginfo.py
Normal file
104
test/test_debuginfo.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
import os
|
||||
import unittest
|
||||
|
||||
from llvm.core import *
|
||||
from llvm import _dwarf, debuginfo
|
||||
|
||||
class TestDebugInfo(unittest.TestCase):
|
||||
|
||||
def test_dwarf_constants(self):
|
||||
dwarf_constants = vars(_dwarf)
|
||||
|
||||
# Version numbers
|
||||
self.assertIn("LLVMDebugVersion", dwarf_constants)
|
||||
self.assertIn("DWARF_VERSION", dwarf_constants)
|
||||
|
||||
# Tags
|
||||
self.assertIn("DW_TAG_compile_unit", dwarf_constants)
|
||||
|
||||
# Language identifiers
|
||||
self.assertIn("DW_LANG_Python", dwarf_constants)
|
||||
self.assertIn("DW_LANG_C89", dwarf_constants)
|
||||
self.assertIn("DW_LANG_C99", dwarf_constants)
|
||||
|
||||
# print sorted([constname for constname in dwarf_constants
|
||||
# if constname.startswith("DW_LANG_")])
|
||||
|
||||
def test_debug_info_compile_unit(self):
|
||||
mod = Module.new('test_debug_info')
|
||||
fty = Type.function(Type.float(), [Type.float()])
|
||||
square = mod.add_function(fty, 'square')
|
||||
bb = square.append_basic_block('entry')
|
||||
bldr = Builder.new(bb)
|
||||
|
||||
source_filename = "test_debug_info.py"
|
||||
source_filedir = os.path.expanduser("~")
|
||||
|
||||
# Debug info for our file
|
||||
filedesc = debuginfo.FileDescriptor(source_filename, source_filedir)
|
||||
|
||||
# Debug info for our function
|
||||
subprogram = debuginfo.SubprogramDescriptor(
|
||||
filedesc,
|
||||
"some_function",
|
||||
"some_function",
|
||||
"some_function",
|
||||
filedesc,
|
||||
1, # line number
|
||||
debuginfo.empty, # Type descriptor
|
||||
llvm_func=square,
|
||||
)
|
||||
subprograms = debuginfo.MDList([subprogram])
|
||||
|
||||
# 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)
|
||||
ret = bldr.ret(result)
|
||||
|
||||
# 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(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()
|
||||
# TestDebugInfo("test_debug_info_compile_unit").debug()
|
||||
unittest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue