#!/bin/ksh
# javaLibsGrabber.sh
# rev 1
# from the tool newLibsGrabber.sh By Roger Leuckie
# modified to remove the -p and -f flags and accept parameters
# from the command line. Also update usage message and other
# cosmetic changes by Russ Cunningham
# 02/22/06
# takes two parameters, the name of the core file and the directory
# path to the executable that caused the core.
# extracts the libraries and executable paths from the core file
# and creates a compressed tar file called ARCHIVE_NAME
# in the current directory containing these files
# does some error checking to see if its a complete core file
# the the error checking is not complete so a partial core may
# slip through
# 02/23/06 
# made a change suggested by Wei Luo on the java team to fix a
# major problem of the customer not knowing which java installed
# on the machine was the one that created the core file.
# The script now makes a pass through the core file looking for the
# full path for the libjava.a library which is always in the same
# directory as the java executable. It strips off the path and uses
# that path to retrieve the correct java

(( mask64 		= 1 ))

(( word_size		= 4 ))
(( bit_size		= 32 ))
(( is64bit		= 0 ))

(( loader_offset	= 0 ))
(( next_offset		= 1 ))
(( lib_offset		= 0 ))

(( path_max		= 1024 + 9 ))

ARCHIVE_NAME="core-libs.tar.Z"

grep "#define[ 	]*PATH_MAX[ 	]*" /usr/include/sys/limits.h 2>/dev/null | \
	 head -1 |  awk '{print $3}' | read path_max

get_bitsize(){
	od -tdL -j1276 -N4 ${1} 2>/dev/null | head -1 | awk '{print $2}' | read bit64_flag

	if [ -z "${bit64_flag}" ]; then
		echo "ERROR: unable to determine if 32/64 bit application. may be truncated." >&2
		exit 1
	fi

	if (( mask64 == ( bit64_flag & mask64 ) )); then
		(( bit_size	= 64 ))
		(( word_size	= 8 ))
		(( is64bit	= 1 ))
	fi
}

get_loader_offset() {
	od -tdL -j16 -N8 ${1} | head -1 | awk '{print $3}' | read loader_offset

	if [ -z "${loader_offset}" ]; then
		echo "ERROR: unable to determine loader offset. may be truncated." >&2
		exit 1
	fi

	if (( loader_offset < 1 )) || (( loader_offset > 1000000 )); then
		echo "ERROR: loader offset out of range ( 1-100000 ). may be corrupted." >&2
		exit 1
	fi
}

get_next_offset() {
	od -tdI -j${2} -N4 ${1} | awk '{print $2}' | read next_offset

	if [ -z "${next_offset}" ]; then
		echo "ERROR: unable to determine next lib offset. may be corrupted." >&2	
		exit 1
	fi
}

get_lib_offset() {
	(( lib_offset		= ${1} + ( word_size * 6 ) ))
}


get_file() {
	od -S -j${2} -N${path_max} ${1} | head -1 | awk '{print $2}'
}

get_file_list() {

	get_bitsize ${1}
	get_loader_offset ${1}
	(( current_offset	= loader_offset ))

	while (( next_offset != 0 )); do

		get_next_offset ${1} ${current_offset}
		get_lib_offset ${current_offset}

		get_file ${1} ${lib_offset} | read file_in_core

		if [ ! -f ${file_in_core} ]; then
			# this should only happen for the executable
	    		if [ -f "${EXEC_PATH}/${file_in_core}" ]; then
				path_and_file="${EXEC_PATH}/${file_in_core}"
			fi
	
		else
			path_and_file="${file_in_core}"
		fi

#		echo "INFO: file in core: ${file_in_core}	full path: ${path_and_file}" >&2

		echo "${path_and_file}"

#echo "${is64bit} ${bit_size} ${word_size} ${loader_offset} ${next_offset} ${lib_offset}"


		(( current_offset = current_offset + next_offset ))
	done
}

usage() {
	echo
	echo "USAGE: ${0}  core_file  " >&2
	echo "Like: ${0} core.001 " >&2
	echo
	exit 1
}
if [ $# != 1 ]; then
	usage
fi

echo "finding the path for the executable that caused the core file" >&2
EXEC_PATH=$(dirname "$( get_file_list ${1} | sort -u | grep libjava.a)")

echo "the path is ${EXEC_PATH}" 

core_file=$1



if [ ! -f ${core_file} ]; then
	echo "ERROR: ${core_file} does not exist." >&2
	exit 1
fi

if [ -n "${EXEC_PATH}" ]; then
	if [ ! -d ${EXEC_PATH} ]; then
		echo "ERROR: ${EXEC_PATH} may not be a directory." >&2
		exit 1
	fi
fi

echo "INFO: processing AIX core ${core_file}" >&2

file_list="$( get_file_list ${core_file} | sort -u | sed "s|^/|./|g" )"

# added 01/25/06
# to always pickup the two libs needed by the dbx prog
dbxstring="  ./usr/lib/libpthdebug.a  ./usr/lib/libdbx.a"
file_list=${file_list}${dbxstring}
#echo $file_list >file_list

if [ -z "${file_list}" ]; then
	echo "ERROR: no files could be determined from ${core_file}." >&2
	exit 1
fi

echo "${file_list}" | wc -l | read file_count

# added 01/25/06
# add 2 to file_count as the two extra files we added don't have
# new lines but tar doesn't care, just the error routine
(( file_count=file_count + 2))

echo "INFO: archiving ${file_count} files identifed from ${core_file}" >&2

cd /
tar -chf - ${file_list} | compress -c > ${OLDPWD}/${ARCHIVE_NAME}
cd ${OLDPWD}

if [ ! -f ${ARCHIVE_NAME} ]; then
	echo "ERROR: unable to create archive of libraries." >&2
	exit 1
fi

uncompress -c < ${ARCHIVE_NAME} | tar -tvf - | wc -l | read tar_file_count
if (( tar_file_count == 0 )); then
	echo "ERROR: unable to verify archive ${ARCHIVE_NAME}." >&2
	exit 1
fi
if (( file_count != tar_file_count )); then
	echo "ERROR: number of files in ${ARCHIVE_NAME} not valid." >&2
	exit
fi
echo "INFO: ${ARCHIVE_NAME} created." >&2
exit 0
