| OLD | NEW |
| 1 #!/bin/bash | 1 #!/bin/bash |
| 2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 # Script to upload all debug symbols required for crash reporting | 6 # Script to upload all debug symbols required for crash reporting |
| 7 # purposes. This script need only be used to upload release builds | 7 # purposes. This script need only be used to upload release builds |
| 8 # symbols or to debug crashes on non-release builds (in which case try | 8 # symbols or to debug crashes on non-release builds (in which case try |
| 9 # to only upload the symbols for those executables involved). | 9 # to only upload the symbols for those executables involved). |
| 10 # | 10 # |
| 11 # NOTE: This script must be run from the chromeos build chroot environment. | 11 # NOTE: This script must be run from the chromeos build chroot environment. |
| 12 # | 12 # |
| 13 | 13 |
| 14 # Load common constants. This should be the first executable line. | 14 # Load common constants. This should be the first executable line. |
| 15 # The path to common.sh should be relative to your script's location. | 15 # The path to common.sh should be relative to your script's location. |
| 16 . "$(dirname "$0")/common.sh" | 16 . "$(dirname "$0")/common.sh" |
| 17 | 17 |
| 18 # Script must be run inside the chroot | 18 # Script must be run inside the chroot |
| 19 restart_in_chroot_if_needed $* | 19 restart_in_chroot_if_needed $* |
| 20 | 20 |
| 21 get_default_board | 21 get_default_board |
| 22 | 22 |
| 23 # Flags | 23 # Flags |
| 24 DEFINE_string board "$DEFAULT_BOARD" "The board to build packages for." | 24 DEFINE_string board "$DEFAULT_BOARD" "The board to build packages for." |
| 25 DEFINE_boolean dryrun ${FLAGS_FALSE} "Run without actually uploading." | 25 DEFINE_boolean official_build $FLAGS_FALSE "Point to official symbol server." |
| 26 DEFINE_boolean regenerate $FLAGS_TRUE "Regenerate all symbols." |
| 26 DEFINE_boolean verbose ${FLAGS_FALSE} "Be verbose." | 27 DEFINE_boolean verbose ${FLAGS_FALSE} "Be verbose." |
| 27 DEFINE_boolean official_build $FLAGS_FALSE "Point to official symbol server." | |
| 28 DEFINE_boolean yes ${FLAGS_FALSE} "Answer yes to all prompts." | 28 DEFINE_boolean yes ${FLAGS_FALSE} "Answer yes to all prompts." |
| 29 | 29 |
| 30 DUMP_SYMS="dump_syms" | |
| 31 SYM_UPLOAD="sym_upload" | 30 SYM_UPLOAD="sym_upload" |
| 32 | 31 |
| 33 CUMULATIVE_SIZE=0 | |
| 34 ANY_ERRORS=0 | 32 ANY_ERRORS=0 |
| 35 | 33 |
| 36 SYM_FILE=$(mktemp "/tmp/sym.XXXX") | |
| 37 ERR_FILE=$(mktemp "/tmp/err.XXXX") | 34 ERR_FILE=$(mktemp "/tmp/err.XXXX") |
| 38 | 35 |
| 39 function cleanup() { | 36 function cleanup() { |
| 40 rm -f "${SYM_FILE}" "${ERR_FILE}" | 37 rm -f "${ERR_FILE}" |
| 41 } | 38 } |
| 42 | 39 |
| 43 # Given path to a debug file, return its text file | 40 function really_upload() { |
| 44 function get_text_for_debug { | |
| 45 local debug_file=$1 | |
| 46 local text_dir=$(dirname ${debug_file#$DEBUG_ROOT}) | |
| 47 local text_path=${SYSROOT}${text_dir}/$(basename "${debug_file}" .debug) | |
| 48 echo ${text_path} | |
| 49 } | |
| 50 | |
| 51 # Given path to a text file, return its debug file | |
| 52 function get_debug_for_text { | |
| 53 local text_file=$1 | |
| 54 local text_path=${text_file#${SYSROOT}} | |
| 55 local debug_path=${DEBUG_ROOT}${text_path}.debug | |
| 56 echo ${debug_path} | |
| 57 } | |
| 58 | |
| 59 function really_upload { | |
| 60 if [ ${FLAGS_yes} -eq ${FLAGS_TRUE} ]; then | 41 if [ ${FLAGS_yes} -eq ${FLAGS_TRUE} ]; then |
| 61 return 0 | 42 return 0 |
| 62 fi | 43 fi |
| 63 echo "Uploading symbols for an entire Chromium OS build is really only " | 44 echo "Uploading symbols for an entire Chromium OS build is really only " |
| 64 echo "necessary for release builds and in a few cases for developers " | 45 echo "necessary for release builds and in a few cases for developers " |
| 65 echo "to debug problems. It will take considerable time to run. For " | 46 echo "to debug problems. It will take considerable time to run. For " |
| 66 echo "developer debugging purposes, consider instead passing specific files " | 47 echo "developer debugging purposes, consider instead passing specific files " |
| 67 echo "to upload." | 48 echo "to upload." |
| 68 read -p "Are you sure you want to upload all build symbols (y/N)? " SURE | 49 read -p "Are you sure you want to upload all build symbols (y/N)? " SURE |
| 69 SURE="${SURE:0:1}" # Get just the first character | 50 SURE="${SURE:0:1}" # Get just the first character |
| 70 if [ "${SURE}" != "y" ]; then | 51 if [ "${SURE}" != "y" ]; then |
| 71 echo "Ok, better safe than sorry." | 52 echo "Ok, better safe than sorry." |
| 72 return 1 | 53 return 1 |
| 73 fi | 54 fi |
| 74 return 0 | 55 return 0 |
| 75 } | 56 } |
| 76 | 57 |
| 77 # Dump given debug and text file to SYM_FILE. Returns 1 if any errors, even | 58 # Upload the given symbol file to given URL. |
| 78 # if they can be ignored, but only sets ANY_ERRORS if the error should not | 59 function upload_file() { |
| 79 # be ignored (and we should not proceed to upload). | 60 local upload_file="$1" |
| 80 function dump_file { | 61 local upload_url="$2" |
| 81 local debug_file="$1" | 62 if [ ${FLAGS_verbose} -eq ${FLAGS_TRUE} ]; then |
| 82 local text_file="$2" | 63 info "Uploading ${upload_file}" |
| 83 # Dump symbols as root in order to read all files. | 64 fi |
| 84 if ! sudo "${DUMP_SYMS}" "${debug_file}" "${text_file}" > "${SYM_FILE}" \ | 65 if ! "${SYM_UPLOAD}" "${upload_file}" "${upload_url}" > /dev/null \ |
| 85 2> "${ERR_FILE}"; then | 66 2> "${ERR_FILE}"; then |
| 86 # A lot of files (like kernel files) contain no debug information, do | 67 error "Unable to upload symbols in ${upload_file}:" |
| 87 # not consider such occurrences as errors. | |
| 88 if grep -q "file contains no debugging information" "${ERR_FILE}"; then | |
| 89 warn "No symbols found for ${text_file}" | |
| 90 return 1 | |
| 91 fi | |
| 92 error "Unable to dump symbols for ${text_file}:" | |
| 93 cat "${ERR_FILE}" | 68 cat "${ERR_FILE}" |
| 94 ANY_ERRORS=1 | 69 ANY_ERRORS=1 |
| 95 return 1 | 70 return 1 |
| 96 fi | 71 fi |
| 97 if [ ${FLAGS_verbose} -eq ${FLAGS_TRUE} ]; then | 72 if [ ${FLAGS_verbose} -eq ${FLAGS_TRUE} ]; then |
| 98 local file_id=$(head -1 ${SYM_FILE} | cut -d' ' -f4) | 73 size=$(wc -c "${upload_file}" | cut -d' ' -f1) |
| 99 local module_name=$(head -1 ${SYM_FILE} | cut -d' ' -f5) | |
| 100 # Show file upload success and symbol info for easier lookup | |
| 101 info "Dumped symbols from ${text_file} for ${module_name}|${file_id}." | |
| 102 fi | |
| 103 # Sanity check: if we've created the same named file in the /usr/lib/debug | |
| 104 # directory during the src_compile stage of an ebuild, verify our sym file | |
| 105 # is the same. | |
| 106 local installed_sym="${DEBUG_ROOT}"/$(basename "${text_file}").sym | |
| 107 if [ -e "${installed_sym}" ]; then | |
| 108 if ! diff "${installed_sym}" "${SYM_FILE}"; then | |
| 109 error "${installed_sym} differ from current sym file:" | |
| 110 diff "${installed_sym}" "${SYM_FILE}" | |
| 111 ANY_ERRORS=1 | |
| 112 return 1 | |
| 113 fi | |
| 114 fi | |
| 115 size=$(wc -c "${SYM_FILE}" | cut -d' ' -f1) | |
| 116 CUMULATIVE_SIZE=$((CUMULATIVE_SIZE + $size)) | |
| 117 return 0 | |
| 118 } | |
| 119 | |
| 120 # Upload the current symbol file to given URL. | |
| 121 function upload_file { | |
| 122 local upload_url="$1" | |
| 123 if ! "${SYM_UPLOAD}" "${SYM_FILE}" "${upload_url}" > /dev/null \ | |
| 124 2> "${ERR_FILE}"; then | |
| 125 error "Unable to upload symbols in ${SYM_FILE}:" | |
| 126 cat "${ERR_FILE}" | |
| 127 ANY_ERRORS=1 | |
| 128 return 1 | |
| 129 fi | |
| 130 if [ ${FLAGS_verbose} -eq ${FLAGS_TRUE} ]; then | |
| 131 size=$(wc -c "${SYM_FILE}" | cut -d' ' -f1) | |
| 132 info "Successfully uploaded ${size}B." | 74 info "Successfully uploaded ${size}B." |
| 133 fi | 75 fi |
| 134 return 0 | 76 return 0 |
| 135 } | 77 } |
| 136 | 78 |
| 137 # Convert and then upload the given debug file to the given URL. No | |
| 138 # return value. | |
| 139 function process_file { | |
| 140 local debug_file="$1" | |
| 141 local upload_url="$2" | |
| 142 local text_file="$(get_text_for_debug ${debug_file})" | |
| 143 if [ "${text_file##*.}" == "ko" ]; then | |
| 144 # Skip kernel objects. We can't use their symbols and they sometimes | |
| 145 # have objects with empty text sections which trigger errors in dump_sym. | |
| 146 if [ ${FLAGS_verbose} -eq ${FLAGS_TRUE} ]; then | |
| 147 info "Skipping kernel object: ${text_file}" | |
| 148 fi | |
| 149 return 0 | |
| 150 fi | |
| 151 if [ "${text_file#${AUTOTEST_ROOT}}" != "${text_file}" ]; then | |
| 152 # Skip autotest files, they are not part of the image to debug | |
| 153 # and some cause trouble to dump_syms because they are built | |
| 154 # externally (with different build options). | |
| 155 if [ ${FLAGS_verbose} -eq ${FLAGS_TRUE} ]; then | |
| 156 info "Skipping autotest file: ${text_file}" | |
| 157 fi | |
| 158 return 0 | |
| 159 fi | |
| 160 if [ ! -f "${text_file}" ]; then | |
| 161 # Allow files to not exist, for instance if they are in the INSTALL_MASK. | |
| 162 warn "Binary does not exist: ${text_file}" | |
| 163 return 0 | |
| 164 fi | |
| 165 | |
| 166 dump_file "${debug_file}" "${text_file}" || return 0 | |
| 167 | |
| 168 [ ${FLAGS_dryrun} -eq ${FLAGS_TRUE} ] && return 0 | |
| 169 | |
| 170 upload_file "${upload_url}" | |
| 171 } | |
| 172 | |
| 173 function main() { | 79 function main() { |
| 174 trap cleanup EXIT | 80 trap cleanup EXIT |
| 175 | 81 |
| 176 # Parse command line | 82 # Parse command line |
| 177 FLAGS_HELP="usage: $0 [flags] [<files...>]" | 83 FLAGS_HELP="usage: $0 [flags] [<files...>]" |
| 178 FLAGS "$@" || exit 1 | 84 FLAGS "$@" || exit 1 |
| 179 eval set -- "${FLAGS_ARGV}" | 85 eval set -- "${FLAGS_ARGV}" |
| 180 | 86 |
| 181 set -e | 87 set -e |
| 182 | 88 |
| 183 [ -n "$FLAGS_board" ] || die "--board is required." | 89 [ -n "$FLAGS_board" ] || die "--board is required." |
| 184 | 90 |
| 185 SYSROOT="/build/${FLAGS_board}" | 91 SYSROOT="/build/${FLAGS_board}" |
| 186 | 92 |
| 187 local upload_url="" | 93 local upload_url="" |
| 188 if [ ${FLAGS_dryrun} -eq ${FLAGS_FALSE} ]; then | 94 if [ $FLAGS_official_build -eq $FLAGS_TRUE ]; then |
| 189 if [ $FLAGS_official_build -eq $FLAGS_TRUE ]; then | 95 upload_url="http://clients2.google.com/cr/symbol" |
| 190 upload_url="http://clients2.google.com/cr/symbol" | |
| 191 else | |
| 192 upload_url="http://clients2.google.com/cr/staging_symbol" | |
| 193 warn "This is an unofficial build, uploading to staging server." | |
| 194 fi | |
| 195 info "Uploading symbols to ${upload_url} from ${SYSROOT}." | |
| 196 else | 96 else |
| 197 warn "Will not upload symbols due to --nodryrun." | 97 upload_url="http://clients2.google.com/cr/staging_symbol" |
| 98 warn "This is an unofficial build, uploading to staging server." |
| 198 fi | 99 fi |
| 100 info "Uploading symbols to ${upload_url} from ${SYSROOT}." |
| 199 | 101 |
| 200 DEBUG_ROOT="${SYSROOT}/usr/lib/debug" | 102 MINIDUMP_SYMBOLS_ROOT="${SYSROOT}/usr/lib/debug/breakpad" |
| 201 AUTOTEST_ROOT="${SYSROOT}/usr/local/autotest" | |
| 202 CUMULATIVE_SIZE=0 | |
| 203 | 103 |
| 204 if [ -z "${FLAGS_ARGV}" ]; then | 104 if [ -z "${FLAGS_ARGV}" ]; then |
| 205 if [ ${FLAGS_dryrun} -eq ${FLAGS_FALSE} ]; then | 105 really_upload || exit 1 |
| 206 really_upload || exit 1 | 106 if [ ${FLAGS_regenerate} -eq ${FLAGS_TRUE} ]; then |
| 107 sudo rm -rf "${MINIDUMP_SYMBOLS_ROOT}" |
| 108 info "Generating all minidump symbol files." |
| 109 local verbosity="" |
| 110 local generate_script="$(dirname $0)/cros_generate_breakpad_symbols" |
| 111 [ ${FLAGS_verbose} -eq ${FLAGS_TRUE} ] && verbosity="--verbose" |
| 112 if ! "${generate_script}" --board=${FLAGS_board} ${verbosity}; then |
| 113 error "Some errors while generating symbols; uploading anyway" |
| 114 ANY_ERRORS=1 |
| 115 fi |
| 207 fi | 116 fi |
| 208 for debug_file in $(find "${DEBUG_ROOT}" -name \*.debug); do | 117 |
| 209 ! process_file "${debug_file}" "${upload_url}" | 118 info "Uploading all minidump symbol files." |
| 119 for sym_file in $(find "${MINIDUMP_SYMBOLS_ROOT}" -name \*.sym); do |
| 120 ! upload_file "${sym_file}" "${upload_url}" |
| 210 done | 121 done |
| 211 else | 122 else |
| 212 for either_file in ${FLAGS_ARGV}; do | 123 error "Unexpected args ${FLAGS_ARGV}" |
| 213 either_file=${either_file#\'} | |
| 214 either_file=${either_file%\'} | |
| 215 if [ ! -f "${either_file}" ]; then | |
| 216 error "Specified file ${either_file} does not exist" | |
| 217 ANY_ERRORS=1 | |
| 218 continue | |
| 219 fi | |
| 220 if [ "${either_file##*.}" == "debug" ]; then | |
| 221 debug_file="${either_file}" | |
| 222 else | |
| 223 debug_file="$(get_debug_for_text ${either_file})" | |
| 224 fi | |
| 225 ! process_file "${debug_file}" "${upload_url}"; | |
| 226 done | |
| 227 fi | |
| 228 | |
| 229 if [ ${FLAGS_dryrun} -eq ${FLAGS_TRUE} ]; then | |
| 230 warn "Did not actually upload, pass --nodryrun to upload" | |
| 231 info "Would have uploaded ${CUMULATIVE_SIZE}B of debug information" | |
| 232 else | |
| 233 info "Uploaded ${CUMULATIVE_SIZE}B of debug information" | |
| 234 fi | 124 fi |
| 235 | 125 |
| 236 [ ${ANY_ERRORS} -ne 0 ] && die "Encountered problems" | 126 [ ${ANY_ERRORS} -ne 0 ] && die "Encountered problems" |
| 237 return 0 | 127 return 0 |
| 238 } | 128 } |
| 239 | 129 |
| 240 main "$@" | 130 main "$@" |
| OLD | NEW |