#!/bin/sh

# src/tools/find_typedef

# This script attempts to find all typedef's in the postgres binaries
# by using 'nm' to report all typedef debugging symbols.
# 
# For this program to work, you must have compiled all binaries with 
# debugging symbols.
#
# This is run on BSD/OS 4.0 or Linux, so you may need to make changes.
# 
# Ignore the nm errors about a file not being a binary file.
#
# It gets typedefs by reading "STABS":
#
#    http://www.informatik.uni-frankfurt.de/doc/texi/stabs_toc.html
#
#    objdump:
#       -G, --stabs  Display (in raw form) any STABS info in the file
#
#       --stabs
#         Display the contents of the .stab, .stab.index, and
#         .stab.excl sections from an ELF file.  This is only
#         useful on systems (such as Solaris  2.0)  in  which
#         .stab debugging symbol-table entries are carried in
#         an ELF section.  In most other file formats, debug-
#         ging  symbol-table  entries  are  interleaved  with
#         linkage symbols, and are visible in the --syms out-
#         put.


if [ "$#" -eq 0 -o ! -d "$1" ]
then	echo "Usage:  $0 postgres_binary_directory [...]" 1>&2
	exit 1
fi

for DIR
do	# if objdump -W is recognized, only one line of error should appear
	if [ `objdump -W 2>&1 | wc -l` -eq 1 ]
	then	# Linux
		# Unfortunately the Linux version doesn't show unreferenced typedefs.
		# The problem is that they are still in the source code so should be
		# indented properly.  However, I think pgindent only cares about
		# the typedef references, not the definitions, so I think it might
		# be fine
		objdump -W "$DIR"/* |
		egrep -A3 '\(DW_TAG_typedef\)' |
		awk ' $2 == "DW_AT_name" {print $NF}'
	elif [ `readelf -w 2>&1 | wc -l` -gt 1 ]
	then	# FreeBSD, similar output to Linux
		readelf -w "$DIR"/* |
		egrep -A3 '\(DW_TAG_typedef\)' |
		awk ' $1 == "DW_AT_name" {print $NF}'
	else	# BSD/OS
		# BSD/OS reports all typedefs, even those defined in system
		# include files but never referenced in the PG code.
		objdump --stabs "$DIR"/* |
		awk ' $2 == "LSYM" && $7 ~ /:t/ {sub(":.*", "", $7); print $7}'
	fi
done |
grep -v ' ' | # some typedefs have spaces, remove them
sort |
uniq |
# these are used both for typedefs and variable names
# so do not include them
egrep -v '^(date|interval|timestamp|ANY)$'
