Skip to content

Commit

Permalink
what a nightmare. Implemented copying stuff out of VEX
Browse files Browse the repository at this point in the history
  • Loading branch information
zardus committed Sep 29, 2013
1 parent 083e129 commit befff35
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 7 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ You can use pyvex pretty easily. For now, it only supports translation and prett

Awesome stuff!

## Static gotchas

To use PyVEX statically, VEX's memory management needs to be worked around. The issue is that all of the nice, helpful, constructor functions (ie, emptyIRSB(), mkIRCallee(), etc) allocate memory managed by VEX, and VEX is liable to free it or reuse it at any time. Thus, everything needs to be deepCopied out of VEX.

There are a few approaches to solving this. To work around the issue, we could simply pull all of these functions out of VEX and use our local copies, using reasonable memory management. However, that's a lot of functions to pull out and keep synced. We took the (possibly worse) approach of deepCopying everything away from VEX. The file generate\_deepcopy.sh copies out the deepCopy operations out of VEX, does some sedding to rename the functions, and we call those to pull everything out from VEX.

One issue with that the fact that we need to explicitly replace functions, hence the giant list of defines in that shell script. Whenever Valgrind adds more of these, pyvex might silently segfault until they're added to the replacement list.

## Next steps

- Get pyvex working in Valgrind, dynamically.
Expand Down
116 changes: 115 additions & 1 deletion generate_deepcopy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,126 @@ cat > pyvex/pyvex_deepcopy.c <<END
#include <libvex_ir.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "pyvex_logging.h"
#include "pyvex_deepcopy.h"
#define vpanic(x) { error(x "\n"); assert(0); }
#define PYVEX_SHALLOW_FUNC(type) type *pyvex_shallowCopy_##type(type *x) { type *o = malloc(sizeof(type)); memcpy(o, x, sizeof(type)); return o; }
PYVEX_SHALLOW_FUNC(IRConst)
#define IRConst_U1(...) pyvex_shallowCopy_IRConst(IRConst_U1(__VA_ARGS__))
#define IRConst_U8(...) pyvex_shallowCopy_IRConst(IRConst_U8(__VA_ARGS__))
#define IRConst_U16(...) pyvex_shallowCopy_IRConst(IRConst_U16(__VA_ARGS__))
#define IRConst_U32(...) pyvex_shallowCopy_IRConst(IRConst_U32(__VA_ARGS__))
#define IRConst_U64(...) pyvex_shallowCopy_IRConst(IRConst_U64(__VA_ARGS__))
#define IRConst_F32(...) pyvex_shallowCopy_IRConst(IRConst_F32(__VA_ARGS__))
#define IRConst_F64(...) pyvex_shallowCopy_IRConst(IRConst_F64(__VA_ARGS__))
#define IRConst_F32i(...) pyvex_shallowCopy_IRConst(IRConst_F32i(__VA_ARGS__))
#define IRConst_F64i(...) pyvex_shallowCopy_IRConst(IRConst_F64i(__VA_ARGS__))
#define IRConst_V128(...) pyvex_shallowCopy_IRConst(IRConst_V128(__VA_ARGS__))
#define IRConst_V256(...) pyvex_shallowCopy_IRConst(IRConst_V256(__VA_ARGS__))
PYVEX_SHALLOW_FUNC(IRCallee)
#define mkIRCallee(...) pyvex_shallowCopy_IRCallee(mkIRCallee(__VA_ARGS__))
PYVEX_SHALLOW_FUNC(IRRegArray)
#define mkIRRegArray(...) pyvex_shallowCopy_IRRegArray(mkIRRegArray(__VA_ARGS__))
PYVEX_SHALLOW_FUNC(IRExpr)
#define IRExpr_Get(...) pyvex_shallowCopy_IRExpr(IRExpr_Get(__VA_ARGS__))
#define IRExpr_GetI(...) pyvex_shallowCopy_IRExpr(IRExpr_GetI(__VA_ARGS__))
#define IRExpr_RdTmp(...) pyvex_shallowCopy_IRExpr(IRExpr_RdTmp(__VA_ARGS__))
#define IRExpr_Qop(...) pyvex_shallowCopy_IRExpr(IRExpr_Qop(__VA_ARGS__))
#define IRExpr_Triop(...) pyvex_shallowCopy_IRExpr(IRExpr_Triop(__VA_ARGS__))
#define IRExpr_Binop(...) pyvex_shallowCopy_IRExpr(IRExpr_Binop(__VA_ARGS__))
#define IRExpr_Unop(...) pyvex_shallowCopy_IRExpr(IRExpr_Unop(__VA_ARGS__))
#define IRExpr_Load(...) pyvex_shallowCopy_IRExpr(IRExpr_Load(__VA_ARGS__))
#define IRExpr_Const(...) pyvex_shallowCopy_IRExpr(IRExpr_Const(__VA_ARGS__))
#define IRExpr_CCall(...) pyvex_shallowCopy_IRExpr(IRExpr_CCall(__VA_ARGS__))
#define IRExpr_Mux0X(...) pyvex_shallowCopy_IRExpr(IRExpr_Mux0X(__VA_ARGS__))
PYVEX_SHALLOW_FUNC(IRDirty)
#define emptyIRDirty(...) pyvex_shallowCopy_IRDirty(emptyIRDirty(__VA_ARGS__))
PYVEX_SHALLOW_FUNC(IRCAS)
#define mkIRCAS(...) pyvex_shallowCopy_IRCAS(mkIRCAS(__VA_ARGS__))
PYVEX_SHALLOW_FUNC(IRPutI)
#define mkIRPutI(...) pyvex_shallowCopy_IRPutI(mkIRPutI(__VA_ARGS__))
PYVEX_SHALLOW_FUNC(IRStmt)
#define IRStmt_NoOp(...) pyvex_shallowCopy_IRStmt(IRStmt_NoOp(__VA_ARGS__))
#define IRStmt_AbiHint(...) pyvex_shallowCopy_IRStmt(IRStmt_AbiHint(__VA_ARGS__))
#define IRStmt_IMark(...) pyvex_shallowCopy_IRStmt(IRStmt_IMark(__VA_ARGS__))
#define IRStmt_Put(...) pyvex_shallowCopy_IRStmt(IRStmt_Put(__VA_ARGS__))
#define IRStmt_PutI(...) pyvex_shallowCopy_IRStmt(IRStmt_PutI(__VA_ARGS__))
#define IRStmt_WrTmp(...) pyvex_shallowCopy_IRStmt(IRStmt_WrTmp(__VA_ARGS__))
#define IRStmt_Store(...) pyvex_shallowCopy_IRStmt(IRStmt_Store(__VA_ARGS__))
#define IRStmt_CAS(...) pyvex_shallowCopy_IRStmt(IRStmt_CAS(__VA_ARGS__))
#define IRStmt_LLSC(...) pyvex_shallowCopy_IRStmt(IRStmt_LLSC(__VA_ARGS__))
#define IRStmt_Dirty(...) pyvex_shallowCopy_IRStmt(IRStmt_Dirty(__VA_ARGS__))
#define IRStmt_MBE(...) pyvex_shallowCopy_IRStmt(IRStmt_MBE(__VA_ARGS__))
#define IRStmt_Exit(...) pyvex_shallowCopy_IRStmt(IRStmt_Exit(__VA_ARGS__))
PYVEX_SHALLOW_FUNC(IRTypeEnv)
// nothing for this guy
PYVEX_SHALLOW_FUNC(IRSB)
#define emptyIRSB(...) pyvex_shallowCopy_IRSB(emptyIRSB(__VA_ARGS__))
END

