Skip to content

Commit f7d8ae1

Browse files
committed
Cleaned up the arg parsing and parameter passing, making it more easily extensible.
1 parent abb00c7 commit f7d8ae1

File tree

1 file changed

+103
-88
lines changed

1 file changed

+103
-88
lines changed

extract-bc

Lines changed: 103 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,22 @@ name to __WLLVM).
2525
import os
2626
import sys
2727
import subprocess as sp
28-
#from subprocess import *
28+
2929
from driver.utils import llvmCompilerPathEnv
3030
from driver.popenwrapper import Popen
3131
from driver.utils import elfSectionName
3232
from driver.utils import darwinSegmentName
3333
from driver.utils import darwinSectionName
3434
from driver.utils import FileType
3535

36+
import driver.logconfig
37+
3638
import logging
3739
import pprint
38-
import driver.logconfig
3940
import tempfile
4041
import shutil
42+
import argparse
43+
4144

4245
# Python 2 does not have exceptions automatically
4346
# imported whereas python 3 does. Handle this
@@ -49,9 +52,6 @@ except NameError:
4952
bitCodeArchiveExtension='bca'
5053
moduleExtension='bc'
5154

52-
#verbose flag to pass to the external calls
53-
verboseFlag = False
54-
5555
# Use objdump on the provided binary; parse out the fields
5656
# to find the given section. Return the size and offset of
5757
# that section (in bytes)
@@ -140,30 +140,30 @@ def extract_section_linux(inputFile):
140140
return contents
141141

142142

143-
def linkFiles(outputFile, llvmLinker, fileNames):
144-
linkCmd = [ llvmLinker, '-v' ] if verboseFlag else [ llvmLinker ]
143+
def linkFiles(pArgs, fileNames):
144+
linkCmd = [ pArgs.llvmLinker, '-v' ] if pArgs.verboseFlag else [ pArgs.llvmLinker ]
145145

146-
linkCmd.extend(['-o', outputFile ])
146+
linkCmd.extend(['-o', pArgs.outputFile ])
147147

148148
linkCmd.extend([x for x in fileNames if x != ''])
149-
logging.info('Writing output to {0}'.format(outputFile))
149+
logging.info('Writing output to {0}'.format(pArgs.outputFile))
150150
try:
151151
linkProc = Popen(linkCmd)
152152
except OSError as e:
153153
if e.errno == 2:
154-
errorMsg = "Your llvm-link doesn't seem to be easy to find.\nEither install it or use the -l llvmLinker option."
154+
errorMsg = 'Your llvm-link does not seem to be easy to find.\nEither install it or use the -l llvmLinker option.'
155155
else:
156-
errorMsg = "OS error({0}): {1}".format(e.errno, e.strerror)
156+
errorMsg = 'OS error({0}): {1}'.format(e.errno, e.strerror)
157157
logging.error(errorMsg)
158158
raise Exception(errorMsg)
159159

160160
else:
161161
exitCode = linkProc.wait()
162-
logging.info('{0} returned {1}'.format(llvmLinker, str(exitCode)))
162+
logging.info('{0} returned {1}'.format(pArgs.llvmLinker, str(exitCode)))
163163
return exitCode
164164

165165

166-
def archiveFiles(outputFile, llvmArchiver, fileNames):
166+
def archiveFiles(pArgs, fileNames):
167167
retCode = 0
168168
# We do not want full paths in the archive so we need to chdir into each
169169
# bitcode's folder. Handle this by calling llvm-ar once for all bitcode
@@ -185,48 +185,47 @@ def archiveFiles(outputFile, llvmArchiver, fileNames):
185185
for (dirname, bcList) in dirToBCMap.items():
186186
logging.debug('Changing directory to "{0}"'.format(dirname))
187187
os.chdir(dirname)
188-
larCmd = [llvmArchiver, 'rs', outputFile ] + bcList
188+
larCmd = [pArgs.llvmArchiver, 'rs', pArgs.outputFile ] + bcList
189189
larProc = Popen(larCmd)
190190
retCode = larProc.wait()
191191
if retCode != 0:
192192
logging.error('Failed to execute:\n{0}'.format(pprint.pformat(larCmd)))
193193
break
194194

195195
if retCode == 0:
196-
logging.info('Generated LLVM bitcode archive {0}'.format(outputFile))
196+
logging.info('Generated LLVM bitcode archive {0}'.format(pArgs.outputFile))
197197
else:
198198
logging.error('Failed to generate LLVM bitcode archive')
199199

200200
return retCode
201-
pass
202201

203202

204-
def handleExecutable(inputFile, outputFile, extractor, llvmLinker, manifestFlag):
203+
def handleExecutable(pArgs):
205204

