Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| #!/bin/ksh | |
| # | |
| # kernel_diagreport2text.ksh | |
| # | |
| # Prints the stack trace from an OS X kernel panic diagnostic report, along | |
| # with as much symbol translation as your mach_kernel version provides. | |
| # By default, this is some, but with the Kernel Debug Kit, it should be a lot | |
| # more. This is not an official Apple tool. | |
| # | |
| # USAGE: | |
| # ./kernel_diagreport2text.ksh [-f kernel_file] Kernel_report.panic [...] | |
| # | |
| # Note: The Kernel Debug Kit currently requires an Apple ID to download. It | |
| # would be great if this was not necessary. | |
| # | |
| # This script calls atos(1) for symbol translation, and also some sed/awk | |
| # to decorate remaining untranslated symbols with kernel extension names, | |
| # if the ranges match. | |
| # | |
| # This uses your current kernel, /mach_kernel, to translate symbols. If you run | |
| # this on kernel diag reports from a different kernel version, it will print | |
| # a "kernel version mismatch" warning, as the translation may be incorrect. Find | |
| # a matching mach_kernel file and use the -f option to point to it. | |
| # | |
| # Copyright 2014 Brendan Gregg. All rights reserved. | |
| # | |
| # CDDL HEADER START | |
| # | |
| # The contents of this file are subject to the terms of the | |
| # Common Development and Distribution License (the "License"). | |
| # You may not use this file except in compliance with the License. | |
| # | |
| # You can obtain a copy of the license at docs/cddl1.txt or | |
| # http://opensource.org/licenses/CDDL-1.0. | |
| # See the License for the specific language governing permissions | |
| # and limitations under the License. | |
| # | |
| # When distributing Covered Code, include this CDDL HEADER in each | |
| # file and include the License file at docs/cddl1.txt. | |
| # If applicable, add the following below this CDDL HEADER, with the | |
| # fields enclosed by brackets "[]" replaced with your own identifying | |
| # information: Portions Copyright [yyyy] [name of copyright owner] | |
| # | |
| # CDDL HEADER END | |
| kernel=/mach_kernel | |
| function usage { | |
| print "USAGE: $0 [-f kernel_file] Kernel_diag_report.panic [...]" | |
| print " eg, $0 /Library/Logs/DiagnosticReports/Kernel_2014-05-26-124827_bgregg.panic" | |
| exit | |
| } | |
| (( $# == 0 )) && usage | |
| [[ $1 == "-h" || $1 == "--help" ]] && usage | |
| if [[ $1 == "-f" ]]; then | |
| kernel=$2 | |
| if [[ ! -e $kernel ]]; then | |
| print -u2 "ERROR: Kernel $kernel not found. Quitting." | |
| exit 2 | |
| fi | |
| shift 2 | |
| fi | |
| if [[ ! -x /usr/bin/atos ]]; then | |
| print -u2 "ERROR: Couldn't find, and need, /usr/bin/atos. Is this part of Xcode? Quitting..." | |
| exit 2 | |
| fi | |
| while (( $# != 0 )); do | |
| if [[ "$file" != "" ]]; then print; fi | |
| file=$1 | |
| shift | |
| echo "File $file" | |
| if [[ ! -e $file ]]; then | |
| print "ERROR: File $file not found. Skipping." | |
| continue | |
| fi | |
| # Find slide address | |
| slide=$(awk '/^Kernel slide:.*0x/ { print $3 }' $file) | |
| if [[ "$slide" == "" ]]; then | |
| print -n "ERROR: Missing \"Kernel slide:\" line, so can't process $file. " | |
| print "This is needed for atos -s. Is this really a Kernel diag panic file?" | |
| continue | |
| fi | |
| # Print panic line | |
| grep '^panic' $file | |
| # Check kernel version match (uname -v string) | |
| kernel_ver=$(strings -a $kernel | grep 'Darwin Kernel Version') | |
| panic_ver=$(grep 'Darwin Kernel Version' $file) | |
| warn="" | |
| if [[ "$kernel_ver" != "$panic_ver" ]]; then | |
| print "WARNING: kernel version mismatch (use -f):" | |
| printf "%14s: %s\n" "$kernel" "$kernel_ver" | |
| printf "%14s: %s\n" "panic file" "$panic_ver" | |
| warn=" (may be incorrect due to mismatch)" | |
| fi | |
| # Find kernel extension ranges | |
| i=0 | |
| unset name start end | |
| awk 'ext == 1 && /0x.*->.*0x/ { | |
| gsub(/\[.*\]/, ""); gsub(/@/, " "); gsub(/->/, " ") | |
| print $0 | |
| } | |
| /Kernel Extensions in backtrace/ { ext = 1 } | |
| /^$/ { ext = 0 } | |
| ' < $file | while read n s e; do | |
| # the awk gsub's convert this line: | |
| # com.apple.driver.AppleUSBHub(666.4)[CD9B71FF-2FDD-3BC4-9C39-5E066F66D158]@0xffffff7f84ed2000->0xffffff7f84ee9fff | |
| # into this: | |
| # com.apple.driver.AppleUSBHub(666.4) 0xffffff7f84ed2000 0xffffff7f84ee9fff | |
| # which can then be read as three fields | |
| name[i]=$n | |
| start[i]=$s | |
| end[i]=$e | |
| (( i++ )) | |
| done | |
| # Print and translate stack | |
| print "Stack$warn:" | |
| awk 'backtrace == 1 && /^[^ ]/ { print $3 } | |
| /Backtrace.*Return Address/ { backtrace = 1 } | |
| /^$/ { backtrace = 0 } | |
| ' < $file | atos -d -o $kernel -s $slide | while read line; do | |
| # do extensions | |
| if [[ $line =~ 0x* ]]; then | |
| i=0 | |
| while (( i <= ${#name[@]} )); do | |
| [[ "${start[i]}" == "" ]] && break | |
| # assuming fixed width addresses, use string comparison: | |
| if [[ $line > ${start[$i]} && $line < ${end[$i]} ]]; then | |
| line="$line (in ${name[$i]})" | |
| break | |
| fi | |
| (( i++ )) | |
| done | |
| fi | |
| print " $line" | |
| done | |
| # Print other key details | |
| awk '/^BSD process name/ { gsub(/ corresponding to current thread/, ""); print $0 } | |
| ver == 1 { print "Mac OS version:", $0; ver = 0 } | |
| /^Mac OS version/ { ver = 1 } | |
| ' < $file | |
| done |