Table extractor tool

Benjamin Larsson <[email protected]> Tue, 20 Dec 2005 19:55:44 +0000
Newsgroups gmane.comp.video.xine.codec.devel
Message-ID <[email protected]>
Hi, I have meant to release this tool for some time now but I've been
lazy. Anyway it's called elftractor and can extract tables from elf
executables with the info from the symbol tables. To use it just run it
with ./elftractor.pl --analyse "file". A default database file is then
created. This file is a regular textfile that can be edited. After the
database has been edited, just run ./elftractor.pl --generate-tables
"file" to extract the tables from the file. Currently only 1 and 2
dimensional tables can be generated correctly. I've attached one example
db for the indeo4 decoder elf. This file can be found in the all codec
package from mplayerhq.

MvH
Benjamin Larsson

-- 
"incorrect information" is an oxymoron. Information is, by definition, factual, correct.
elftractor.pl (text/plain, 11.7 KB)
#!/usr/bin/perl

#Argument parser

if (@ARGV){
    if ($ARGV[0] eq "--analyse"){
        $demange=0;
        analyse();
    }
    if ($ARGV[0] eq "--analyse-demangle"){
        $demangle=1;
        analyse();
    }
    if ($ARGV[0] eq "--generate-skeleton"){
        generate_skeleton();
    }
    if ($ARGV[0] eq "--generate-tables"){
        generate_tables();
    }
    if ($ARGV[0] eq "--generate-all"){
        generate_tables();
        generate_skeleton();
    }

} else{
    print "Usage:\n";
    print "./elftractor.pl [command] binary\n";
    print "--analyse - analyses and creates a database\n";
    print "--analyse-demangle - analyse and demangle of function names\n";
    print "--generate-skeleton - generates code skeleton from database\n";
    print "--generate-tables - generates datatables from database\n";
    print "--generate-all - generates tables and function skeleton\n";
    exit;
}
exit;

sub generate_skeleton
{
    #parse the input file
    $FILE1 = $ARGV[1];
    $ts = 0;
    $tn = 0;
    open(DATAFILE, "<$FILE1.db") or die "File doesn't exist\n";
    while ($rad = <DATAFILE>)
    {
        if ($rad eq "[functions end]\n") {$ts = 0;}
        if ($ts == 1) {
            chomp($rad);
            @tmpsplit=split /;/,$rad;
            $functions_name[$tn] = $tmpsplit[0];
            $functions_address[$tn] = $tmpsplit[1];
            $functions_size[$tn] = $tmpsplit[2];
            $functions_argument[$tn] = $tmpsplit[3];
            $tn++;
        }
        if ($rad eq "[functions begin]\n") {$ts = 1;}
    }
    #open outputfile
    open(OUTFILE, ">$FILE1.c") or die "can't open $FILE1.c: $!";

    print OUTFILE "#include \"$FILE1.h\"\n\n\n\n";
    for ($i=0 ; $i<$tn; $i++){
        print OUTFILE "static void $functions_name[$i]$functions_argument[$i]\n{\n}\n\n";
    }
    close(OUTFILE);
    print "$tn functions written to $FILE1.c\n";
}