206-
fileNames = extractor(inputFile)
205+
fileNames = pArgs.extractor(pArgs.inputFile)
207206

208207
if not fileNames:
209208
return 1
210209

211-
if manifestFlag:
212-
manifestFile = '{0}.wllvm.manifest'.format(inputFile)
210+
if pArgs.manifestFlag:
211+
manifestFile = '{0}.wllvm.manifest'.format(pArgs.inputFile)
213212
with open(manifestFile, 'w') as output:
214213
for f in fileNames:
215214
output.write('{0}\n'.format(f))
216215

217-
if outputFile == None:
218-
outputFile = inputFile + '.' + moduleExtension
216+
if pArgs.outputFile == None:
217+
pArgs.outputFile = pArgs.inputFile + '.' + moduleExtension
218+
219+
return linkFiles(pArgs, fileNames)
219220

220-
return linkFiles(outputFile, llvmLinker, fileNames)
221221

222222

223223

224+
def handleArchive(pArgs):
224225

225-
def handleArchive(inputFile, outputFile, arCmd, fileType, extractor, llvmArchiver, manifestFlag):
226-
inputFile = os.path.abspath(inputFile)
227226
originalDir = os.getcwd() # This will be the destination
228227

229-
arCmd.append(inputFile);
228+
pArgs.arCmd.append(pArgs.inputFile)
230229

