Package bap :: Module bap
[hide private]
[frames] | no frames]

Source Code for Module bap.bap

  1  from subprocess import Popen,PIPE 
  2  from . import bir 
  3   
  4   
5 -class BapError(Exception):
6 "Base class for BAP runtime errors"
7 - def __init__(self, cmd, out, err):
8 self.cmd = cmd 9 self.out = out 10 self.err = err
11
12 - def info(self):
13 return """ 14 Standard output:\n{0}\n 15 Standard error: \n{1}\n 16 Invoked as: {2} 17 """.format(self.out, self.err, ' '.join(self.cmd))
18
19 -class MalformedOutput(BapError):
20 """Raised if we were unable to parse the output of bap. """
21 - def __init__(self, exn, *args):
22 super(MalformedOutput, self).__init__(*args) 23 self.exn = exn
24
25 - def __str__(self):
26 return '\n'.join([ 27 "expected a valid Python expression, but got", 28 str(self.exn), 29 self.info() 30 ])
31
32 -class Failed(BapError):
33 "Raised when bap subprocess returns a non-zero code"
34 - def __init__(self, code, *args):
35 super(Failed, self).__init__(*args) 36 self.code = code
37
38 - def __str__(self):
39 return '\n'.join([ 40 "exited with return code {0}".format(self.code), 41 self.info() 42 ])
43
44 -class Killed(BapError):
45 "Raised when bap subprocess is killed by a signal"
46 - def __init__(self, signal, *args):
47 super(Killed, self).__init__(*args) 48 self.signal = signal
49
50 - def __str__(self):
51 return '\n'.join([ 52 "received signal {0}".format(self.signal), 53 self.info() 54 ])
55 56 57 adt_project_parser = { 58 'format' : 'adt', 59 'load' : bir.loads 60 } 61 62
63 -def run(path, args=[], bap='bap', parser=adt_project_parser):
64 r"""run(file[, args] [, bap=PATH] [,parser=PARSER]) -> project 65 66 Run bap on a specified `file`, wait until it finishes, parse 67 and return the result, using project data structure as default. 68 69 Example: 70 71 >>> proj = run('/bin/true') 72 73 To specify extra command line arguments, pass them as a list: 74 75 >>> proj = run('/bin/true', ['--no-cache', '--symbolizer=ida']) 76 77 To specify an explicit path to `bap` executable use `bap` keyword 78 argument: 79 80 >>> proj = run('/bin/true', bap='/usr/bin/bap') 81 82 83 By default a project data structure is dumped in ADT format and 84 loaded into `bir.Project` data structure. To parse other formats, 85 a parser argument can be specified. It must be a dictionary, that 86 may contain the following two fields: 87 88 - `format` - a format name as accepted by bap's `--dump` option, 89 it will passed to bap. 90 - `load` - a function that parses the output. 91 92 93 In case of errors, the `load` function must raise `SyntaxError` 94 exception. Example: 95 96 >>> version = run('/bin/true', parser={'load' : str.strip}) 97 98 If `parser` is `None` or if it doesn't provide `load` function, 99 then the program output is returned as is. 100 101 102 Exceptions 103 ---------- 104 105 Will pass through exceptions from the underlying subprocess module, 106 with OSError being the most common one. If everything went fine on 107 the system level, then may raise SyntaxError at the parsing step. 108 Also may raise Failed or Killed exceptions in case if the return code 109 wasn't zero. 110 111 112 """ 113 opts = [bap, path] + args 114 115 if parser and 'format' in parser: 116 opts += ['-d{format}'.format(**parser)] 117 118 bap = Popen(opts, stdout=PIPE, stderr=PIPE) 119 out,err = bap.communicate() 120 121 if bap.returncode == 0: 122 try: 123 if parser and 'load' in parser: 124 return parser['load'](out) 125 else: 126 return out 127 except SyntaxError as exn: 128 raise MalformedOutput(exn, opts, out, err) 129 elif bap.returncode < 0: 130 raise Killed(-bap.returncode, opts, out, err) 131 else: 132 raise Failed(bap.returncode, opts, out, err)
133