sub generate_tables
{
    #parse the input file
    $FILE1 = $ARGV[1];
    $ts = 0;
    $tn = 0;
    open(DATAFILE, "<$FILE1.db") or die "File doesn't exist\n";
    while ($rad = <DATAFILE>)
    {
        if ($rad eq "[tables end]\n") {$ts = 0;}
        if ($ts == 1) {
            chomp($rad);
            @tmpsplit=split /;/,$rad;
            $tabler_name[$tn] = $tmpsplit[0];
            $tabler_address[$tn] = $tmpsplit[1];
            $tabler_size[$tn] = $tmpsplit[2];
            $tabler_type[$tn] = $tmpsplit[3];
            $tabler_cols[$tn] = $tmpsplit[4];
            $tabler_readonly[$tn] = $tmpsplit[5];
            $tabler_dimensions[$tn] = $tmpsplit[6];
            for ($i=0 ; $i<$tabler_dimensions[$tn] ; $i++){
                $tabler_dsize[$tn][$i] = $tmpsplit[7+$i];
            }
            $tn++;
            #print "$tmpsplit[0] - $tmpsplit[5]\n";
        }
        if ($rad eq "[tables begin]\n") {$ts = 1;}
    }
    close(DATAFILE);

    #get .data and .rodata offsets
    open(DATAFILE, "<$FILE1.db") or die "File doesn't exist\n";
    $ts = 0;
    while ($rad = <DATAFILE>)
    {
        if ($rad eq "[offset end]\n") {$ts = 0;}
        if ($ts == 2) {
            @tmpsplit=split /;/,$rad;
            $doffset = $tmpsplit[1];
            $ts = 3;
        }
        if ($ts == 1) {
            @tmpsplit=split /;/,$rad;
            $drooffset = $tmpsplit[1];
            $ts = 2;
        }
        if ($rad eq "[offset begin]\n") {$ts = 1;}
    }
    close(DATAFILE);

    #open outputfile
    open(OUTFILE, ">$FILE1.h") or die "can't open $FILE1.h: $!";

    #print "$drooffset $doffset\n";
    for ($i=0 ; $i<$tn; $i++){
        #type to unpacktype
        $unpacktype="";
        $delim=0;
        $floatfix=0;
        if ($tabler_type[$i] eq "int8_t") {$unpacktype="c";}
        if ($tabler_type[$i] eq "uint8_t") {$unpacktype="C";}
        if ($tabler_type[$i] eq "int16_t") {$unpacktype="s";}
        if ($tabler_type[$i] eq "uint16_t") {$unpacktype="S";}
        if ($tabler_type[$i] eq "int32_t") {$unpacktype="i";}
        if ($tabler_type[$i] eq "uint32_t") {$unpacktype="I";}
        if ($tabler_type[$i] eq "int64_t") {$unpacktype="l";}
        if ($tabler_type[$i] eq "uint64_t") {$unpacktype="L";}
        if ($tabler_type[$i] eq "float") {$unpacktype="f";$floatfix = 1;}
        if ($tabler_type[$i] eq "double") {$unpacktype="d";$floatfix = 1;}
        if ($tabler_type[$i] eq "hex8_t") {$unpacktype="h";$delim=2;}
        if ($tabler_type[$i] eq "hex16_t") {$unpacktype="h";$delim=4;}
        if ($tabler_type[$i] eq "hex32_t") {$unpacktype="h";$delim=8;}
        if ($tabler_type[$i] eq "hex64_t") {$unpacktype="h";$delim=16;}

        #get right offset
        if ($tabler_readonly[$i]==1){
            $ofs = $drooffset;
        } else {
            $ofs = $doffset;
        }

        #calculate the seek address
        $seekaddress = hex($tabler_address[$i]) - $ofs;

        #access the file for data
        open(BINFILE, $FILE1) or die "can't open $FILE1: $!";
        seek(BINFILE, $seekaddress, 0) or die "seek:$!";
        read(BINFILE, $BUFFER, $tabler_size[$i]);
        close(BINFILE);

        @fields = unpack("$unpacktype*",$BUFFER);

        #divide the hex numbers
        if ($delim > 0) {
            $hexdata = $fields[0];
            $fptr = 0;
            for ($nptr=0;$nptr < (length($hexdata));$nptr = $nptr + $delim) {
                $fields[$fptr] = "\"0x".substr("$hexdata", $nptr, $delim)."\"";
                $fptr++;
            }
            #rename the type hex to uint
            $tabler_type[$i] =~ s/hex/uint/;
        }



        #numbers of elements
        $numelements = $#fields+1;

        #const or not
        $const = "";
        if ($tabler_readonly[$i]==1){
            $const = "const ";
        }

        $tsize = 1;
        $dimstring = "";
        #evaluate the dimensions
        for ($j=0; $j<$tabler_dimensions[$i]-1; $j++){
            $tsize = $tsize*$tabler_dsize[$i][$j];
            $dimstring = $dimstring."\[$tabler_dsize[$i][$j]\]";
        }
        $numelements_last = $numelements/$tsize;
        $dimstring = $dimstring."\[$numelements_last\]";

        print OUTFILE "static $const$tabler_type[$i] $tabler_name[$i]$dimstring = {\n    ";
        if ($tabler_dimensions[$tn]>1) {
            print OUTFILE "{ ";
        }

        $colcounter = 0;
        $elcounter = 0;
        foreach $rad (@fields) {
            for ($j=0; $j<$tabler_dimensions[$i]-1; $j++){
                if (($elcounter%$numelements_last == 0)) {
                    $colcounter = 0;
                    if ($elcounter == 0){
                        print OUTFILE "{";
                    } else {
                        print OUTFILE "    {";
                    }
                }
            }
            $elcounter++;
            if ($colcounter == $tabler_cols[$i]) {
                print OUTFILE "\n    ";
                $colcounter = 0;
            }
            #fix missing .0 for floats
            if ($floatfix==1) {
                if ($rad=~ m/\./) {
                } else {
                    $rad = "$rad.0";
                }
            }
            print OUTFILE "$rad,";
            $colcounter ++;
            for ($j=0; $j<$tabler_dimensions[$i]-1; $j++){
                if ($elcounter%$numelements_last == 0){
                    $colcounter = 0;
                    print OUTFILE "},\n";
                }
            }
        }
        if ($tabler_dimensions[$i]>1) {
            print OUTFILE "};\n\n";
        } else {
            print OUTFILE "\n};\n\n";
        }
        #print "$tabler_name[$i] $tabler_address[$i] $tabler_size[$i] $seekaddress\n @fields\n";
    }
    print "$tn tables written to $FILE1.h.\n";
    close(OUTFILE);
}