cat $VALGRIND_HOME/VEX/priv/ir_defs.c | grep -A1000000 "(Deep) copy constructors" | grep -B10000000 "Primop types" | sed -e "s/shallowCopy/pyvex_shallowCopy/g" -e "s/deepCopy/pyvex_deepCopy/g" -e "s/LibVEX_Alloc/malloc/g" >> pyvex/pyvex_deepcopy.c
cat $VALGRIND_HOME/VEX/priv/ir_defs.c |
grep -A1000000 "(Deep) copy constructors" |
grep -B10000000 "Primop types" |
sed -e "s/shallowCopy/pyvex_shallowCopy/g" |
sed -e "s/deepCopy/pyvex_deepCopy/g" |
sed -e "s/bb2->next *= *pyvex_deepCopyIRExpr(bb->next)/bb2->next = NULL; if (bb->next) &/" |
sed -e "s/case Ico_V128: return IRConst_V128(c->Ico.V128);/&\ncase Ico_V256: return IRConst_V256(c->Ico.V256);/" |
sed -e "s/LibVEX_Alloc/malloc/g" >> pyvex/pyvex_deepcopy.c

cat >> pyvex/pyvex_deepcopy.c <<END
#undef IRConst_U1
#undef IRConst_U8
#undef IRConst_U16
#undef IRConst_U32
#undef IRConst_U64
#undef IRConst_F32
#undef IRConst_F64
#undef IRConst_F32i
#undef IRConst_F64i
#undef IRConst_V128
#undef IRConst_V256
#undef mkIRCallee
#undef mkIRCallee
#undef mkIRRegArray
#undef IRExpr_Get
#undef IRExpr_GetI
#undef IRExpr_RdTmp
#undef IRExpr_Qop
#undef IRExpr_Triop
#undef IRExpr_Binop
#undef IRExpr_Unop
#undef IRExpr_Load
#undef IRExpr_Const
#undef IRExpr_CCall
#undef IRExpr_Mux0X
#undef emptyIRDirty
#undef mkIRCAS
#undef mkIRPutI
#undef IRStmt_NoOp
#undef IRStmt_AbiHint
#undef IRStmt_IMark
#undef IRStmt_Put
#undef IRStmt_PutI
#undef IRStmt_WrTmp
#undef IRStmt_Store
#undef IRStmt_CAS
#undef IRStmt_LLSC
#undef IRStmt_Dirty
#undef IRStmt_MBE
#undef IRStmt_Exit
#undef emptyIRSB
END
109 changes: 106 additions & 3 deletions pyvex/pyvex_deepcopy.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,75 @@
#include <libvex_ir.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#include "pyvex_logging.h"
#include "pyvex_deepcopy.h"

