mirror of
https://github.com/swg-ostrich/ostrich.git
synced 2026-01-16 23:04:19 -05:00
221 lines
5.8 KiB
Bash
221 lines
5.8 KiB
Bash
#!/bin/bash -f
|
|
|
|
if [ $# != 4 ]; then
|
|
echo Usage: coreMemoryReport.sh exename corename dumpname reportname
|
|
exit 1
|
|
fi
|
|
|
|
checkTool()
|
|
{
|
|
which $1 >& /dev/null
|
|
if [ $? = 1 ]; then
|
|
echo "Could not find $1 in $PATH."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# check for needed tools
|
|
checkTool grep
|
|
checkTool sed
|
|
checkTool sort
|
|
checkTool uniq
|
|
checkTool gawk
|
|
checkTool objdump
|
|
checkTool addr2line
|
|
checkTool CoreMemWalker
|
|
|
|
# check gawk version, need >= 3.1 for coprocesses
|
|
awk_major=`gawk --version |grep '^GNU Awk' |sed -e '/^GNU Awk /s///' -e '/\..*$/s///'`
|
|
awk_minor=`gawk --version |grep '^GNU Awk' |sed -e '/^GNU Awk [0-9]*\./s///' -e '/\..*$/s///'`
|
|
|
|
if [ $awk_major -le 3 ]; then
|
|
if [ $awk_major -lt 3 ] || [ $awk_minor -lt 1 ]; then
|
|
echo 'GNU Awk version >= 3.1 is required.'
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
EXE=$1
|
|
CORE=$2
|
|
DUMPNAME=$3
|
|
REPORTNAME=$4
|
|
|
|
# load the memory map for a specified object file and section type
|
|
loadMemoryMap()
|
|
{
|
|
objdump -h $1 |grep $2 >.tmpmem
|
|
ao_c=0
|
|
while read -a LINE ; do
|
|
let s=0x${LINE[3]}
|
|
let e=$s+0x${LINE[2]}
|
|
let o=0x${LINE[5]}-$s
|
|
ao_s[$ao_c]=$s
|
|
ao_e[$ao_c]=$e
|
|
ao_o[$ao_c]=$o
|
|
let ao_c=$ao_c+1
|
|
done <.tmpmem
|
|
}
|
|
|
|
# determine the offset in the file associated with the current memory map of the memory address passed in
|
|
getAddrOffset()
|
|
{
|
|
result=0
|
|
let t=$1
|
|
i=0
|
|
while [ $i -lt $ao_c ]; do
|
|
if [ $t -ge ${ao_s[$i]} ] && [ $t -lt ${ao_e[$i]} ] ; then
|
|
let result=${ao_o[$i]}+$t
|
|
break
|
|
fi
|
|
let i=$i+1
|
|
done
|
|
echo $result
|
|
}
|
|
|
|
# determine the object to search for memory manager info
|
|
MEMOBJ=`ldd $EXE |grep libsharedMemoryManager.so |sed 's/[()]//g' |gawk '{print $3}'`
|
|
if [ "$MEMOBJ" = "" ]; then
|
|
MEMOBJ=$EXE
|
|
MEMOFS=0
|
|
else
|
|
LINE=(`ldd $EXE |sed 's/[()]//g' |sort -k 4,4 |nl |gawk '{print $1, $4}' |grep libsharedMemoryManager.so`)
|
|
MEMOFS=0x`objdump -h $CORE |grep -B1 'READONLY, CODE' |grep '00000000 4' |nl |grep "^ *${LINE[0]} " |gawk '{print $5}'`
|
|
fi
|
|
|
|
# grab the mappings of memory regions in the memory manager object
|
|
echo Getting memory manager object memory map...
|
|
loadMemoryMap $MEMOBJ rodata
|
|
|
|
# determine the number of entries in the memory block call stacks
|
|
echo Determining memory block owner call stack size...
|
|
LINE=(`objdump -t $MEMOBJ |grep ' _[^G]*22MemoryManagerNamespace.*cms_allocatedBlockSize'`)
|
|
offset=`getAddrOffset 0x${LINE[0]}`
|
|
LINE=(`od -t x4 -j$offset -N4 $MEMOBJ`)
|
|
let own_size=(0x${LINE[1]}-12)/4
|
|
|
|
# grab the mappings of memory regions in the core file
|
|
echo Getting core memory map...
|
|
loadMemoryMap $CORE load
|
|
|
|
# get the address of the first memory block
|
|
echo Finding first memory block...
|
|
LINE=(`objdump -t $MEMOBJ |grep '22MemoryManagerNamespace.*ms_firstSystemAllocation'`)
|
|
let adjustedOfs=0x${LINE[0]}+$MEMOFS
|
|
offset=`getAddrOffset $adjustedOfs`
|
|
LINE=(`od -t x4 -j$offset -N4 $CORE`)
|
|
let firstAddr=0x${LINE[1]}
|
|
|
|
rm -f $DUMPNAME
|
|
|
|
echo Dumping allocated block info...
|
|
CoreMemWalker $CORE .tmpmem $firstAddr $own_size >$DUMPNAME
|
|
rm -f .tmpmem
|
|
|
|
echo Processing memory report...
|
|
cat $DUMPNAME |sed 's/^0x[0-9a-f]* //' |sort -n |uniq -c | \
|
|
gawk '
|
|
{
|
|
printf "%d %d", $1*$2, $1
|
|
for (i = 3; i <= NF; ++i)
|
|
printf " %s", $i
|
|
printf "\n"
|
|
}' | sort -n -r >.tmpdmp
|
|
|
|
rm -f .tmpresolve .tmplib*
|
|
|
|
# Determine all binaries associated with $EXE, and store their names and
|
|
# base addresses in the lib_name and lib_addr arrays respectively.
|
|
echo Determining address spaces...
|
|
lib_count=1
|
|
lib_addr[0]=0
|
|
lib_name[0]=$EXE
|
|
ldd $EXE |sed 's/[()]//g' |sort -k 4,4 |nl |gawk '{print $1, $4}' >.tmplibs
|
|
while read -a LINE ; do
|
|
lib_name[$lib_count]=${LINE[1]}
|
|
let lib_addr[$lib_count]=0x`objdump -h $CORE |grep -B1 'READONLY, CODE' |grep '00000000 4' |nl |grep "^ *${LINE[0]} " |gawk '{print $5}'`
|
|
let lib_count=$lib_count+1
|
|
done <.tmplibs
|
|
|
|
# Determine which library in the lib_name/lib_addr arrays the passed in
|
|
# address belongs to. Return the index in the array.
|
|
getLibNumber()
|
|
{
|
|
result=0
|
|
let t=$1
|
|
j=1
|
|
while [ $j -lt $lib_count ]; do
|
|
if [ ${lib_addr[$j]} -gt $t ] ; then
|
|
break
|
|
fi
|
|
let j=$j+1
|
|
done
|
|
let result=$j-1
|
|
echo $result
|
|
}
|
|
|
|
# Run through all referenced addresses, sorting them by the binary they
|
|
# belong to, and saving a file of addresses and a separate file of
|
|
# addresses relative to the binary's start address. Also fill in '??:0'
|
|
# in the resolved address cache for each address, so that every referenced
|
|
# address has an entry, and use that to prevent trying to resolve an
|
|
# address multiple times (by outputting duplicates to the per-binary
|
|
# address list files).
|
|
echo Sorting addresses by lib...
|
|
while read -a LINE ; do
|
|
# run through $LINE[2..] accumulating addresses per lib
|
|
i=2
|
|
while [ $i -lt ${#LINE[*]} ]; do
|
|
addr=${LINE[$i]}
|
|
if [ "${addr_cache[$addr]}" != "??:0" ] ; then
|
|
lib_number=`getLibNumber $addr`
|
|
let offset=addr-${lib_addr[$lib_number]}
|
|
echo $addr >> .tmplib_addr_$lib_number
|
|
echo -n "0x" >> .tmplib_ofs_$lib_number
|
|
echo "obase=16; $offset" |bc >> .tmplib_ofs_$lib_number
|
|
addr_cache[$addr]="??:0"
|
|
fi
|
|
let i=$i+1
|
|
done
|
|
done <.tmpdmp
|
|
|
|
# Resolve all addresses referenced in the report, batched by which binary
|
|
# the address belongs to.
|
|
echo Resolving Addresses...
|
|
i=0
|
|
while [ $i -lt $lib_count ]; do
|
|
if [ -e .tmplib_ofs_$i ]; then
|
|
addr2line -s -e ${lib_name[$i]} `cat .tmplib_ofs_$i` >.tmpresolve
|
|
j=0
|
|
while read -a LINE ; do
|
|
resolved[$j]=${LINE[*]}
|
|
let j=$j+1
|
|
done <.tmpresolve
|
|
j=0
|
|
while read -a LINE ; do
|
|
addr_cache[${LINE[*]}]=${resolved[$j]}
|
|
let j=$j+1
|
|
done <.tmplib_addr_$i
|
|
fi
|
|
let i=$i+1
|
|
done
|
|
|
|
# Generate the final report file, by looking up all but the first 2 fields of
|
|
# everything in .tmpdmp in the resolved address cache.
|
|
echo Generating Report...
|
|
rm -f $REPORTNAME
|
|
while read -a LINE ; do
|
|
echo -n "${LINE[0]} ${LINE[1]}" >> $REPORTNAME
|
|
i=2
|
|
while [ $i -lt ${#LINE[*]} ]; do
|
|
addr=${LINE[$i]}
|
|
echo -n " ${addr_cache[$addr]}($addr)" >> $REPORTNAME
|
|
let i=$i+1
|
|
done
|
|
echo >> $REPORTNAME
|
|
done <.tmpdmp
|
|
|
|
rm -f .tmpdmp .tmpresolve .tmplib*
|
|
|
|
echo Done!
|
|
|