iBoot/tools/parse_release_log.py

89 lines
3.1 KiB
Python

#!/usr/bin/python
import re
import os
import hashlib
import hmac
import argparse
import sys
argparser = argparse.ArgumentParser(description='Parses obfuscated logging from iBoot release builds')
argparser.add_argument('--src', required=True, help='iBoot source tree corresponding to log')
argparser.add_argument('-v', '--verbose', action='store_true', default=False, help='Attempts to load log string from source file instead of simplying printing the source file and line number')
argparser.add_argument('filename', nargs='?', default=None, help='File to read log from (omit for stdin)')
args = argparser.parse_args()
id_file_map = {}
directory = args.src
base_hmac = hmac.new('obfuscation of filename for release build logging', '', hashlib.sha1)
for (path, dirnames, filenames) in os.walk(directory):
# strip the part of the pathname we supplied off the pathname
shortened_path = path[len(directory)+1:]
# don't iterate into paths we don't care about
try:
dirnames.remove('.svn')
except ValueError:
pass
# only look at .c and .cpp files in the build directory, be more permissive elsewhere
if shortened_path.startswith('build/'):
filenames = [x for x in filenames if x.endswith('.c') or x.endswith('.cpp')]
for filename in filenames:
full_path = os.path.join(shortened_path, filename)
current_hmac = base_hmac.copy()
current_hmac.update(full_path)
file_id = current_hmac.hexdigest()[:16]
if file_id in id_file_map and id_file_map[file_id] != full_path:
print 'Warning: Files "{}" and "{}" both have the same ID {}'.format(full_path, id_file_map[file_id], file_id)
else:
id_file_map[file_id] = full_path
file_cache = {}
def get_src_line(filename, line_number):
if filename not in file_cache:
file_path = os.path.join(directory, filename)
with open(file_path) as f:
lines = [x.strip() for x in f]
file_cache[filename] = lines
return file_cache[filename][line_number - 1]
def parse_src_line(src_line):
result = re.match(r'dprintf\s*\(\s*[a-zA-Z0-9_]+,\s*"([^"]*)".*', src_line)
if result is not None:
return result.group(1)
else:
return src_line
def parse_log(f):
log_re = re.compile(r'^(.*\|)?([0-9a-f]{16}):(\d+)$')
for line in f:
line = line.rstrip()
result = log_re.match(line)
if result is not None:
timestamp = result.group(1) or ''
file_id = result.group(2)
line_number = int(result.group(3))
if file_id in id_file_map:
filename = id_file_map[file_id]
if args.verbose:
src_line = get_src_line(filename, line_number)
print '{}{} [{}:{}]'.format(timestamp, parse_src_line(src_line), filename, line_number)
else:
print '{}{}:{}'.format(timestamp, filename, line_number)
continue
print line
if args.filename is not None:
with open(args.filename) as f:
parse_log(f)
else:
parse_log(sys.stdin)