2018-05-24 15:32:17 +02:00
|
|
|
#!/usr/bin/env python
|
|
|
|
import unittest
|
|
|
|
import logging
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import subprocess
|
|
|
|
import tempfile
|
|
|
|
import shutil
|
|
|
|
import lief
|
|
|
|
from lief import Logger
|
|
|
|
Logger.set_level(lief.LOGGING_LEVEL.INFO)
|
|
|
|
|
|
|
|
from subprocess import Popen
|
|
|
|
from unittest import TestCase
|
|
|
|
|
2019-08-22 22:05:53 +01:00
|
|
|
from utils import get_compiler
|
|
|
|
|
2018-05-24 15:32:17 +02:00
|
|
|
BINADD_C = """\
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
int add(int a, int b);
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
if (argc != 3) {
|
|
|
|
printf("Usage: %s <a> <b>\\n", argv[0]);
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int res = add(atoi(argv[1]), atoi(argv[2]));
|
|
|
|
printf("From myLIb, a + b = %d\\n", res);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
"""
|
|
|
|
|
|
|
|
ADD_C = """\
|
|
|
|
int add(int a, int b) {
|
|
|
|
return a + b;
|
|
|
|
}
|
|
|
|
"""
|
|
|
|
|
|
|
|
class LibAddSample(object):
|
|
|
|
COUNT = 0
|
|
|
|
def __init__(self):
|
|
|
|
self.logger = logging.getLogger(__name__)
|
|
|
|
self.tmp_dir = tempfile.mkdtemp(suffix='_lief_sample_{:d}'.format(LibAddSample.COUNT))
|
|
|
|
self.logger.debug("temp dir: {}".format(self.tmp_dir))
|
|
|
|
|
|
|
|
LibAddSample.COUNT += 1
|
|
|
|
|
|
|
|
self.binadd_path = os.path.join(self.tmp_dir, "binadd.c")
|
|
|
|
self.add_c_path = os.path.join(self.tmp_dir, "add.c")
|
|
|
|
self.binadd_obj = os.path.join(self.tmp_dir, "binadd.o")
|
|
|
|
self.binadd_bin = os.path.join(self.tmp_dir, "binadd.exe")
|
|
|
|
|
2019-08-22 22:05:53 +01:00
|
|
|
self.compiler = get_compiler()
|
2018-05-24 15:32:17 +02:00
|
|
|
self.logger.debug("Compiler: {}".format(self.compiler))
|
|
|
|
|
|
|
|
with open(self.binadd_path, 'w') as f:
|
|
|
|
f.write(BINADD_C)
|
|
|
|
|
|
|
|
with open(self.add_c_path, 'w') as f:
|
|
|
|
f.write(ADD_C)
|
|
|
|
|
|
|
|
self._compile_objadd()
|
|
|
|
|
|
|
|
|
|
|
|
def _compile_objadd(self):
|
|
|
|
if os.path.isfile(self.binadd_obj):
|
|
|
|
os.remove(self.binadd_obj)
|
|
|
|
|
|
|
|
cmd = [self.compiler, '-c', '-o', self.binadd_obj, self.binadd_path]
|
|
|
|
self.logger.debug("Compile 'binadd' with: {}".format(" ".join(cmd)))
|
|
|
|
p = Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
|
|
stdout, _ = p.communicate()
|
|
|
|
self.logger.debug(stdout)
|
|
|
|
|
|
|
|
def compile_object_to_bin(self):
|
|
|
|
if os.path.isfile(self.binadd_bin):
|
|
|
|
os.remove(self.binadd_bin)
|
|
|
|
|
|
|
|
cmd = [self.compiler, '-o', self.binadd_bin, self.binadd_obj, self.add_c_path]
|
|
|
|
self.logger.debug("Compile 'binadd' with: {}".format(" ".join(cmd)))
|
|
|
|
p = Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
|
|
stdout, _ = p.communicate()
|
|
|
|
self.logger.debug(stdout)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def binadd(self):
|
|
|
|
return self.binadd_bin
|
|
|
|
|
|
|
|
@property
|
|
|
|
def objadd(self):
|
|
|
|
return self.binadd_obj
|
|
|
|
|
|
|
|
@property
|
|
|
|
def directory(self):
|
|
|
|
return self.tmp_dir
|
|
|
|
|
|
|
|
def remove(self):
|
|
|
|
if os.path.isdir(self.directory):
|
|
|
|
shutil.rmtree(self.directory)
|
|
|
|
|
|
|
|
def __del__(self):
|
|
|
|
self.remove()
|
|
|
|
|
|
|
|
|
|
|
|
class TestStatic(TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
self.logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
|
|
|
|
def test_write_object(self):
|
|
|
|
sample = LibAddSample()
|
|
|
|
tmp_file = os.path.join(sample.directory, "newfile.o")
|
|
|
|
binadd = lief.parse(sample.objadd)
|
|
|
|
init_obj = [str(o).strip() for o in binadd.object_relocations]
|
|
|
|
|
|
|
|
binadd.write(tmp_file)
|
|
|
|
binadd = lief.parse(tmp_file)
|
|
|
|
new_obj = [str(o).strip() for o in binadd.object_relocations]
|
|
|
|
|
|
|
|
self.assertEqual(len(init_obj), len(new_obj))
|
|
|
|
|
|
|
|
for new, old in zip(new_obj, init_obj):
|
|
|
|
self.assertEqual(new, old)
|
|
|
|
|
|
|
|
# Check it can still be compiled
|
|
|
|
sample.compile_object_to_bin()
|
|
|
|
self.assertEqual(subprocess.check_output([sample.binadd_bin, "2", "3"]).decode('ascii', 'ignore'),
|
|
|
|
'From myLIb, a + b = 5\n')
|
|
|
|
|
|
|
|
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
|
|
|
|
def test_update_addend_object(self):
|
|
|
|
sample = LibAddSample()
|
|
|
|
tmp_file = os.path.join(sample.directory, "newfile.o")
|
|
|
|
binadd = lief.parse(sample.objadd)
|
|
|
|
reloc = next(o for o in binadd.object_relocations if o.symbol.name == "add")
|
|
|
|
|
|
|
|
reloc.addend = 0xABCD
|
|
|
|
binadd.write(tmp_file)
|
|
|
|
binadd = lief.parse(tmp_file)
|
|
|
|
reloc = next(o for o in binadd.object_relocations if o.symbol.name == "add")
|
|
|
|
|
|
|
|
self.assertEqual(reloc.addend, 0xABCD)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
|
|
|
root_logger = logging.getLogger()
|
|
|
|
root_logger.setLevel(logging.DEBUG)
|
|
|
|
|
|
|
|
ch = logging.StreamHandler()
|
|
|
|
ch.setLevel(logging.DEBUG)
|
|
|
|
root_logger.addHandler(ch)
|
|
|
|
|
|
|
|
unittest.main(verbosity=2)
|
|
|
|
|