Skip to content

Commit

Permalink
[llvm.py] Initial skeleton for Python LLVM bindings
Browse files Browse the repository at this point in the history
This contains a semi-functional skeleton for the implementation of the
LLVM bindings for Python.

The API for the Object.h interface is roughly designed but not
implemented. MemoryBufferRef is implemented and actually appears to
work!

The ObjectFile unit test fails with a segmentation fault because the
LLVM library isn't being properly initialized. The build system doesn't
know about this code yet, so no alerts should fire.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@152397 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
indygreg committed Mar 9, 2012
1 parent 1fabd9f commit 5ae0427
Show file tree
Hide file tree
Showing 7 changed files with 361 additions and 0 deletions.
Empty file added bindings/python/README.txt
Empty file.
Empty file.
37 changes: 37 additions & 0 deletions bindings/python/llvm/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#===- common.py - Python LLVM Bindings -----------------------*- python -*--===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#

from ctypes import cdll

import ctypes.util
import platform

__all__ = [
"find_library",
"get_library",
]

def find_library():
# FIXME should probably have build system define absolute path of shared
# library at install time.
for lib in ["LLVM-3.1svn", "LLVM"]:
result = ctypes.util.find_library(lib)
if result:
return result

# FIXME This is a local hack to ease development.
return "/usr/local/llvm/lib/libLLVM-3.1svn.so"

def get_library():
"""Obtain a reference to the llvm library."""
lib = find_library()
if not lib:
raise Exception("LLVM shared library not found!")

return cdll.LoadLibrary(lib)
61 changes: 61 additions & 0 deletions bindings/python/llvm/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#===- core.py - Python LLVM Bindings -------------------------*- python -*--===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#

from .common import get_library

from ctypes import POINTER
from ctypes import byref
from ctypes import c_char_p
from ctypes import c_void_p

__all__ = [
"lib",
"MemoryBufferRef",
]

lib = get_library()

class MemoryBuffer(object):
"""Represents an opaque memory buffer."""

def __init__(self, filename=None):
"""Create a new memory buffer.
Currently, we support creating from the contents of a file at the
specified filename.
"""
if filename is None:
raise Exception("filename argument must be defined")

memory = c_void_p(None)
out = c_char_p(None)

result = lib.LLVMCreateMemoryBufferWithContentsOfFile(filename,
byref(memory), byref(out))

if result:
raise Exception("Could not create memory buffer: %s" % out.value)

self._memory = memory

def __del__(self):
lib.LLVMDisposeMemoryBuffer(self._memory)

def from_param(self):
return self._memory


def register_library(library):
library.LLVMCreateMemoryBufferWithContentsOfFile.argtypes = [c_char_p,
POINTER(c_void_p), POINTER(c_char_p)]
library.LLVMCreateMemoryBufferWithContentsOfFile.restype = bool

library.LLVMDisposeMemoryBuffer.argtypes = [c_void_p]

register_library(lib)
243 changes: 243 additions & 0 deletions bindings/python/llvm/object.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
#===- object.py - Python Object Bindings --------------------*- python -*--===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#

from ctypes import c_char_p
from ctypes import c_uint64
from ctypes import c_void_p

from .common import get_library
from .core import MemoryBuffer

__all__ = [
"lib",
"ObjectFile",
"Relocation",
"Section",
"Symbol",
]

class ObjectFile(object):
"""Represents an object/binary file."""

def __init__(self, filename=None, contents=None):
"""Construct an instance from a filename or binary data.
filename must be a path to a file that can be opened with open().
contents can be either a native Python buffer type (like str) or a
llvm.core.MemoryBuffer instance.
"""
if contents:
assert isinstance(contents, MemoryBuffer)

if filename is not None:
contents = MemoryBuffer(filename=filename)

self._memory = contents
self._obj = lib.LLVMCreateObjectFile(contents)

def __del__(self):
lib.LLVMDisposeObjectFile(self._obj)

def get_sections(self):
"""Obtain the sections in this object file.
This is an iterator for llvm.object.Section instances.
"""
pass

def get_symbols(self):
"""Obtain the symbols in this object file.
This is an iterator for llvm.object.Symbol instances.
"""

class Section(object):
"""Represents a section in an object file."""

def __init__(self, obj=None):
"""Construct a new section instance.
Section instances can currently only be created from an ObjectFile
instance. Therefore, this constructor should not be used outside of
this module.
"""
pass

def __del__(self):
pass

@property
def name(self):
pass

@property
def size(self):
pass

@property
def contents(self):
pass

@property
def address(self):
pass

# TODO consider exposing more Pythonic interface, like __contains__
def has_symbol(self, symbol):
pass

def get_relocations(self):
pass

class Symbol(object):
def __init__(self):
pass

@property
def name(self):
pass

@property
def address(self):
pass

@property
def file_offset(self):
pass

@property
def size(self):
pass

class Relocation(object):
def __init__(self):
pass

@property
def address(self):
pass

@property
def offset(self):
pass

@property
def symbol(self):
pass

@property
def type(self):
pass

@property
def type_name(self):
pass

