in src/main/abi-symbols/abi-dumper.pl [1025:1337]
sub readDWARFInfo($)
{
my $Path = $_[0];
my $Dir = getDirname($Path);
my $Name = getFilename($Path);
if(not checkCmd($EU_READELF)) {
exitStatus("Not_Found", "can't find \"$EU_READELF\" command");
}
if(-s $Path > 1024*1024*100) {
$TooBig = 1;
}
my $AddOpt = "";
if(not defined $AddrToName)
{ # disable search of symbol names
$AddOpt .= " -N";
}
my $Sect = `$EU_READELF_L -S \"$Path\" 2>\"$TMP_DIR/error\"`;
if($Sect!~/\.z?debug_info/)
{ # No DWARF info
if(my $DebugFile = getDebugFile($Path, "gnu_debuglink"))
{
my $DPath = $DebugFile;
my $DName = getFilename($DPath);
printMsg("INFO", "Found link to $DName (gnu_debuglink)");
if(my $DDir = getDirname($Path))
{
$DPath = $DDir."/".$DPath;
}
my $Found = undef;
if(defined $SearchDirDebuginfo)
{
if(-f $SearchDirDebuginfo."/".$DName) {
$Found = $SearchDirDebuginfo."/".$DName;
}
else
{
my @Files = findFiles($SearchDirDebuginfo, "f");
foreach my $F (@Files)
{
if(getFilename($F) eq $DName)
{
$Found = $F;
last;
}
}
}
}
elsif(-f $DPath
and $DPath ne $Path) {
$Found = $DPath;
}
if($Found and $Found ne $Path)
{
printMsg("INFO", "Reading debug-info file $DName linked from gnu_debuglink");
return readDWARFInfo($Found);
}
else
{
printMsg("ERROR", "missed debug-info file $DName linked from gnu_debuglink (try --search-debuginfo=DIR option)");
return 0;
}
}
return 0;
}
elsif(not defined $AltDebugInfoOpt)
{
if($Sect=~/\.gnu_debugaltlink/)
{
if(my $AltObj = getDebugAltLink($Path))
{
$AltDebugInfo = $AltObj;
readAltInfo($AltObj);
}
else {
exitStatus("Error", "can't read gnu_debugaltlink");
}
}
}
if($AltDebugInfo)
{
if($TooBig) {
printMsg("WARNING", "input object is compressed and large, may require a lot of RAM memory to process");
}
}
printMsg("INFO", "Reading debug-info");
my $ExtraPath = undef;
# ELF header
if($ExtraInfo)
{
mkpath($ExtraInfo);
$ExtraPath = $ExtraInfo."/elf-header";
}
if($ExtraPath)
{
system($EU_READELF_L." -h \"$Path\" 2>\"$TMP_DIR/error\" >\"$ExtraPath\"");
open(HEADER, $ExtraPath);
}
else {
open(HEADER, $EU_READELF_L." -h \"$Path\" 2>\"$TMP_DIR/error\" |");
}
my %Header = ();
while(<HEADER>)
{
if(/\A\s*([\w ]+?)\:\s*(.+?)\Z/) {
$Header{$1} = $2;
}
}
close(HEADER);
$SYS_ARCH = $Header{"Machine"};
if($SYS_ARCH=~/80\d86/
or $SYS_ARCH=~/i\d86/)
{ # i386, i586, etc.
$SYS_ARCH = "x86";
}
if($SYS_ARCH=~/amd64/i
or $SYS_ARCH=~/x86\-64/i)
{ # amd64
$SYS_ARCH = "x86_64";
}
initRegs();
# ELF sections
if($ExtraInfo)
{
mkpath($ExtraInfo);
$ExtraPath = $ExtraInfo."/elf-sections";
}
if($ExtraPath)
{
system($EU_READELF_L." -S \"$Path\" 2>\"$TMP_DIR/error\" >\"$ExtraPath\"");
open(HEADER, $ExtraPath);
}
# source info
if($ExtraInfo)
{
mkpath($ExtraInfo);
$ExtraPath = $ExtraInfo."/debug_line";
}
if($ExtraPath)
{
system($EU_READELF_L." $AddOpt --debug-dump=line \"$Path\" 2>\"$TMP_DIR/error\" >\"$ExtraPath\"");
open(SRC, $ExtraPath);
}
else {
open(SRC, $EU_READELF_L." $AddOpt --debug-dump=line \"$Path\" 2>\"$TMP_DIR/error\" |");
}
my $Offset = undef;
my $DirTable_Def = undef;
my %DirTable = ();
while(<SRC>)
{
if(defined $AddDirs)
{
if(/Directory table/i)
{
$DirTable_Def = 1;
%DirTable = ();
next;
}
elsif(/File name table/i)
{
$DirTable_Def = undef;
next;
}
if(defined $DirTable_Def)
{
if(/\A\s*([^\[\]\(\)]+?)\Z/) {
$DirTable{keys(%DirTable)+1} = $1;
}
elsif(/\A\s*(\d+)\s+(.+?)\s+\(\d+\)\Z/)
{ # F34
$DirTable{$1} = $2;
}
}
}
if(index($_, "Table")!=-1
and /Table at offset (\w+)/) {
$Offset = $1;
}
elsif(defined $Offset)
{
my ($Num, $Dir, $File) = ();
if(/(\d+)\s+(\d+)\s+\d+\s+\d+\s+([^ ]+)/) {
($Num, $Dir, $File) = ($1, $2, $3);
}
elsif(/(\d+)\s+([^ ]+)\s+\(\d+\)\,\s+(\d+)/)
{ # F34
($Num, $File, $Dir) = ($1, $2, $3);
}
if($File)
{
chomp($File);
if(defined $AddDirs)
{
if(my $DName = $DirTable{$Dir})
{
$File = $DName."/".$File;
}
}
$SourceFile{$Offset}{$Num} = $File;
}
}
}
close(SRC);
# debug_loc
if($ExtraInfo)
{
mkpath($ExtraInfo);
$ExtraPath = $ExtraInfo."/debug_loc";
}
if($ExtraPath)
{
system($EU_READELF_L." $AddOpt --debug-dump=loc \"$Path\" 2>\"$TMP_DIR/error\" >\"$ExtraPath\"");
open(LOC, $ExtraPath);
}
else {
open(LOC, $EU_READELF_L." $AddOpt --debug-dump=loc \"$Path\" 2>\"$TMP_DIR/error\" |");
}
my $Offset = undef;
while(<LOC>)
{
if(/\A \[\s*(\w+)\].*\[\s*\w+\]\s*(.+)\Z/) {
$DebugLoc{$1} = $2;
}
elsif(/\A \[\s*(\w+)\]/) {
$DebugLoc{$1} = "";
}
elsif(/Offset:\s+(.+?),/)
{ # F34
$Offset = $1;
}
elsif($Offset and /\A\s+\[\s*\w+\]\s*(.+)\Z/)
{ # F34
$DebugLoc{$Offset} = $1;
}
}
close(LOC);
# dwarf
if($ExtraInfo)
{
mkpath($ExtraInfo);
$ExtraPath = $ExtraInfo."/debug_info";
}
my $INFO_fh;
if($Dir)
{ # to find ".dwz" directory (Fedora)
chdir($Dir);
}
if($ExtraPath)
{
system($EU_READELF_L." $AddOpt --debug-dump=info \"$Name\" 2>\"$TMP_DIR/error\" >\"$ExtraPath\"");
open($INFO_fh, $ExtraPath);
}
else {
open($INFO_fh, $EU_READELF_L." $AddOpt --debug-dump=info \"$Name\" 2>\"$TMP_DIR/error\" |");
}
chdir($ORIG_DIR);
readDWARFDump($INFO_fh, 1);
if(my $Err = readFile("$TMP_DIR/error"))
{ # eu-readelf: cannot get next DIE: invalid DWARF
if($Err=~/invalid DWARF/i)
{
if($Loud) {
printMsg("ERROR", $Err);
}
exitStatus("Invalid_DWARF", "invalid DWARF info");
}
}
return 1;
}