flatcar-scripts/cros_generate_breakpad_symbols
Michael Krebs 104d20d8ea Don't generate symbols for files that dump_syms can't handle.
dump_syms can only dump the symbols of an executable with the same ELF
format as itself.  Some recent build configurations now have binaries with
differing ELF formats.  For example, issue 25468 has a 64-bit kernel where
everything else is 32-bit, and issue 25466 indicates there's a test that
contains a 32-bit executable.

BUG=chromium-os:25496, chromium-os:25468, chromium-os:25466
TEST=Ran cros_generate_breakpad_symbols on 32/64-bit executables

Change-Id: I15f5115585b3ed54ca7ae7b631216285baef8580
Reviewed-on: https://gerrit.chromium.org/gerrit/14835
Tested-by: Michael Krebs <mkrebs@chromium.org>
Reviewed-by: David James <davidjames@chromium.org>
Commit-Ready: Michael Krebs <mkrebs@chromium.org>
2012-01-25 17:47:25 -08:00

237 lines
7.1 KiB
Bash
Executable File

#!/bin/bash
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Script to generate minidump symbols in the format required by
# minidump_stackwalk to dump stack information.
#
# NOTE: This script must be run from the chromeos build chroot environment.
#
# --- BEGIN COMMON.SH BOILERPLATE ---
# Load common CrOS utilities. Inside the chroot this file is installed in
# /usr/lib/crosutils. Outside the chroot we find it relative to the script's
# location.
find_common_sh() {
local common_paths=(/usr/lib/crosutils $(dirname "$(readlink -f "$0")"))
local path
SCRIPT_ROOT=
for path in "${common_paths[@]}"; do
if [ -r "${path}/common.sh" ]; then
SCRIPT_ROOT=${path}
break
fi
done
}
find_common_sh
. "${SCRIPT_ROOT}/common.sh" || { echo "Unable to load common.sh"; exit 1; }
# --- END COMMON.SH BOILERPLATE ---
# Script must be run inside the chroot
restart_in_chroot_if_needed "$@"
get_default_board
# Flags
DEFINE_string board "$DEFAULT_BOARD" "The board to build packages for."
DEFINE_string minidump_symbol_root "" \
"Symbol root (defaults to /usr/lib/debug/breakpad for board)"
DEFINE_boolean verbose ${FLAGS_FALSE} "Be verbose."
CUMULATIVE_SIZE=0
ANY_ERRORS=0
SYM_FILE=$(mktemp "/tmp/sym.XXXX")
ERR_FILE=$(mktemp "/tmp/err.XXXX")
function cleanup() {
rm -f "${SYM_FILE}" "${ERR_FILE}"
}
# Given path to a debug file, return its text file
function get_text_for_debug() {
local debug_file=$1
local text_dir=$(dirname "${debug_file#$DEBUG_ROOT}")
local text_path=${SYSROOT}${text_dir}/$(basename "${debug_file}" .debug)
echo ${text_path}
}
# Given path to a text file, return its debug file
function get_debug_for_text() {
local text_file=$1
local text_path=${text_file#${SYSROOT}}
local debug_path=${DEBUG_ROOT}${text_path}.debug
echo ${debug_path}
}
# Returns true if the file given is a 64-bit ELF file.
function is_64b_elf() {
local elf="$1"
file "${elf}" | grep -q "ELF 64-bit"
}
# Verify the file given is an ELF file that dump_syms can handle. A 32-bit
# dump_syms cannot dump a 64-bit ELF file, and vice versa.
function verify_not_mismatched_elf() {
local elf="$1"
if [ ${DUMP_SYMS_IS_64BIT} -ne 0 ]; then
if ! is_64b_elf "${elf}"; then
warn "Not dumping symbols for file ${elf} because it is not 64-bit"
return 1
fi
else
if is_64b_elf "${elf}"; then
warn "Not dumping symbols for file ${elf} because it is 64-bit"
return 1
fi
fi
return 0
}
# Dump given debug and text file. Returns 1 if any errors, even
# if they can be ignored, but only sets ANY_ERRORS if the error should not
# be ignored (and we should not proceed to upload).
function dump_file() {
local debug_file="$1"
local text_file="$2"
local debug_directory="$(dirname "${debug_file}")"
# 32-bit dump_syms cannot dump a 64-bit ELF file, and vice versa
verify_not_mismatched_elf "${text_file}" || return 1
# Dump symbols as root in order to read all files.
if ! sudo "${DUMP_SYMS}" "${text_file}" "${debug_directory}" > "${SYM_FILE}" \
2> "${ERR_FILE}"; then
# Try dumping just the main file to get public-only symbols.
if ! sudo "${DUMP_SYMS}" "${text_file}" > "${SYM_FILE}" 2> "${ERR_FILE}";
then
# A lot of files (like kernel files) contain no debug information, do
# not consider such occurrences as errors.
if grep -q "file contains no debugging information" "${ERR_FILE}"; then
warn "No symbols found for ${text_file}"
return 1
fi
error "Unable to dump symbols for ${text_file}:"
cat "${ERR_FILE}"
ANY_ERRORS=1
return 1
else
warn "File ${text_file} did not have debug info, using linkage symbols"
fi
fi
local file_id=$(head -1 ${SYM_FILE} | cut -d' ' -f4)
local module_name=$(head -1 ${SYM_FILE} | cut -d' ' -f5)
if [ ${FLAGS_verbose} -eq ${FLAGS_TRUE} ]; then
# Show file upload success and symbol info for easier lookup
info "Dumped symbols from ${text_file} for ${module_name}|${file_id}."
fi
# Sanity check: if we've created the same named file in the /usr/lib/debug
# directory during the src_compile stage of an ebuild, verify our sym file
# is the same.
local installed_sym="${DEBUG_ROOT}"/$(basename "${text_file}").sym
if [ -e "${installed_sym}" ]; then
if ! diff "${installed_sym}" "${SYM_FILE}"; then
error "${installed_sym} differ from current sym file:"
diff "${installed_sym}" "${SYM_FILE}"
ANY_ERRORS=1
return 1
fi
fi
size=$(wc -c "${SYM_FILE}" | cut -d' ' -f1)
CUMULATIVE_SIZE=$((CUMULATIVE_SIZE + $size))
local container_dir="${FLAGS_minidump_symbol_root}/${module_name}/${file_id}"
sudo mkdir -p "${container_dir}"
sudo mv "${SYM_FILE}" "${container_dir}/${module_name}.sym"
return 0
}
# Convert the given debug file. No return value.
function process_file() {
local debug_file="$1"
local text_file="$(get_text_for_debug ${debug_file})"
if [ "${text_file##*.}" == "ko" ]; then
# Skip kernel objects. We can't use their symbols and they sometimes
# have objects with empty text sections which trigger errors in dump_sym.
if [ ${FLAGS_verbose} -eq ${FLAGS_TRUE} ]; then
info "Skipping kernel object: ${text_file}"
fi
return 0
fi
if [ ! -f "${text_file}" ]; then
# Allow files to not exist, for instance if they are in the INSTALL_MASK.
warn "Binary does not exist: ${text_file}"
return 0
fi
dump_file "${debug_file}" "${text_file}"
}
function main() {
trap cleanup EXIT
# Parse command line
FLAGS_HELP="usage: $0 [flags] [<files...>]"
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
set -e
[ -n "$FLAGS_board" ] || die "--board is required."
case "$(portageq-${FLAGS_board} envvar ARCH)" in
amd64)
echo "Detected amd64 board.."
DUMP_SYMS="/build/${FLAGS_board}/usr/bin/dump_syms"
DUMP_SYMS_IS_64BIT=1
;;
*)
DUMP_SYMS="dump_syms"
DUMP_SYMS_IS_64BIT=0
esac
echo "Using dump_sys: $DUMP_SYMS"
SYSROOT="/build/${FLAGS_board}"
if [[ -z "${FLAGS_minidump_symbol_root}" ]]; then
FLAGS_minidump_symbol_root="${SYSROOT}/usr/lib/debug/breakpad"
fi
info "Writing minidump symbols to ${FLAGS_minidump_symbol_root}"
DEBUG_ROOT="${SYSROOT}/usr/lib/debug"
CUMULATIVE_SIZE=0
sudo rm -rf "${FLAGS_minidump_symbol_root}"
if [ -z "${FLAGS_ARGV}" ]; then
for debug_file in $(find "${DEBUG_ROOT}" -name \*.debug); do
! process_file "${debug_file}"
done
else
for either_file in ${FLAGS_ARGV}; do
either_file=${either_file#\'}
either_file=${either_file%\'}
if [ ! -f "${either_file}" ]; then
error "Specified file ${either_file} does not exist"
ANY_ERRORS=1
continue
fi
if [ "${either_file##*.}" == "debug" ]; then
debug_file="${either_file}"
else
debug_file="$(get_debug_for_text ${either_file})"
fi
! process_file "${debug_file}"
done
fi
info "Generated ${CUMULATIVE_SIZE}B of debug information"
[ ${ANY_ERRORS} -ne 0 ] && die "Encountered problems"
return 0
}
main "$@"