231230
# Make temporary directory to extract objects to
232231
tempDir = ''
@@ -238,19 +237,19 @@ def handleArchive(inputFile, outputFile, arCmd, fileType, extractor, llvmArchive
238237

239238
# Extract objects from archive
240239
try:
241-
arP = Popen(arCmd)
240+
arP = Popen(pArgs.arCmd)
242241
except OSError as e:
243242
if e.errno == 2:
244-
errorMsg = "Your ar doesn't seem to be easy to find.\n"
243+
errorMsg = 'Your ar does not seem to be easy to find.\n'
245244
else:
246-
errorMsg = "OS error({0}): {1}".format(e.errno, e.strerror)
245+
errorMsg = 'OS error({0}): {1}'.format(e.errno, e.strerror)
247246
logging.error(errorMsg)
248247
raise Exception(errorMsg)
249248

250249
arPE = arP.wait()
251250

252251
if arPE != 0:
253-
errorMsg = 'Failed to execute archiver with command {0}'.format(arCmd)
252+
errorMsg = 'Failed to execute archiver with command {0}'.format(pArgs.arCmd)
254253
logging.error(errorMsg)
255254
raise Exception(errorMsg)
256255

@@ -259,10 +258,10 @@ def handleArchive(inputFile, outputFile, arCmd, fileType, extractor, llvmArchive
259258
logging.debug('Exploring "{0}"'.format(root))
260259
for f in files:
261260
fPath = os.path.join(root, f)
262-
if FileType.getFileType(fPath) == fileType:
261+
if FileType.getFileType(fPath) == pArgs.fileType:
263262

264263
# Extract bitcode locations from object
265-
contents = extractor(fPath)
264+
contents = pArgs.extractor(fPath)
266265

267266
for bcFile in contents:
268267
if bcFile != '':
@@ -282,37 +281,42 @@ def handleArchive(inputFile, outputFile, arCmd, fileType, extractor, llvmArchive
282281
shutil.rmtree(tempDir)
283282

284283
#write the manifest file if asked for
285-
if manifestFlag:
286-
manifestFile = '{0}.llvm.manifest'.format(inputFile)
284+
if pArgs.manifestFlag:
285+
manifestFile = '{0}.llvm.manifest'.format(pArgs.inputFile)
287286
with open(manifestFile, 'w') as output:
288287
for f in bitCodeFiles:
289288
output.write('{0}\n'.format(f))
290289

291290
# Build bitcode archive
292291
os.chdir(originalDir)
293292

294-
return buildArchive(inputFile, outputFile, llvmArchiver, bitCodeFiles)
293+
return buildArchive(pArgs, bitCodeFiles)
295294

296-
def buildArchive(inputFile, outputFile, llvmArchiver, bitCodeFiles):
295+
def buildArchive(pArgs, bitCodeFiles):
297296
# Pick output file path if outputFile not set
298-
if outputFile == None:
299-
if inputFile.endswith('.a'):
297+
if pArgs.outputFile == None:
298+
if pArgs.inputFile.endswith('.a'):
300299
# Strip off .a suffix
301-
outputFile = inputFile[:-2]
300+
pArgs.outputFile = pArgs.inputFile[:-2]
302301
else:
303-
outputFile = inputFile
304-
outputFile +='.' + bitCodeArchiveExtension
302+
pArgs.outputFile = pArgs.inputFile
303+
pArgs.outputFile +='.' + bitCodeArchiveExtension
304+
305+
logging.info('Writing output to {0}'.format(pArgs.outputFile))
306+
307+
return archiveFiles(pArgs, bitCodeFiles)
305308

306-
logging.info('Writing output to {0}'.format(outputFile))
307309

308-
return archiveFiles(outputFile, llvmArchiver, bitCodeFiles)
310+
class ExtractedArgs:
309311

312+
fileType = None
313+
314+
extractor = None
315+
316+
arCmd = None
310317

311318

312319
def extract_bc_args(args):
313-
import argparse
314-
315-
global verboseFlag
316320

317321
# do we need a path in front?
318322
llvmToolPrefix = os.getenv(llvmCompilerPathEnv)
@@ -332,109 +336,120 @@ def extract_bc_args(args):
332336
llvmArchiver = os.path.join(llvmToolPrefix, llvmArchiverName)
333337

334338
parser = argparse.ArgumentParser(description=__doc__)
335-
parser.add_argument("wllvm_binary", help="A binary produced by wllvm/wllvm++")
336-
parser.add_argument("--linker","-l",
339+
parser.add_argument(dest='inputFile',
340+
help='A binary produced by wllvm/wllvm++')
341+
parser.add_argument('--linker','-l',
342+
dest='llvmLinker',
337343
help='The LLVM bitcode linker to use. Default "%(default)s"',
338344
default=llvmLinker)
339-
parser.add_argument("--archiver","-a",
345+
parser.add_argument('--archiver','-a',
346+
dest='llvmArchiver',
340347
help='The LLVM bitcode archiver to use. Default "%(default)s"',
341348
default=llvmArchiver)
342-
parser.add_argument("--verbose","-v",
349+
parser.add_argument('--verbose','-v',
350+
dest='verboseFlag',
343351
help='Call the external procedures in verbose mode.',
344352
action="store_true")
345-
parser.add_argument("--manifest","-m",
353+
parser.add_argument('--manifest', '-m',
354+
dest='manifestFlag',
346355
help='Write a manifest file listing all the .bc files used.',
347-
action="store_true")
348-
parser.add_argument("--output","-o",
356+
action='store_true')
357+
parser.add_argument('--bytecode', '-b',
358+
dest='bytecodeModuleFlag',
359+
help='Extract a bytecode module rather than an archive. ' +
360+
'Only useful when extracting from an archive.',
361+
action='store_true')
362+
parser.add_argument('--output','-o',
363+
dest='outputFile',
349364
help='The output file. Defaults to a file in the same directory ' +
350365
'as the input with the same name as the input but with an ' +
351366
'added file extension (.'+ moduleExtension + ' for bitcode '+
352367
'modules and .' + bitCodeArchiveExtension +' for bitcode archives)',
353368
default=None)
354-
parsedArgs = parser.parse_args()
369+
pArgs = parser.parse_args(namespace=ExtractedArgs())
355370

356-
inputFile = parsedArgs.wllvm_binary
357-
llvmLinker = parsedArgs.linker
358-
llvmArchiver = parsedArgs.archiver
359-
verboseFlag = parsedArgs.verbose
360-
manifestFlag = parsedArgs.manifest
361371

362372
# Check file exists
363-
if not os.path.exists(inputFile):
364-
logging.error('File "{0}" does not exist.'.format(inputFile))
365-
return (False, inputFile, '', llvmLinker, llvmArchiver, manifestFlag)
373+
if not os.path.exists(pArgs.inputFile):
374+
logging.error('File "{0}" does not exist.'.format(pArgs.inputFile))
375+
return (False, None)
376+
377+
pArgs.inputFile = os.path.abspath(pArgs.inputFile)
366378

379+
367380
# Check output destitionation if set
368-
outputFile = parsedArgs.output
381+
outputFile = pArgs.outputFile
369382
if outputFile != None:
370383
# Get Absolute output path
371384
outputFile = os.path.abspath(outputFile)
372385
if not os.path.exists(os.path.dirname(outputFile)):
373-
logging.error('Output directory "{0}" does not exist.'.format(
374-
os.path.dirname(outputFile)))
375-
return (False, inputFile, '', llvmLinker, llvmArchiver, manifestFlag)
386+
logging.error('Output directory "{0}" does not exist.'.format(os.path.dirname(outputFile)))
387+
return (False, None)
376388

377-
return (True, inputFile, outputFile, llvmLinker, llvmArchiver, manifestFlag)
389+
pArgs.output = outputFile
378390

391+
return (True, pArgs)
392+
379393

380394
def main(args):
381395

382-
(success, inputFile, outputFile, llvmLinker, llvmArchiver, manifestFlag) = extract_bc_args(args)
396+
(success, pArgs) = extract_bc_args(args)
383397

384398
if not success:
385399
return 1
386400

387-
if ( sys.platform.startswith('freebsd') or
388-
sys.platform.startswith('linux') ):
401+
if ( sys.platform.startswith('freebsd') or sys.platform.startswith('linux') ):
389402

390-
process_file_unix(inputFile, outputFile, llvmLinker, llvmArchiver, manifestFlag)
403+
process_file_unix(pArgs)
391404

392405
elif sys.platform.startswith('darwin'):
393406

394-
process_file_darwin(inputFile, outputFile, llvmLinker, llvmArchiver, manifestFlag)
407+
process_file_darwin(pArgs)
395408

396409
else:
397410
#iam: do we work on anything else?
398411
logging.error('Unsupported or unrecognized platform: {0}'.format(sys.platform))
399412
return 1
400413

401414

402-
def process_file_unix(inputFile, outputFile, llvmLinker, llvmArchiver, manifestFlag):
403-
ft = FileType.getFileType(inputFile)
415+
def process_file_unix(pArgs):
416+
417+
ft = FileType.getFileType(pArgs.inputFile)
404418
logging.debug('Detected file type is {0}'.format(FileType.revMap[ft]))
405419

406-
extractor = extract_section_linux
407-
arCmd = ['ar', 'xv'] if verboseFlag else ['ar', 'x']
408-
ofileType = FileType.ELF_OBJECT
420+
pArgs.arCmd = ['ar', 'xv'] if pArgs.verboseFlag else ['ar', 'x']
421+
pArgs.extractor = extract_section_linux
422+
pArgs.fileType = FileType.ELF_OBJECT
409423

410424
if ft == FileType.ELF_EXECUTABLE or ft == FileType.ELF_SHARED or ft == FileType.ELF_OBJECT:
411425
logging.info('Generating LLVM Bitcode module')
412-
return handleExecutable(inputFile, outputFile, extractor, llvmLinker, manifestFlag)
426+
return handleExecutable(pArgs)
413427
elif ft == FileType.ARCHIVE:
414428
logging.info('Generating LLVM Bitcode archive')
415-
return handleArchive(inputFile, outputFile, arCmd, ofileType, extractor, llvmArchiver, manifestFlag)
429+
return handleArchive(pArgs)
416430
else:
417-
logging.error('File "{0}" of type {1} cannot be used'.format(inputFile,FileType.revMap[ft]))
431+
logging.error('File "{0}" of type {1} cannot be used'.format(pArgs.inputFile, FileType.revMap[ft]))
418432
return 1
419433

420434

421435

422-
def process_file_darwin(inputFile, outputFile, llvmLinker, llvmArchiver, manifestFlag):
423-
ft = FileType.getFileType(inputFile)
436+
def process_file_darwin(pArgs):
437+
438+
ft = FileType.getFileType(pArgs.inputFile)
424439
logging.debug('Detected file type is {0}'.format(FileType.revMap[ft]))
425440

426-
extractor = extract_section_darwin
427-
arCmd = ['ar', '-x', '-v'] if verboseFlag else ['ar', '-x']
428-
ofileType = FileType.MACH_OBJECT
441+
pArgs.arCmd = ['ar', '-x', '-v'] if pArgs.verboseFlag else ['ar', '-x']
442+
pArgs.extractor = extract_section_darwin
443+
pArgs.fileType = FileType.MACH_OBJECT
429444

430445
if ft == FileType.MACH_EXECUTABLE or ft == FileType.MACH_SHARED or ft == FileType.MACH_OBJECT:
431446
logging.info('Generating LLVM Bitcode module')
432-
return handleExecutable(inputFile, outputFile, extractor, llvmLinker, manifestFlag)
447+
return handleExecutable(pArgs)
433448
elif ft == FileType.ARCHIVE:
434449
logging.info('Generating LLVM Bitcode archive')
435-
return handleArchive(inputFile, outputFile, arCmd, ofileType, extractor, llvmArchiver, manifestFlag)
450+
return handleArchive(pArgs)
436451
else:
437-
logging.error('File "{0}" of type {1} cannot be used'.format(inputFile,FileType.revMap[ft]))
452+
logging.error('File "{0}" of type {1} cannot be used'.format(pArgs.inputFile, FileType.revMap[ft]))
438453
return 1
439454

440455

0 commit comments

Comments
 (0)