Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/usr/bin/env python3
# Copyright 2013-2019 Valve Corporation
# Copyright 2019 Collabora Ltd.
#
# SPDX-License-Identifier: MIT
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import argparse
import logging
import os
import re
import subprocess
import sys
"""
Provide build-ID-based hard links to legacy path-based debugging symbols.
Based on build-runtime.py in steam-runtime.
"""
logger = logging.getLogger('flatdeb.dbgsym-use-build-id')
def main():
# type: (...) -> None
parser = argparse.ArgumentParser(
description=(
'Provide build-ID-based hard links for legacy debug symbols'
),
)
parser.add_argument(
'--dry-run',
action='store_true',
default=False,
)
parser.add_argument('--debug-dir', default='/usr/lib/debug')
args = parser.parse_args()
for dirname, subdirs, files in os.walk(args.debug_dir):
# Skip build-ID directory: it is already in the form we wanted
if '.build-id' in subdirs:
subdirs.remove('.build-id')
for f in files:
if f.endswith('.txt'):
continue
# Scrape the output of readelf to find the build-ID for this
# binary
path = os.path.join(dirname, f)
with subprocess.Popen([
os.environ.get('READELF', 'readelf'), '-n', path,
], stdout=subprocess.PIPE, universal_newlines=True) as p:
stdout = p.stdout
assert stdout is not None
for line in stdout:
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
m = re.search(
r'Build ID: ([a-fA-F0-9]{2})([a-fA-F0-9]+)',
line,
re.ASCII,
)
if m is None:
continue
# ensure no path traversal
assert '.' not in m.group(1)
assert '.' not in m.group(2)
linkdir = os.path.join(
args.debug_dir, '.build-id', m.group(1),
)
link = os.path.join(linkdir, m.group(2) + '.debug')
if args.dry_run:
logger.info('Would hard-link %s as %s', path, link)
else:
logger.info('Hard-linking %s as %s', path, link)
if not os.access(linkdir, os.W_OK):
os.makedirs(linkdir)
if os.path.lexists(link):
os.unlink(link)
os.link(os.path.join(dirname, f), link)
break
else:
logger.warning(
'Unable to create build-ID-based hard link to %s',
path,
)
if __name__ == '__main__':
if sys.stderr.isatty():
try:
import colorlog
except ImportError:
logging.basicConfig()
else:
formatter = colorlog.ColoredFormatter(
'%(log_color)s%(levelname)s:%(name)s:%(reset)s %(message)s')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logging.getLogger().addHandler(handler)
else:
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
try:
main()
except KeyboardInterrupt:
raise SystemExit(130)