1*4882a593Smuzhiyun#! /bin/sh 2*4882a593Smuzhiyun 3*4882a593Smuzhiyun# Add a .gdb_index section to a file. 4*4882a593Smuzhiyun 5*4882a593Smuzhiyun# Copyright (C) 2010-2021 Free Software Foundation, Inc. 6*4882a593Smuzhiyun# This program is free software; you can redistribute it and/or modify 7*4882a593Smuzhiyun# it under the terms of the GNU General Public License as published by 8*4882a593Smuzhiyun# the Free Software Foundation; either version 3 of the License, or 9*4882a593Smuzhiyun# (at your option) any later version. 10*4882a593Smuzhiyun# 11*4882a593Smuzhiyun# This program is distributed in the hope that it will be useful, 12*4882a593Smuzhiyun# but WITHOUT ANY WARRANTY; without even the implied warranty of 13*4882a593Smuzhiyun# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*4882a593Smuzhiyun# GNU General Public License for more details. 15*4882a593Smuzhiyun# 16*4882a593Smuzhiyun# You should have received a copy of the GNU General Public License 17*4882a593Smuzhiyun# along with this program. If not, see <http://www.gnu.org/licenses/>. 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun# This program assumes gdb and objcopy are in $PATH. 20*4882a593Smuzhiyun# If not, or you want others, pass the following in the environment 21*4882a593SmuzhiyunGDB=${GDB:=gdb} 22*4882a593SmuzhiyunOBJCOPY=${OBJCOPY:=objcopy} 23*4882a593SmuzhiyunREADELF=${READELF:=readelf} 24*4882a593Smuzhiyun 25*4882a593Smuzhiyunmyname="${0##*/}" 26*4882a593Smuzhiyun 27*4882a593Smuzhiyundwarf5="" 28*4882a593Smuzhiyunif [ "$1" = "-dwarf-5" ]; then 29*4882a593Smuzhiyun dwarf5="$1" 30*4882a593Smuzhiyun shift 31*4882a593Smuzhiyunfi 32*4882a593Smuzhiyun 33*4882a593Smuzhiyunif test $# != 1; then 34*4882a593Smuzhiyun echo "usage: $myname [-dwarf-5] FILE" 1>&2 35*4882a593Smuzhiyun exit 1 36*4882a593Smuzhiyunfi 37*4882a593Smuzhiyun 38*4882a593Smuzhiyunfile="$1" 39*4882a593Smuzhiyun 40*4882a593Smuzhiyunif test ! -r "$file"; then 41*4882a593Smuzhiyun echo "$myname: unable to access: $file" 1>&2 42*4882a593Smuzhiyun exit 1 43*4882a593Smuzhiyunfi 44*4882a593Smuzhiyun 45*4882a593Smuzhiyundir="${file%/*}" 46*4882a593Smuzhiyuntest "$dir" = "$file" && dir="." 47*4882a593Smuzhiyun 48*4882a593Smuzhiyundwz_file="" 49*4882a593Smuzhiyunif $READELF -S "$file" | grep -q " \.gnu_debugaltlink "; then 50*4882a593Smuzhiyun dwz_file=$($READELF --string-dump=.gnu_debugaltlink "$file" \ 51*4882a593Smuzhiyun | grep -A1 "'\.gnu_debugaltlink':" \ 52*4882a593Smuzhiyun | tail -n +2 \ 53*4882a593Smuzhiyun | sed 's/.*]//') 54*4882a593Smuzhiyun dwz_file=$(echo $dwz_file) 55*4882a593Smuzhiyun if $READELF -S "$dwz_file" | grep -E -q " \.(gdb_index|debug_names) "; then 56*4882a593Smuzhiyun # Already has an index, skip it. 57*4882a593Smuzhiyun dwz_file="" 58*4882a593Smuzhiyun fi 59*4882a593Smuzhiyunfi 60*4882a593Smuzhiyun 61*4882a593Smuzhiyunset_files () 62*4882a593Smuzhiyun{ 63*4882a593Smuzhiyun local file="$1" 64*4882a593Smuzhiyun 65*4882a593Smuzhiyun index4="${file}.gdb-index" 66*4882a593Smuzhiyun index5="${file}.debug_names" 67*4882a593Smuzhiyun debugstr="${file}.debug_str" 68*4882a593Smuzhiyun debugstrmerge="${file}.debug_str.merge" 69*4882a593Smuzhiyun debugstrerr="${file}.debug_str.err" 70*4882a593Smuzhiyun} 71*4882a593Smuzhiyun 72*4882a593Smuzhiyuntmp_files= 73*4882a593Smuzhiyunfor f in "$file" "$dwz_file"; do 74*4882a593Smuzhiyun if [ "$f" = "" ]; then 75*4882a593Smuzhiyun continue 76*4882a593Smuzhiyun fi 77*4882a593Smuzhiyun set_files "$f" 78*4882a593Smuzhiyun tmp_files="$tmp_files $index4 $index5 $debugstr $debugstrmerge $debugstrerr" 79*4882a593Smuzhiyundone 80*4882a593Smuzhiyun 81*4882a593Smuzhiyunrm -f $tmp_files 82*4882a593Smuzhiyun 83*4882a593Smuzhiyun# Ensure intermediate index file is removed when we exit. 84*4882a593Smuzhiyuntrap "rm -f $tmp_files" 0 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun$GDB --batch -nx -iex 'set auto-load no' \ 87*4882a593Smuzhiyun -ex "file $file" -ex "save gdb-index $dwarf5 $dir" || { 88*4882a593Smuzhiyun # Just in case. 89*4882a593Smuzhiyun status=$? 90*4882a593Smuzhiyun echo "$myname: gdb error generating index for $file" 1>&2 91*4882a593Smuzhiyun exit $status 92*4882a593Smuzhiyun} 93*4882a593Smuzhiyun 94*4882a593Smuzhiyun# In some situations gdb can exit without creating an index. This is 95*4882a593Smuzhiyun# not an error. 96*4882a593Smuzhiyun# E.g., if $file is stripped. This behaviour is akin to stripping an 97*4882a593Smuzhiyun# already stripped binary, it's a no-op. 98*4882a593Smuzhiyunstatus=0 99*4882a593Smuzhiyun 100*4882a593Smuzhiyunhandle_file () 101*4882a593Smuzhiyun{ 102*4882a593Smuzhiyun local file 103*4882a593Smuzhiyun file="$1" 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun set_files "$file" 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun if test -f "$index4" -a -f "$index5"; then 108*4882a593Smuzhiyun echo "$myname: Both index types were created for $file" 1>&2 109*4882a593Smuzhiyun status=1 110*4882a593Smuzhiyun elif test -f "$index4" -o -f "$index5"; then 111*4882a593Smuzhiyun if test -f "$index4"; then 112*4882a593Smuzhiyun index="$index4" 113*4882a593Smuzhiyun section=".gdb_index" 114*4882a593Smuzhiyun else 115*4882a593Smuzhiyun index="$index5" 116*4882a593Smuzhiyun section=".debug_names" 117*4882a593Smuzhiyun fi 118*4882a593Smuzhiyun debugstradd=false 119*4882a593Smuzhiyun debugstrupdate=false 120*4882a593Smuzhiyun if test -s "$debugstr"; then 121*4882a593Smuzhiyun if ! $OBJCOPY --dump-section .debug_str="$debugstrmerge" "$file" \ 122*4882a593Smuzhiyun /dev/null 2>$debugstrerr; then 123*4882a593Smuzhiyun cat >&2 $debugstrerr 124*4882a593Smuzhiyun exit 1 125*4882a593Smuzhiyun fi 126*4882a593Smuzhiyun if grep -q "can't dump section '.debug_str' - it does not exist" \ 127*4882a593Smuzhiyun $debugstrerr; then 128*4882a593Smuzhiyun debugstradd=true 129*4882a593Smuzhiyun else 130*4882a593Smuzhiyun debugstrupdate=true 131*4882a593Smuzhiyun cat >&2 $debugstrerr 132*4882a593Smuzhiyun fi 133*4882a593Smuzhiyun cat "$debugstr" >>"$debugstrmerge" 134*4882a593Smuzhiyun fi 135*4882a593Smuzhiyun 136*4882a593Smuzhiyun $OBJCOPY --add-section $section="$index" \ 137*4882a593Smuzhiyun --set-section-flags $section=readonly \ 138*4882a593Smuzhiyun $(if $debugstradd; then \ 139*4882a593Smuzhiyun echo --add-section .debug_str="$debugstrmerge"; \ 140*4882a593Smuzhiyun echo --set-section-flags .debug_str=readonly; \ 141*4882a593Smuzhiyun fi; \ 142*4882a593Smuzhiyun if $debugstrupdate; then \ 143*4882a593Smuzhiyun echo --update-section .debug_str="$debugstrmerge"; \ 144*4882a593Smuzhiyun fi) \ 145*4882a593Smuzhiyun "$file" "$file" 146*4882a593Smuzhiyun 147*4882a593Smuzhiyun status=$? 148*4882a593Smuzhiyun else 149*4882a593Smuzhiyun echo "$myname: No index was created for $file" 1>&2 150*4882a593Smuzhiyun echo "$myname: [Was there no debuginfo? Was there already an index?]" \ 151*4882a593Smuzhiyun 1>&2 152*4882a593Smuzhiyun fi 153*4882a593Smuzhiyun} 154*4882a593Smuzhiyun 155*4882a593Smuzhiyunhandle_file "$file" 156*4882a593Smuzhiyunif [ "$dwz_file" != "" ]; then 157*4882a593Smuzhiyun handle_file "$dwz_file" 158*4882a593Smuzhiyunfi 159*4882a593Smuzhiyun 160*4882a593Smuzhiyunexit $status 161