#define vpanic(x) { error(x "\n"); assert(0); }

#define PYVEX_SHALLOW_FUNC(type) type *pyvex_shallowCopy_##type(type *x) { type *o = malloc(sizeof(type)); memcpy(o, x, sizeof(type)); return o; }

PYVEX_SHALLOW_FUNC(IRConst)
#define IRConst_U1(...) pyvex_shallowCopy_IRConst(IRConst_U1(__VA_ARGS__))
#define IRConst_U8(...) pyvex_shallowCopy_IRConst(IRConst_U8(__VA_ARGS__))
#define IRConst_U16(...) pyvex_shallowCopy_IRConst(IRConst_U16(__VA_ARGS__))
#define IRConst_U32(...) pyvex_shallowCopy_IRConst(IRConst_U32(__VA_ARGS__))
#define IRConst_U64(...) pyvex_shallowCopy_IRConst(IRConst_U64(__VA_ARGS__))
#define IRConst_F32(...) pyvex_shallowCopy_IRConst(IRConst_F32(__VA_ARGS__))
#define IRConst_F64(...) pyvex_shallowCopy_IRConst(IRConst_F64(__VA_ARGS__))
#define IRConst_F32i(...) pyvex_shallowCopy_IRConst(IRConst_F32i(__VA_ARGS__))
#define IRConst_F64i(...) pyvex_shallowCopy_IRConst(IRConst_F64i(__VA_ARGS__))
#define IRConst_V128(...) pyvex_shallowCopy_IRConst(IRConst_V128(__VA_ARGS__))
#define IRConst_V256(...) pyvex_shallowCopy_IRConst(IRConst_V256(__VA_ARGS__))

PYVEX_SHALLOW_FUNC(IRCallee)
#define mkIRCallee(...) pyvex_shallowCopy_IRCallee(mkIRCallee(__VA_ARGS__))

PYVEX_SHALLOW_FUNC(IRRegArray)
#define mkIRRegArray(...) pyvex_shallowCopy_IRRegArray(mkIRRegArray(__VA_ARGS__))

