#!/usr/bin/perl

# infos = [file, ref, level, type of declaration, parent (if level>1), name, type (base type or ref dwarf), global, size, address]
# type of declaration : base_type, pointer_type, const_type, structure_type, member, enumeration_type, enumerator


use strict;
use warnings;
use Switch;

my ($argument) = @ARGV;

my $executable = $argument;
open (FILE, $executable) or die "E/S : $!\n";

my @infos;

my $ligne="";
my @champs;

my $file = 0;
my $level=1;
my $ref=0; my $parent_ref=0;
my $type_decl="undef";
my $name="undef";
my $type="undef";
my $size=0;
my $global = 0;
my $address=0;


while ($ligne=<FILE>) {

    @champs = split /\s+/, $ligne;

    if(@champs > 0){

	if ($champs[0] eq "<") { # new declaration

	    # save last information in infos
	    if( $level>0 ) {
		my @entry = ($file, $ref, $level, $type_decl, $parent_ref, $name, $type, $global, $size, $address);
		push @infos, \@entry;
	    }
	   
	    # get new information
	    my @lr = split /></, $champs[1];

	    if($lr[0] > 0){ # level = 0, information about source file
		
		if($level < $lr[0]){
		    $parent_ref = $ref;
		}else{
		    if($lr[0] == 1){
			$parent_ref = 0;
		    }
		}
		
		$level = $lr[0]; # level
		$ref = substr($lr[1], 0, length($lr[1]) -1 ); # dwarf ref		
		$type_decl = $champs[2];

	    }else{ # create new hashtable

		$file++;
		$level=0;
	    }

	}else{

	    switch ($champs[1]){

		case "DW_AT_name" { $name = substr($champs[2], 1, length($champs[2]) - 2); }
		case "DW_AT_type" { $type = substr($champs[2], 1, length($champs[2]) - 2); }
		case "DW_AT_byte_size" { $size = hex($champs[2]); }
		case "DW_AT_external" { $global = 1; }
		case "DW_AT_location" { 
		    if ($global == 1) {
			$address = $champs[3]; 
		    }
		}
		else { $global = 0;}


	    }
	    #print $champs[1]." ".$champs[2]."\n";
	}
    }
} 

# save last information in infos
my @entry = ($file, $ref, $level, $type_decl, $parent_ref, $name, $type, $global, $size, $address);
push @infos, \@entry;

my $i;

printf "%5s %12s %6s %30s %11s %60s %15s %9s %5s %10s\n", "file", "ref", "level", "type of declaration", "parent", "name", "type", "isGlobal", "size", "address";
for($i = 0; $i < @infos; $i++){
    printf "%5s %12s %6s %30s %11s %60s %15s %9s %5s %10s\n", $infos[$i]->[0], $infos[$i]->[1], $infos[$i]->[2], $infos[$i]->[3], $infos[$i]->[4], $infos[$i]->[5], $infos[$i]->[6], $infos[$i]->[7], $infos[$i]->[8], $infos[$i]->[9];
}
