Skip to content

Commit

Permalink
[llvm.py] Implement interface to object files
Browse files Browse the repository at this point in the history
It is now possible to load object files and scan over sections, symbols,
and relocations! Includes test code with partial coverage.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@152482 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
indygreg committed Mar 10, 2012
1 parent 51cf866 commit 61e22cd
Show file tree
Hide file tree
Showing 10 changed files with 620 additions and 144 deletions.
67 changes: 67 additions & 0 deletions bindings/python/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
This directory contains Python bindings for LLVM's C library.

The bindings are currently a work in progress and are far from complete.
Use at your own risk.

Developer Info
==============

The single Python package is "llvm." Modules inside this package roughly
follow the names of the modules/headers defined by LLVM's C API.

Testing
-------

All test code is location in llvm/tests. Tests are written as classes
which inherit from llvm.tests.base.TestBase, which is a convenience base
class that provides common functionality.

Tests can be executed by installing nose:

pip install nosetests

Then by running nosetests:

nosetests

To see more output:

nosetests -v

To step into the Python debugger while running a test, add the following
to your test at the point you wish to enter the debugger:

import pdb; pdb.set_trace()

Then run nosetests:

nosetests -s -v

You should strive for high code coverage. To see current coverage:

pip install coverage
nosetests --with-coverage --cover-html

Then open cover/index.html in your browser of choice to see the code coverage.

Style Convention
----------------

All code should pass PyFlakes. First, install PyFlakes:

pip install pyflakes

Then at any time run it to see a report:

pyflakes .

Eventually we'll provide a Pylint config file. In the meantime, install
Pylint:

pip install pylint

And run:

pylint llvm

And try to keep the number of violations to a minimum.
72 changes: 67 additions & 5 deletions bindings/python/llvm/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,85 @@
import ctypes.util

__all__ = [
'LLVMObject',
'c_object_p',
'find_library',
'get_library',
]

LLVMObject = POINTER(c_void_p)
c_object_p = POINTER(c_void_p)

class LLVMObject(object):
"""Base class for objects that are backed by an LLVM data structure.
This class should never be instantiated outside of this package.
"""
def __init__(self, ptr, ownable=True, disposer=None):
assert isinstance(ptr, c_object_p)

self._ptr = self._as_parameter_ = ptr

self._self_owned = True
self._ownable = ownable
self._disposer = disposer

self._owned_objects = []

def take_ownership(self, obj):
"""Take ownership of another object.
When you take ownership of another object, you are responsible for
destroying that object. In addition, a reference to that object is
placed inside this object so the Python garbage collector will not
collect the object while it is still alive in libLLVM.
This method should likely only be called from within modules inside
this package.
"""
assert isinstance(obj, LLVMObject)

self._owned_objects.append(obj)
obj._self_owned = False

def from_param(self):
"""ctypes function that converts this object to a function parameter."""
return self._as_parameter_

def __del__(self):
if self._self_owned and self._disposer:
self._disposer(self)

class CachedProperty(object):
"""Decorator that caches the result of a property lookup.
This is a useful replacement for @property. It is recommended to use this
decorator on properties that invoke C API calls for which the result of the
call will be idempotent.
"""
def __init__(self, wrapped):
self.wrapped = wrapped
try:
self.__doc__ = wrapped.__doc__
except: # pragma: no cover
pass

def __get__(self, instance, instance_type=None):
if instance is None:
return self

value = self.wrapped(instance)
setattr(instance, self.wrapped.__name__, value)

return value

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']:
for lib in ['LLVM-3.1svn', 'libLLVM-3.1svn', 'LLVM', 'libLLVM']:
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"
return None

def get_library():
"""Obtain a reference to the llvm library."""
Expand Down
27 changes: 7 additions & 20 deletions bindings/python/llvm/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@
#===------------------------------------------------------------------------===#

from .common import LLVMObject
from .common import c_object_p
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",
"MemoryBuffer",
]

lib = get_library()

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

def __init__(self, filename=None):
Expand All @@ -34,7 +34,7 @@ def __init__(self, filename=None):
if filename is None:
raise Exception("filename argument must be defined")

memory = LLVMObject()
memory = c_object_p()
out = c_char_p(None)

result = lib.LLVMCreateMemoryBufferWithContentsOfFile(filename,
Expand All @@ -43,26 +43,13 @@ def __init__(self, filename=None):
if result:
raise Exception("Could not create memory buffer: %s" % out.value)

self._memory = memory
self._as_parameter_ = self._memory
self._owned = True

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

def from_param(self):
return self._as_parameter_

def release_ownership(self):
self._owned = False

LLVMObject.__init__(self, memory, disposer=lib.LLVMDisposeMemoryBuffer)

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

library.LLVMDisposeMemoryBuffer.argtypes = [c_void_p]
library.LLVMDisposeMemoryBuffer.argtypes = [MemoryBuffer]

register_library(lib)
Loading

0 comments on commit 61e22cd

Please sign in to comment.