PYVEX_SHALLOW_FUNC(IRExpr)
#define IRExpr_Get(...) pyvex_shallowCopy_IRExpr(IRExpr_Get(__VA_ARGS__))
#define IRExpr_GetI(...) pyvex_shallowCopy_IRExpr(IRExpr_GetI(__VA_ARGS__))
#define IRExpr_RdTmp(...) pyvex_shallowCopy_IRExpr(IRExpr_RdTmp(__VA_ARGS__))
#define IRExpr_Qop(...) pyvex_shallowCopy_IRExpr(IRExpr_Qop(__VA_ARGS__))
#define IRExpr_Triop(...) pyvex_shallowCopy_IRExpr(IRExpr_Triop(__VA_ARGS__))
#define IRExpr_Binop(...) pyvex_shallowCopy_IRExpr(IRExpr_Binop(__VA_ARGS__))
#define IRExpr_Unop(...) pyvex_shallowCopy_IRExpr(IRExpr_Unop(__VA_ARGS__))
#define IRExpr_Load(...) pyvex_shallowCopy_IRExpr(IRExpr_Load(__VA_ARGS__))
#define IRExpr_Const(...) pyvex_shallowCopy_IRExpr(IRExpr_Const(__VA_ARGS__))
#define IRExpr_CCall(...) pyvex_shallowCopy_IRExpr(IRExpr_CCall(__VA_ARGS__))
#define IRExpr_Mux0X(...) pyvex_shallowCopy_IRExpr(IRExpr_Mux0X(__VA_ARGS__))

PYVEX_SHALLOW_FUNC(IRDirty)
#define emptyIRDirty(...) pyvex_shallowCopy_IRDirty(emptyIRDirty(__VA_ARGS__))

PYVEX_SHALLOW_FUNC(IRCAS)
#define mkIRCAS(...) pyvex_shallowCopy_IRCAS(mkIRCAS(__VA_ARGS__))

PYVEX_SHALLOW_FUNC(IRPutI)
#define mkIRPutI(...) pyvex_shallowCopy_IRPutI(mkIRPutI(__VA_ARGS__))

PYVEX_SHALLOW_FUNC(IRStmt)
#define IRStmt_NoOp(...) pyvex_shallowCopy_IRStmt(IRStmt_NoOp(__VA_ARGS__))
#define IRStmt_AbiHint(...) pyvex_shallowCopy_IRStmt(IRStmt_AbiHint(__VA_ARGS__))
#define IRStmt_IMark(...) pyvex_shallowCopy_IRStmt(IRStmt_IMark(__VA_ARGS__))
#define IRStmt_Put(...) pyvex_shallowCopy_IRStmt(IRStmt_Put(__VA_ARGS__))
#define IRStmt_PutI(...) pyvex_shallowCopy_IRStmt(IRStmt_PutI(__VA_ARGS__))
#define IRStmt_WrTmp(...) pyvex_shallowCopy_IRStmt(IRStmt_WrTmp(__VA_ARGS__))
#define IRStmt_Store(...) pyvex_shallowCopy_IRStmt(IRStmt_Store(__VA_ARGS__))
#define IRStmt_CAS(...) pyvex_shallowCopy_IRStmt(IRStmt_CAS(__VA_ARGS__))
#define IRStmt_LLSC(...) pyvex_shallowCopy_IRStmt(IRStmt_LLSC(__VA_ARGS__))
#define IRStmt_Dirty(...) pyvex_shallowCopy_IRStmt(IRStmt_Dirty(__VA_ARGS__))
#define IRStmt_MBE(...) pyvex_shallowCopy_IRStmt(IRStmt_MBE(__VA_ARGS__))
#define IRStmt_Exit(...) pyvex_shallowCopy_IRStmt(IRStmt_Exit(__VA_ARGS__))

PYVEX_SHALLOW_FUNC(IRTypeEnv)
// nothing for this guy

