#!/usr/bin/perl
-# $OpenBSD: parse_structinfo.pl,v 1.2 2013/10/19 21:02:50 guenther Exp $
+# $OpenBSD: parse_structinfo.pl,v 1.3 2015/04/29 06:06:38 guenther Exp $
#
# Copyright (c) 2009 Miodrag Vallat.
# Copyright (c) 2013 Philip Guenther.
use strict;
use warnings;
use integer;
+use IO::File;
use constant MAX_COLUMN => 72;
my $max_fsize = 0;
my $max_ssize = 0;
+# Variables used in generating the raw, textual output
+my $txt; # IO::File to write to
+my @id2struct; # mapping of objdump's struct ids to @structs idxes
+my @subfield; # list of subfields to dump at the end
+
# count of how many times each literal string appears
my %strings;
my @strings_by_len;
} );
sub new_field
{
- my($name, $offs, $size, $items) = @_;
-
- add_string($name);
- push @fields, {
- name => $name,
- offs => $offs,
- size => $size,
- items => $items // 1,
- struct => scalar(@structs),
- };
- $max_offs = $offs if $offs > $max_offs;
- $max_fsize = $size if $size > $max_fsize;
- push @{ $offs_to_fields{$offs} }, $#fields;
- push @{ $size_to_fields{$size} }, $#fields;
+ my($name, $offs, $size, $items, $id) = @_;
+
+ $items //= 1;
+ add_string($name);
+ push @fields, {
+ name => $name,
+ offs => $offs,
+ size => $size,
+ items => $items,
+ struct => scalar(@structs),
+ };
+ $max_offs = $offs if $offs > $max_offs;
+ $max_fsize = $size if $size > $max_fsize;
+ push @{ $offs_to_fields{$offs} }, $#fields;
+ push @{ $size_to_fields{$size} }, $#fields;
+ if ($txt) {
+ raw($offs, $size * $items, $cur_struct->{name}, $name);
+ if (defined $id) {
+ push @subfield, [ $cur_struct->{name}, $name, $offs, $id ];
+ }
+ }
}
+# Generate textual output for those who are ddb challenged.
+$txt = IO::File->new("db_structinfo.txt", "w")
+ or warn "$0: unable to create db_structinfo.txt: $!";
+sub raw {
+ my($offs, $size, $struct, $member) = @_;
+ $txt->print(join("\t", $offs, $size, $offs+$size, $struct, $member), "\n");
+}
+$txt and $txt->print(join("\t", qw(offset size next struct member)), "\n");
+
+
while (<>) {
chomp; # strip record separator
- if (m!^struct (\w+) \{ /\* size (\d+) !) {
+ if (m!^struct (\w+) \{ /\* size (\d+) id (\d+) !) {
$depth = 1;
$cur_struct = {
name => $1,
size => $2,
fieldmin => scalar(@fields)
};
+ $id2struct[$3] = scalar(@structs);
next
}
# Try and gather the field name.
# The most common case: not a function pointer or array
- if (m!\s\**(\w+);\s/\* bitsize!) {
- new_field($1, $curoffs, $cursize);
+ if (m!\s(\**)(\w+);\s/\* bitsize!) {
+ my $pointer = $1 ne "";
+ my $name = $2;
+ # check for a struct id to match up
+ my($id) = !$pointer && m!/\* id (\d+) \*/.*;!;
+ new_field($name, $curoffs, $cursize, 1, $id);
next
}
}
# Maybe it's an array
- if (m!\s\**([][:\w]+);\s/\* bitsize!) {
- my $name = $1;
+ if (m!\s(\**)([][:\w]+);\s/\* bitsize!) {
+ my $pointer = $1 ne "";
+ my $name = $2;
my $items = 1;
while ($name =~ s/\[(\d+)\]:\w+//) {
$items *= $1;
}
- new_field($name, $curoffs, $cursize / $items, $items);
+ # check for a struct id to match up
+ my($id) = !$pointer && m!/\* id (\d+) \*/.*;!;
+ new_field($name, $curoffs, $cursize / $items, $items, $id);
next
}
}
}
+# Do all the subfield processing
+# XXX Should recurse into subsub...fields?
+foreach my $sf (@subfield) {
+ my($struct_name, $name, $offs, $id) = @$sf;
+ my $s = $id2struct[$id];
+
+ # We don't remember unions. No point in doing so
+ next if !defined $s;
+
+ my $struct = $structs[$s];
+ foreach my $i ($struct->{fieldmin} .. $struct->{fieldmax}) {
+ my $f = $fields[$i];
+ raw($offs + $f->{offs}, $f->{size} * $f->{items},
+ $struct_name, "$name.$f->{name}");
+ }
+}
+
# Pick a type for ddb_field_off: if the offsets and sizes are all less than
# 65536 then we'll use u_short, otherwise u_int.
my $f_type = "u_short";
# Check for overflow and, if so, print some stats
if ($soff > 65535 || @structs > 65535 || @fields > 65535) {
print STDERR <<EOM;
-ERROR: value of range of u_short Time to change types?
+ERROR: value out of range of u_short Time to change types?
max string offset: $soff
max field offset: $max_offs