#!/usr/bin/perl

# Copyright (C) 2012, 2019 Christoph Berg <myon@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# Gross hack to read the contents of Pg_magic_data from a .so file

use strict;
use warnings;

my $version_only = 0;
if ($ARGV[0] eq '-v') {
	$version_only = 1;
	shift @ARGV;
}

my $so = $ARGV[0] || die "Usage: $0 .so";

my $objdump = `objdump -d $so`;
my $address;
# 0000000000006880 <Pg_magic_func>:
#     6880:	48 8d 05 19 06 01 00 	lea    0x10619(%rip),%rax        # 16ea0 <_fini+0x11c>
if ($objdump =~ /<Pg_magic_func(?:\@\@Base)?>:\n.* # ([[:xdigit:]]+) </) {
	$address = hex($1);
# ... # 50a0 <Pg_magic_data.18191>
} elsif ($objdump =~ /# ([[:xdigit:]]+) <Pg_magic_data/) {
	$address = hex($1);
} else {
	die "No Pg_magic_data found in objdump -d $so output";
}
#print "address is $address ($1)\n";

open F, $so;
seek F, $address, 0;
my $data;
read F, $data, 4; # one integer
my $sizeof_pg_magic_struct = unpack("l", $data);;
#print "sizeof(Pg_magic_struct): $sizeof_pg_magic_struct\n";
read F, $data, $sizeof_pg_magic_struct - 4; # rest of Pg_magic_struct
my @integers = unpack("l*", $data);
my $PG_VERSION_NUM = $integers[0];

if ($version_only) {
	printf "%d.%d\n", $PG_VERSION_NUM / 100, $PG_VERSION_NUM % 100;
	exit 0;
}

my @fields = qw(PG_VERSION_NUM);
if ($PG_VERSION_NUM <= 803) { # 8.2 and 8.3 (Pg_magic_struct was introduced in 8.2)
	@fields = qw(PG_VERSION_NUM FUNC_MAX_ARGS INDEX_MAX_KEYS NAMEDATALEN);
} else { # 8.4 to 9.2
	@fields = qw(PG_VERSION_NUM FUNC_MAX_ARGS INDEX_MAX_KEYS NAMEDATALEN FLOAT4PASSBYVAL FLOAT8PASSBYVAL);
}
foreach my $integer (@integers) {
	my $field = shift @fields;
	print "$field: $integer\n";
}
