gdb-add-index 4.5 KB

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