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 |