sub analyse
{
    my $k;
    $tn = 0;
    $tron = 0;
    $fnum = 0;
    $FILE1 = $ARGV[1];
    print "$FILE1\n";
    # get SYMBOL TABLE
    if ($demangle == 1) {
        @symtable = `objdump -C -tT $FILE1`;
    } else {
        @symtable = `objdump -tT $FILE1`;
    }
    foreach $rad (@symtable) {
        #parse readwrite tables
        if ($rad =~ m/\.data/) {
	    #print $rad;
	    $address = (substr $`,0,8);
	    $rad = $';
	    while (($rad =~ s/  / /g) || ($rad =~ s/\t//g)){}
	    #print $rad;
            $size = (substr $rad,0,8);
            $name = (substr $rad,9);
            chomp($name);
            $size = hex($size);
            if ($size > 0) {
                #print "$name $size $address\n";
                $tabler_name[$tn] = $name;
                $tabler_size[$tn] = $size;
                $tabler_address[$tn] = $address;
                $tn++;
            }
        }
        #parse readonly tables
        if ($rad =~ m/\.rodata/) {
            #print $rad;
            $address = (substr $`,0,8);
            $rad = $';
            while (($rad =~ s/  / /g) || ($rad =~ s/\t//g)){}
            #print $rad;
            $size = (substr $rad,0,8);
            $name = (substr $rad,9);
            chomp($name);
            $size = hex($size);
            #print "$name $size $address\n";
            if ($size > 0) {
                #print "$name $size $address\n";
                $tablero_name[$tron] = $name;
                $tablero_size[$tron] = $size;
                $tablero_address[$tron] = $address;
                $tron++;
            }
        }
        #parse functions
        if ($rad =~ m/\.text/) {
        $address = (substr $`,0,8);
        #print $rad;
        $rad = $';
        while (($rad =~ s/  / /g) || ($rad =~ s/\t//g)){}
            $argument="(n/a)";
            $size = (substr $rad,0,8);
            $name = (substr $rad,9);
            chomp($name);
            if ($demangle == 1) {
                if($name =~ m/\(/) {
                    $argument = "(".$';
                    $name = $`;
                }
            }
            $size = hex($size);
            #print "$name $argument $size\n";
            if ($size > 0) {
                #print "$name $argument $size\n";
                $functions_name[$fnum] = $name;
                $functions_address[$fnum] = $address;
                $functions_size[$fnum] = $size;
                $functions_argument[$fnum] = $argument;
                $fnum++;
            }
        }
    }

    #get .data and .rodata offsets
    @offsets = `readelf -S $FILE1`;
    foreach $rad (@offsets) {
        if ($rad=~ m/ \.data/) {
            $dataaddress = (substr $rad,41,8);
            $dataoffset = (substr $rad,50,6);
            $doffset = hex($dataaddress) - hex($dataoffset);
        }
        if ($rad=~ m/ \.rodata/) {
            $rodataaddress = (substr $rad,41,8);
            $rodataoffset = (substr $rad,50,6);
            $drooffset = hex($rodataaddress) - hex($rodataoffset);
        }
    }

    #write the database
    open(DB, ">".$FILE1.".db") or die "File doesn't exist\n";
    print DB "# offsets for data tables in non hex format(decimal), the order is fixed\n";
    print DB "[offset begin]\n";
    print DB "ro_offset;$drooffset;\n";
    print DB "rw_offset;$doffset;\n";
    print DB "[offset end]\n";

    print DB "# name(string), address(hex), size(int), type(string), cols(int), readonly(bolean), dimensions(int), dim 1 to n-1 size...(int)\n";
    print DB "[tables begin]\n";
    #write read/write tables
    for ($i=0 ; $i<$tn; $i++){
        print DB "$tabler_name[$i];$tabler_address[$i];$tabler_size[$i];hex8_t;8;0;1;\n";
    }
    #write readonly tables
    for ($i=0 ; $i<$tron; $i++){
        print DB "$tablero_name[$i];$tablero_address[$i];$tablero_size[$i];hex8_t;8;1;1;\n";
    }
    print DB "[tables end]\n";
    #write functions
    print DB "# name(string); address(hex); size(int); arguments(string)\n";
    print DB "[functions begin]\n";
    for ($i=0 ; $i<$fnum; $i++){
        print DB "$functions_name[$i];$functions_address[$i];$functions_size[$i];$functions_argument[$i];\n";
    }
    print DB "[functions end]\n";
    close DB;
    print "Found $tn rw tables, $tron readonly tables and $fnum functions.\n";
    print "Database $FILE1.db written.\n";
}
vid_iv41.xa.db (text/plain, 6 KB)
# offsets for data tables in non hex format(decimal), the order is fixed
[offset begin]
ro_offset;0;
rw_offset;4096;
[offset end]
# name(string), address(hex), size(int), type(string), cols(int), readonly(bolean), dimensions(int), dim 1 to n-1 size...(int)
[tables begin]
ubScan;0002e4c0;1024;uint8_t;8;0;2;16;
MapTbl3;000283e0;1424;uint8_t;8;1;1;
xform_to_scan;0002a860;18;hex8_t;8;1;1;
ClampDitherY_0e;0001d800;256;uint8_t;8;1;1;
MapTbl4;00028980;1424;hex8_t;8;1;1;
CP_ClampDitherY_06;00022740;256;hex8_t;8;1;1;
au16ScaleTables;0002be80;5632;uint16_t;8;1;1;
MapTbl7;00029a60;1424;hex8_t;8;1;1;
ComPicSizes;0002a7e8;56;uint32_t;8;1;1;
au16BaseTables;0002a880;5632;hex16_t;8;1;1;
MapTbl0;00027300;1424;hex8_t;8;1;1;
NullFrmHeader;0002a724;12;uint8_t;8;1;1;
ClampDitherY_02;0001d500;256;hex8_t;8;1;1;
MapTbl2;00027e40;1424;hex8_t;8;1;1;
DitherTable;0001e100;16384;hex32_t;8;1;1;
MapTbl6;000294c0;1424;hex8_t;8;1;1;
MapTbl1;000278a0;1424;hex8_t;8;1;1;
MapTbl5;00028f20;1424;hex8_t;8;1;1;
TruncateV;0001d900;1024;uint32_t;8;1;1;
CP_PalTable;00022280;944;uint8_t;8;1;2;16;
CP_ClampDitherY_0e;00022940;256;hex8_t;8;1;1;
FP_PalTable;0001d140;944;uint8_t;8;1;1;
ClampDitherY_0a;0001d700;256;hex8_t;8;1;1;
CP_ClampDitherY_0a;00022840;256;hex8_t;8;1;1;
CP_ClampDitherY_02;00022640;256;hex8_t;8;1;1;
TileSizeTable;0002a7bc;32;uint16_t;8;1;1;
MapTbl8;0002a000;1424;hex8_t;8;1;1;
TruncateU;0001dd00;1024;uint32_t;8;1;1;
ClampDitherY_06;0001d600;256;hex8_t;8;1;1;
CP_DitherTable;00022a40;16384;hex32_t;8;1;1;
[tables end]
# name(string); address(hex); size(int); arguments(string)
[functions begin]
inv_bits;0001ca60;67;(n/a);
PB2Huff;0001c310;319;(n/a);
transform;00011d50;2560;(n/a);
HiveCreateMutex;00005fd0;12;(n/a);
DecMcRectInterp;0001a9c0;890;(n/a);
BitBuff2Mem;0001c180;174;(n/a);
BitBuffOverWrite;0001bec0;225;(n/a);
DecodeDebugGet;00006d50;12;(n/a);
DecodeResetBrightness;00008670;97;(n/a);
DecodeChangeSaturation;00008580;229;(n/a);
DecodeStartup;00006a40;267;(n/a);
DecodeGetCompressedSize;000067b0;90;(n/a);
DecodeResetContrast;000086e0;97;(n/a);
DecodeUseFixedPalette;00006fb0;232;(n/a);
HiveLocalPtrCheck;00005f00;25;(n/a);
CDecompressBegin;00008100;109;(n/a);
DecodeConstantInit;00006070;327;(n/a);
HiveDecTimer;00006020;39;(n/a);
CDecompress;000070a0;1648;(n/a);
HiveGlobalFreePtr;00005f20;41;(n/a);
DecodeGetDefaultPersData;00006d70;12;(n/a);
make_quant;0000f440;193;(n/a);
GetRVMapTbl;0001c830;131;(n/a);
HiveGlobalPtrCheck;00005f50;25;(n/a);
HiveClosestPaletteIndex;00006060;12;(n/a);
DecodeGetSupportedAlgorithms;00006e40;40;(n/a);
BlockPut;00012870;162;(n/a);
C_YVU9toConfigurablePalette;00016e40;13150;(n/a);
What_The;00005bf0;132;(n/a);
MatCopyFast;0000a540;41;(n/a);
bDecodeThisTile;0001a780;87;(n/a);
BitBuffFlush;0001bfb0;52;(n/a);
BitBuffAlloc;0001bd50;72;(n/a);
HiveGlobalUnlockHandle;00005f80;25;(n/a);
DecodeGetPersData;00006e30;12;(n/a);
tounsigned;0001c2c0;27;(n/a);
readTransTileData;0000ad60;704;(n/a);
dec_transform;00010d30;2459;(n/a);
MatSet;00009fd0;88;(n/a);
HiveEndCriticalSection;00006010;12;(n/a);
HiveGlobalAllocHandle;00005e80;66;(n/a);
DecodeFreePrivateData;000066c0;229;(n/a);
GetHuffmanTbls;0001c5a0;76;(n/a);
MatConvU8;0000a0e0;422;(n/a);
DecodeQuery;00006810;310;(n/a);
HiveLocalFreePtr;00005ed0;41;(n/a);
C_YVU9toActivePalette;00015d60;4308;(n/a);
HiveBeginCriticalSection;00005ff0;25;(n/a);
DecPlaneOpen;00008bb0;182;(n/a);
DecodeImageDimInit;00006e70;66;(n/a);
YVU9_to_RGB24;0000f6c0;4996;(n/a);
BitBuffRead;0001bff0;223;(n/a);
SysFreeFunc;0001cb00;45;(n/a);
HiveFreeMutex;00005fe0;12;(n/a);
readTransBandHdr;0000a810;1350;(n/a);
MatAllocFunc;0000a290;94;(n/a);
DecodeSequenceEnd;00006ee0;12;(n/a);
InitYVU2RGBContribs;0000f550;361;(n/a);
BitBuffByteRead;0001c0d0;171;(n/a);
BitBuffWrite;0001b010;295;(n/a);
MatAdd;0000a3c0;100;(n/a);
BitBuffSize;0001c260;64;(n/a);
ModifyContrastOrSaturation;00008830;114;(n/a);
DecBandOpen;0001a630;228;(n/a);
C_YVU9toCLUT8;00012a00;13150;(n/a);
readPicHdrSt;0000d380;3141;(n/a);
DecodeResetSaturation;00008750;59;(n/a);
DecodeChangeContrast;000083e0;259;(n/a);
DecodeUpdateChroma;000087e0;73;(n/a);
HiveGlobalAllocPtr;00005e30;66;(n/a);
HiveGlobalLockHandle;00005f70;16;(n/a);
DecodeSetPersData;00006f00;12;(n/a);
BlockGetDiff;00012750;286;(n/a);
MatCopyFull;0000a490;172;(n/a);
DecodeIsKeyFrame;00006ec0;32;(n/a);
InitRVMapTbl;0001c950;264;(n/a);
MatAddFull;0000a030;167;(n/a);
MatFreeFunc;0000a2f0;26;(n/a);
make_scan;0000f510;57;(n/a);
DecodeShutdown;00006f10;148;(n/a);
NpMBitBuffWrite;0001be70;72;(n/a);
HuffEncBitBuff;0001b600;1126;(n/a);
BitBuffHist;0001b250;937;(n/a);
MatCksum;0000a360;94;(n/a);
BitBuffFree;0001be20;68;(n/a);
DecodeUpdateLuma;00008790;73;(n/a);
DecodeDebugSet;00006d60;12;(n/a);
InitStaticEncodeTables;0001c450;99;(n/a);
GetRVMapTbls;0001c5f0;208;(n/a);
MatCopy;0000a430;86;(n/a);
DecodeSequenceSetup;00006950;234;(n/a);
DecodeFrame;000061c0;1273;(n/a);
SkipPad2DWord;0001ba70;357;(n/a);
DecBand;0001a1a0;1156;(n/a);
CDecompressEnd;00007710;299;(n/a);
ColorConvert;000088b0;756;(n/a);
tosigned;0001c2a0;23;(n/a);
HuffRead;0001bbe0;360;(n/a);
ComputeDynamicClut;00008ec0;3471;(n/a);
InitQuantTables;0001cb30;410;(n/a);
DecodeSetPaletteConfiguration;00006ef0;12;(n/a);
MatSetFast;00009fa0;44;(n/a);
DecPlaneClose;00008c70;95;(n/a);
DecodeChangeBrightness;000084f0;129;(n/a);
DecodeGetPalette;00006d80;162;(n/a);
DecBandClose;0001a720;88;(n/a);
HiveEncodeProgressFunc;00006050;12;(n/a);
MatSetFull;0000a310;72;(n/a);
PicInfoStAllocPlanes;0000f320;277;(n/a);
HiveLocalAllocPtr;00005de0;66;(n/a);
SysMallocFunc;0001cab0;71;(n/a);
HiveGlobalFreeHandle;00005fa0;41;(n/a);
InitStaticDecodeTables;0001c4c0;223;(n/a);
DecMcRectInterpAvg;0001ad40;706;(n/a);
PicInfoStClose;0000a5a0;624;(n/a);
HaarBands;00009e40;344;(n/a);
GetDecHuffmanTable;0001c6c0;360;(n/a);
HaarInv;00009c50;489;(n/a);
PicInfoStOpen;0000dfd0;4942;(n/a);
DecodeUseThisPalette;00006b50;502;(n/a);
BitBuffSkip2ByteAlign;0001b140;266;(n/a);
BitBuffInit;0001bda0;116;(n/a);
DecPlane;00008cd0;258;(n/a);
SetMatrixRect;0000a570;47;(n/a);
BitBuffByteAlign;0001c230;42;(n/a);
CreateHuffDecTable;0001c8c0;139;(n/a);
BlockGet;00012920;216;(n/a);
[functions end]