]>
Commit | Line | Data |
---|---|---|
3ce6a8ad MT |
1 | #!/bin/bash |
2 | # extract-debuginfo.sh - automagically generate debug info | |
3 | # | |
4 | # Usage: extract-debuginfo.sh [--strict-build-id] [-g] [-r] | |
5 | # [builddir] | |
6 | # | |
7 | # The -g flag says to use strip -g instead of full strip on DSOs. | |
8 | # The --strict-build-id flag says to exit with failure status if | |
9 | # any ELF binary processed fails to contain a build-id note. | |
10 | # The -r flag says to use eu-strip --reloc-debug-sections. | |
11 | # | |
12 | # All file names in switches are relative to builddir (. if not given). | |
13 | # | |
14 | ||
15 | echo "Extracting debuginfo to /usr/lib/debug..." | |
16 | ||
17 | export LC_ALL=C | |
18 | ||
19 | # With -g arg, pass it to strip on libraries. | |
20 | strip_g=false | |
21 | ||
22 | # with -r arg, pass --reloc-debug-sections to eu-strip. | |
23 | strip_r=false | |
24 | ||
25 | # Barf on missing build IDs. | |
26 | strict=false | |
27 | ||
28 | BUILDDIR=. | |
29 | while [ $# -gt 0 ]; do | |
30 | case "${1}" in | |
31 | --sourcedir=*) | |
32 | SOURCEDIR=${1#--sourcedir=} | |
33 | ;; | |
34 | --buildroot=*) | |
35 | BUILDROOT=${1#--buildroot=} | |
36 | ;; | |
37 | --strict-build-id) | |
38 | strict=true | |
39 | ;; | |
40 | -g) | |
41 | strip_g=true | |
42 | ;; | |
43 | -r) | |
44 | strip_r=true | |
45 | ;; | |
46 | *) | |
47 | BUILDDIR=${1} | |
48 | shift | |
49 | break | |
50 | ;; | |
51 | esac | |
52 | shift | |
53 | done | |
54 | ||
55 | debugdir="${BUILDROOT}/usr/lib/debug" | |
56 | ||
57 | # A list of source files that are included in the -debuginfo packages. | |
58 | SOURCEFILE="$(mktemp)" | |
59 | ||
60 | strip_to_debug() { | |
61 | local g= | |
62 | local r= | |
63 | ${strip_r} && r=--reloc-debug-sections | |
64 | ${strip_g} && \ | |
65 | case "$(file -bi "${2}")" in | |
66 | application/x-sharedlib*) | |
67 | g=-g | |
68 | ;; | |
69 | esac | |
70 | ||
71 | eu-strip --remove-comment ${r} ${g} -f "${1}" "${2}" || exit | |
72 | chmod 444 "${1}" || exit | |
73 | } | |
74 | ||
75 | # Make a relative symlink to $1 called $3$2 | |
76 | shopt -s extglob | |
77 | link_relative() { | |
78 | local t="$1" f="$2" pfx="$3" | |
79 | local fn="${f#/}" tn="${t#/}" | |
80 | local fd td d | |
81 | ||
82 | while fd="${fn%%/*}"; td="${tn%%/*}"; [ "$fd" = "$td" ]; do | |
83 | fn="${fn#*/}" | |
84 | tn="${tn#*/}" | |
85 | done | |
86 | ||
87 | d="${fn%/*}" | |
88 | if [ "$d" != "$fn" ]; then | |
89 | d="${d//+([!\/])/..}" | |
90 | tn="${d}/${tn}" | |
91 | fi | |
92 | ||
93 | mkdir -p "$(dirname "$pfx$f")" && ln -snf "$tn" "$pfx$f" | |
94 | } | |
95 | ||
96 | # Make a symlink in /usr/lib/debug/$2 to $1 | |
97 | debug_link() { | |
98 | local l="/usr/lib/debug$2" | |
99 | local t="$1" | |
100 | link_relative "$t" "$l" "$BUILDROOT" | |
101 | } | |
102 | ||
103 | # Provide .2, .3, ... symlinks to all filename instances of this build-id. | |
104 | make_id_dup_link() { | |
105 | local id="${1}" file="${2}" idfile | |
106 | ||
107 | local n=1 | |
108 | while true; do | |
109 | idfile=".build-id/${id:0:2}/${id:2}.${n}" | |
110 | [ $# -eq 3 ] && idfile="${idfile}$3" | |
111 | if [ ! -L "${BUILDROOT}/usr/lib/debug/${idfile}" ]; then | |
112 | break | |
113 | fi | |
114 | n=$[${n}+1] | |
115 | done | |
116 | debug_link "${file}" "/${idfile}" | |
117 | } | |
118 | ||
119 | # Make a build-id symlink for id $1 with suffix $3 to file $2. | |
120 | make_id_link() { | |
121 | local id="${1}" file="${2}" | |
122 | local idfile=".build-id/${id:0:2}/${id:2}" | |
123 | [ $# -eq 3 ] && idfile="${idfile}${3}" | |
124 | local root_idfile="${BUILDROOT}/usr/lib/debug/${idfile}" | |
125 | ||
126 | if [ ! -L "${root_idfile}" ]; then | |
127 | debug_link "${file}" "/${idfile}" | |
128 | return | |
129 | fi | |
130 | ||
131 | make_id_dup_link "$@" | |
132 | ||
133 | [ $# -eq 3 ] && return 0 | |
134 | ||
135 | local other=$(readlink -m "${root_idfile}") | |
136 | other=${other#$BUILDROOT} | |
137 | if cmp -s "${root_idfile}" "${BUILDROOT}${file}" || | |
138 | eu-elfcmp -q "${root_idfile}" "${BUILDROOT}${file}" 2> /dev/null; then | |
139 | # Two copies. Maybe one has to be setuid or something. | |
140 | echo >&2 "*** WARNING: identical binaries are copied, not linked:" | |
141 | echo >&2 " ${file}" | |
142 | echo >&2 " and ${other}" | |
143 | else | |
144 | # This is pathological, break the build. | |
145 | echo >&2 "*** ERROR: same build ID in nonidentical files!" | |
146 | echo >&2 " ${file}" | |
147 | echo >&2 " and ${other}" | |
148 | exit 2 | |
149 | fi | |
150 | } | |
151 | ||
152 | get_debugfn() { | |
153 | dn=$(dirname "${1#$BUILDROOT}") | |
154 | bn=$(basename "$1" .debug).debug | |
155 | ||
156 | debugdn=${debugdir}${dn} | |
157 | debugfn=${debugdn}/${bn} | |
158 | } | |
159 | ||
160 | set -o pipefail | |
161 | ||
162 | strict_error=ERROR | |
163 | ${strict} || strict_error=WARNING | |
164 | ||
165 | ||
166 | # Strip ELF binaries | |
167 | find "$BUILDROOT" ! -path "${debugdir}/*.debug" -type f \ | |
168 | \( -perm -0100 -or -perm -0010 -or -perm -0001 \) \ | |
169 | -print | | |
170 | file -N -f - | sed -n -e 's/^\(.*\):[ ]*.*ELF.*, not stripped/\1/p' | | |
171 | xargs --no-run-if-empty stat -c '%h %D_%i %n' | | |
172 | while read nlinks inum f; do | |
173 | get_debugfn "${f}" | |
174 | [ -f "${debugfn}" ] && continue | |
175 | ||
176 | # If this file has multiple links, keep track and make | |
177 | # the corresponding .debug files all links to one file too. | |
178 | if [ ${nlinks} -gt 1 ]; then | |
179 | eval linked=\$linked_${inum} | |
180 | if [ -n "${linked}" ]; then | |
181 | eval id=\${linkedid_${inum}} | |
182 | make_id_dup_link "${id}" "${dn}/$(basename ${f})" | |
183 | make_id_dup_link "${id}" "/usr/lib/debug${dn}/${bn}" .debug | |
184 | link=${debugfn} | |
185 | get_debugfn "${linked}" | |
186 | echo " hard linked ${link} to ${debugfn}" | |
187 | mkdir -p "$(dirname "$link")" && ln -nf "$debugfn" "$link" | |
188 | continue | |
189 | else | |
190 | eval linked_${inum}=\${f} | |
191 | echo " file ${f} has $[${nlinks} - 1] other hard links" | |
192 | fi | |
193 | fi | |
194 | ||
195 | echo " Extracting debug info from ${f#${BUILDROOT}}" | |
196 | id=$(/usr/lib/pakfire/debugedit -i \ | |
197 | -b "${SOURCEDIR}" \ | |
198 | -d /usr/src/debug \ | |
199 | -l "${SOURCEFILE}" \ | |
200 | "${f}") || exit | |
201 | ||
202 | if [ ${nlinks} -gt 1 ]; then | |
203 | eval linkedid_${inum}=\${id} | |
204 | fi | |
205 | ||
206 | if [ -z "$id" ]; then | |
207 | echo >&2 "*** ${strict_error}: No build ID note found in ${f#${BUILDROOT}}" | |
208 | ${strict} && exit 2 | |
209 | fi | |
210 | ||
211 | [ -x /usr/bin/gdb-add-index ] && /usr/bin/gdb-add-index "${f}" > /dev/null 2>&1 | |
212 | ||
213 | # A binary already copied into /usr/lib/debug doesn't get stripped, | |
214 | # just has its file names collected and adjusted. | |
215 | case "${dn}" in | |
216 | /usr/lib/debug/*) | |
217 | [ -z "${id}" ] || make_id_link "${id}" "${dn}/$(basename ${f})" | |
218 | continue | |
219 | ;; | |
220 | esac | |
221 | ||
222 | mkdir -p "${debugdn}" | |
223 | if test -w "${f}"; then | |
224 | strip_to_debug "${debugfn}" "${f}" | |
225 | else | |
226 | chmod u+w "${f}" | |
227 | strip_to_debug "${debugfn}" "${f}" | |
228 | chmod u-w "${f}" | |
229 | fi | |
230 | ||
231 | if [ -n "${id}" ]; then | |
232 | make_id_link "${id}" "${dn}/$(basename ${f})" | |
233 | make_id_link "${id}" "/usr/lib/debug${dn}/${bn}" .debug | |
234 | fi | |
235 | done || exit | |
236 | ||
237 | # For each symlink whose target has a .debug file, | |
238 | # make a .debug symlink to that file. | |
239 | find $BUILDROOT ! -path "${debugdir}/*" -type l -print | | |
240 | while read f; do | |
241 | t=$(readlink -m "$f").debug | |
242 | f=${f#$BUILDROOT} | |
243 | t=${t#$BUILDROOT} | |
244 | if [ -f "$debugdir$t" ]; then | |
245 | echo "symlinked /usr/lib/debug$t to /usr/lib/debug${f}.debug" | |
246 | debug_link "/usr/lib/debug$t" "${f}.debug" | |
247 | fi | |
248 | done | |
249 | ||
250 | if [ -s "${SOURCEFILE}" ]; then | |
251 | mkdir -p "${BUILDROOT}/usr/src/debug" | |
252 | ||
253 | sort -z -u "${SOURCEFILE}" | grep -E -v -z '(<internal>|<built-in>)$' | \ | |
254 | (cd "${SOURCEDIR}"; cpio -pd0mL "${BUILDROOT}/usr/src/debug" 2>/dev/null) | |
255 | ||
256 | # stupid cpio creates new directories in mode 0700, fixup | |
257 | find "${BUILDROOT}/usr/src/debug" -type d -print0 | \ | |
258 | xargs --no-run-if-empty -0 chmod a+rx | |
259 | ||
260 | # Fix ownership. | |
261 | chown root:root -R ${BUILDROOT}/usr/src/debug | |
262 | fi | |
263 | ||
264 | rm -f ${SOURCEFILE} | |
265 | ||
266 | exit 0 |