5
5
# -----------------------------------------
6
6
# Given a program file to upload, or a program name to delete from the server, does the right thing.
8
from __future__ import print_function
8
10
__all__ = ("upload_program", "delete_program")
10
from .db_api import SextantConnection, Validator
11
from .objdump_parser import get_parsed_objects
12
from .db_api import SextantConnection
13
from .sshmanager import SSHConnectionError
14
from .objdump_parser import Parser, run_objdump
12
15
from os import path
17
def upload_program(user_name, file_path, db_url, display_url='',
18
alternative_name=None, not_object_file=False):
20
Uploads a program to the remote database.
22
Raises requests.exceptions.ConnectionError if the server didn't exist.
23
Raises IOError if file_path doesn't correspond to a file.
24
Raises ValueError if the desired alternative_name (or the default, if no
25
alternative_name was specified) already exists in the database.
26
:param file_path: the path to the local file we wish to upload
27
:param db_url: the URL of the database (eg. http://localhost:7474)
28
:param display_url: alternative URL to display instead of db_url
29
:param alternative_name: a name to give the program to override the default
30
:param object_file: bool(the file is an objdump text output file, rather than a compiled binary)
37
# if no name is specified, use the form "<username>-<binary name>"
38
name = alternative_name or (user_name + '-' + path.split(file_path)[-1])
40
connection = SextantConnection(db_url)
42
program_names = connection.get_program_names()
43
if Validator.sanitise(name) in program_names:
44
raise ValueError("There is already a program with name {}; "
45
"please delete the previous one with the same name "
46
"and retry, or rename the input file.".format(name))
48
parsed_objects = get_parsed_objects(filepath=file_path,
49
sections_to_view=['.text'],
50
not_object_file=not_object_file,
51
ignore_function_pointers=False)
53
logging.info('Objdump has parsed!')
55
program_representation = connection.new_program(Validator.sanitise(name))
57
for obj in parsed_objects:
58
for called in obj.what_do_i_call:
59
if not program_representation.add_function_call(obj.name, called[-1]): # called is a tuple (address, name)
60
logging.error('Validation error: {} calling {}'.format(obj.name, called[-1]))
62
logging.info('Sending {} named objects to server {}...'.format(len(parsed_objects), display_url))
63
program_representation.commit()
64
logging.info('Successfully added {}.'.format(name))
67
def delete_program(program_name, db_url):
69
Deletes a program with the specified name from the database.
70
:param program_name: the name of the program to delete
71
:param db_url: the URL of the database (eg. http://localhost:7474)
72
:return: bool(success)
74
connection = SextantConnection(db_url)
22
def upload_program(connection, user_name, file_path, program_name=None,
23
not_object_file=False):
25
Upload a program's functions and call graph to the database.
29
The SextantConnection object that manages the database connection.
31
The user name of the user uploading the program.
33
The path to either: the output of objdump (if not_object_file is
34
True) OR to a binary file if (not_object_file is False).
36
An optional name to give the program in the database, if not
37
specified then <user_name>-<file name> will be used.
39
Flag controlling whether file_path is pointing to a dump file or
42
if not connection._ssh:
43
raise SSHConnectionError('An SSH connection is required for '
47
file_no_ext = path.basename(file_path).split('.')[0]
48
program_name = '{}-{}'.format(user_name, file_no_ext)
51
if program_name in connection.get_program_names():
52
raise ValueError('A program with name `{}` already exists in the database'
53
.format(program_name))
56
print('Uploading `{}` to the database. '
57
'This may take some time for larger programs.'
58
.format(program_name))
61
if not not_object_file:
62
print('Generating dump file...', end='')
64
file_path, file_object = run_objdump(file_path)
69
# Make parser and wire to DBprogram.
70
with connection.new_program(program_name) as program:
72
def start_parser(program):
73
print('Parsing dump file...', end='')
76
def finish_parser(parser, program):
77
# Callback to make sure the program's csv files are flushed when
78
# the parser completes.
79
program.func_writer.finish()
80
program.call_writer.finish()
82
print('done: {} functions and {} calls.'
83
.format(parser.function_count, parser.call_count))
85
parser = Parser(file_path = file_path, file_object = file_object,
87
add_function = program.add_function,
88
add_call = program.add_call,
89
started=lambda parser: start_parser(program),
90
finished=lambda parser: finish_parser(parser, program))
96
print('Finished in {:.2f}s.'.format(end-start))
99
def delete_program(connection, program_name):
101
Remove the specified program from the database.
105
The SextantConnection object managing the database connection.
107
The name of the program to remove from the database.
75
109
connection.delete_program(program_name)
76
print('Successfully deleted {}.'.format(program_name))