1 from subprocess import Popen,PIPE
2 from . import bir
3
4
6 "Base class for BAP runtime errors"
8 self.cmd = cmd
9 self.out = out
10 self.err = err
11
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
31
33 "Raised when bap subprocess returns a non-zero code"
37
39 return '\n'.join([
40 "exited with return code {0}".format(self.code),
41 self.info()
42 ])
43
45 "Raised when bap subprocess is killed by a signal"
49
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
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