PYVEX_SHALLOW_FUNC(IRSB)
#define emptyIRSB(...) pyvex_shallowCopy_IRSB(emptyIRSB(__VA_ARGS__))
/*--- (Deep) copy constructors. These make complete copies ---*/
/*--- the original, which can be modified without affecting ---*/
/*--- the original. ---*/
Expand Down Expand Up @@ -55,7 +118,7 @@ IRConst* pyvex_deepCopyIRConst ( IRConst* c )
case Ico_F64: return IRConst_F64(c->Ico.F64);
case Ico_F64i: return IRConst_F64i(c->Ico.F64i);
case Ico_V128: return IRConst_V128(c->Ico.V128);
case Ico_V256: return IRConst_V256(c->Ico.V256);
case Ico_V256: return IRConst_V256(c->Ico.V256);
default: vpanic("pyvex_deepCopyIRConst");
}
}
Expand Down Expand Up @@ -240,8 +303,7 @@ IRSB* pyvex_deepCopyIRSBExceptStmts ( IRSB* bb )
{
IRSB* bb2 = emptyIRSB();
bb2->tyenv = pyvex_deepCopyIRTypeEnv(bb->tyenv);
bb->next == NULL;
if (bb->next) bb2->next = pyvex_deepCopyIRExpr(bb->next);
bb2->next = NULL; if (bb->next) bb2->next = pyvex_deepCopyIRExpr(bb->next);
bb2->jumpkind = bb->jumpkind;
bb2->offsIP = bb->offsIP;
return bb2;
Expand All @@ -250,3 +312,44 @@ IRSB* pyvex_deepCopyIRSBExceptStmts ( IRSB* bb )

/*---------------------------------------------------------------*/
/*--- Primop types ---*/
#undef IRConst_U1
#undef IRConst_U8
#undef IRConst_U16
#undef IRConst_U32
#undef IRConst_U64
#undef IRConst_F32
#undef IRConst_F64
#undef IRConst_F32i
#undef IRConst_F64i
#undef IRConst_V128
#undef IRConst_V256
#undef mkIRCallee
#undef mkIRCallee
#undef mkIRRegArray
#undef IRExpr_Get
#undef IRExpr_GetI
#undef IRExpr_RdTmp
#undef IRExpr_Qop
#undef IRExpr_Triop
#undef IRExpr_Binop
#undef IRExpr_Unop
#undef IRExpr_Load
#undef IRExpr_Const
#undef IRExpr_CCall
#undef IRExpr_Mux0X
#undef emptyIRDirty
#undef mkIRCAS
#undef mkIRPutI
#undef IRStmt_NoOp
#undef IRStmt_AbiHint
#undef IRStmt_IMark
#undef IRStmt_Put
#undef IRStmt_PutI
#undef IRStmt_WrTmp
#undef IRStmt_Store
#undef IRStmt_CAS
#undef IRStmt_LLSC
#undef IRStmt_Dirty
#undef IRStmt_MBE
#undef IRStmt_Exit
#undef emptyIRSB
18 changes: 15 additions & 3 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ def test_irsb_popret(self):

self.assertEqual(irsb.tyenv.typeOf(irsb.statements()[16].data), 'Ity_I64')

def test_two_irsb(self):
irsb1 = pyvex.IRSB(bytes='\x5d\xc3')
irsb2 = pyvex.IRSB(bytes='\x5d\x5d\x5d\x5d')

stmts1 = irsb1.statements()
stmts2 = irsb2.statements()

self.assertNotEqual(len(stmts1), len(stmts2))

def test_irsb_deepCopy(self):
irsb = pyvex.IRSB(bytes='\x5d\xc3')
stmts = irsb.statements()
Expand Down Expand Up @@ -340,9 +349,6 @@ def test_irexpr_geti(self):
self.assertRaises(Exception, pyvex.IRExpr.GetI, ())

def test_irexpr_rdtmp(self):
irsb = pyvex.IRSB(bytes='\x90\x5d\xc3')
self.assertEqual(irsb.next.tmp, irsb.next.deepCopy().tmp)

m = pyvex.IRExpr.RdTmp(123)
self.assertEqual(m.tag, "Iex_RdTmp")
self.assertEqual(m.tmp, m.deepCopy().tmp)
Expand All @@ -353,6 +359,12 @@ def test_irexpr_rdtmp(self):
self.assertRaises(Exception, pyvex.IRExpr.RdTmp, ())
self.assertEqual(type(m), type(m.deepCopy()))

print "FUCK"
irsb = pyvex.IRSB(bytes='\x90\x5d\xc3')
print "TMP:",irsb.next.tmp
self.assertEqual(irsb.next.tmp, irsb.next.deepCopy().tmp)


def test_irexpr_get(self):
m = pyvex.IRExpr.Get(0, "Ity_I64")
self.assertEqual(m.type, "Ity_I64")
Expand Down

0 comments on commit befff35

Please sign in to comment.