@property
def value_string(self):
pass

ObjectFileRef = c_void_p
SectionIteratorRef = c_void_p
SymbolIteratorRef = c_void_p
RelocationIteratorRef = c_void_p

def register_library(library):
"""Register function prototypes with LLVM library instance."""

# Object.h functions
library.LLVMCreateObjectFile.argtypes = [MemoryBuffer]
library.LLVMCreateObjectFile.restype = ObjectFileRef

library.LLVMDisposeObjectFile.argtypes = [ObjectFileRef]

library.LLVMGetSections.argtypes = [ObjectFileRef]
library.LLVMGetSections.restype = SectionIteratorRef

library.LLVMDisposeSectionIterator.argtypes = [SectionIteratorRef]

library.LLVMIsSectionIteratorAtEnd.argtypes = [ObjectFileRef,
SectionIteratorRef]
library.LLVMIsSectionIteratorAtEnd.restype = bool

library.LLVMMoveToNextSection.argtypes = [SectionIteratorRef]

library.LLVMMoveToContainingSection.argtypes = [SectionIteratorRef,
SymbolIteratorRef]

library.LLVMGetSymbols.argtypes = [ObjectFileRef]
library.LLVMGetSymbols.restype = SymbolIteratorRef

library.LLVMDisposeSymbolIterator.argtypes = [SymbolIteratorRef]

library.LLVMIsSymbolIteratorAtEnd.argtypes = [ObjectFileRef,
SymbolIteratorRef]
library.LLVMIsSymbolIteratorAtEnd.restype = bool

library.LLVMMoveToNextSymbol.argtypes = [SymbolIteratorRef]

library.LLVMGetSectionName.argtypes = [SectionIteratorRef]
library.LLVMGetSectionName.restype = c_char_p

library.LLVMGetSectionSize.argtypes = [SectionIteratorRef]
library.LLVMGetSectionSize.restype = c_uint64

library.LLVMGetSectionContents.argtypes = [SectionIteratorRef]
library.LLVMGetSectionContents.restype = c_char_p

library.LLVMGetSectionAddress.argtypes = [SectionIteratorRef]
library.LLVMGetSectionAddress.restype = c_uint64

library.LLVMGetSectionContainsSymbol.argtypes = [SectionIteratorRef,
SymbolIteratorRef]
library.LLVMGetSectionContainsSymbol.restype = bool

library.LLVMGetRelocations.argtypes = [SectionIteratorRef]
library.LLVMGetRelocations.restype = RelocationIteratorRef

library.LLVMDisposeRelocationIterator.argtypes = [RelocationIteratorRef]

library.LLVMIsRelocationIteratorAtEnd.argtypes = [SectionIteratorRef,
RelocationIteratorRef]
library.LLVMIsRelocationIteratorAtEnd.restype = bool

library.LLVMMoveToNextRelocation.argtypes = [RelocationIteratorRef]

library.LLVMGetSymbolName.argtypes = [SymbolIteratorRef]
library.LLVMGetSymbolName.restype = c_char_p

library.LLVMGetSymbolAddress.argtypes = [SymbolIteratorRef]
library.LLVMGetSymbolAddress.restype = c_uint64

library.LLVMGetSymbolFileOffset.argtypes = [SymbolIteratorRef]
library.LLVMGetSymbolFileOffset.restype = c_uint64

library.LLVMGetSymbolSize.argtypes = [SymbolIteratorRef]
library.LLVMGetSymbolSize.restype = c_uint64

library.LLVMGetRelocationAddress.argtypes = [SymbolIteratorRef]
library.LLVMGetRelocationAddress.restype = c_uint64

library.LLVMGetRelocationOffset.argtypes = [RelocationIteratorRef]
library.LLVMGetRelocationOffset.restype = c_uint64

library.LLVMGetRelocationSymbol.argtypes = [RelocationIteratorRef]
library.LLVMGetRelocationSymbol.restype = SymbolIteratorRef

library.LLVMGetRelocationType.argtypes = [RelocationIteratorRef]
library.LLVMGetRelocationType.restype = c_uint64

library.LLVMGetRelocationTypeName.argtypes = [RelocationIteratorRef]
library.LLVMGetRelocationTypeName.restype = c_char_p

library.LLVMGetRelocationValueString.argtypes = [RelocationIteratorRef]
library.LLVMGetRelocationValueString.restype = c_char_p

lib = get_library()
register_library(lib)
11 changes: 11 additions & 0 deletions bindings/python/tests/test_core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from llvm.common import find_library
from llvm.core import MemoryBuffer

import unittest

class TestCore(unittest.TestCase):
def test_memory_buffer_create_from_file(self):
source = find_library()
self.assertIsNotNone(source)

mb = MemoryBuffer(filename=source)
9 changes: 9 additions & 0 deletions bindings/python/tests/test_object.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from llvm.common import find_library
from llvm.object import ObjectFile

import unittest

class TestObjectFile(unittest.TestCase):
def test_create_from_file(self):
source = find_library()
of = ObjectFile(filename=source)

0 comments on commit 5ae0427

Please sign in to comment.