用于基于缺失符号发现库依赖性的工具

时间:2012-04-20 19:40:02

标签: linker shared-libraries symbols

我正在开展一个有20年历史的项目,其中有一些......有趣的问题,其中包括:有一些带有循环依赖关系的共享对象。

我正在尝试绘制所有库之间的关系,但如果现有的工具能够搜索库列表以查看可以满足缺少的依赖项的内容,那将会非常有用。

作为参考,他们通过执行以下操作来解决问题:

# True list of dependencies:
A: B
B: A
C: A

# Dependencies used in practice:
A:
B: A
C: A B

1 个答案:

答案 0 :(得分:0)

我没有测试过以下代码,因为我刚刚尝试从内存中重写这个代码,但是我之前写的解决这个问题的代码(看起来大概就是这个代码)工作正常:

#!/usr/bin/env perl

using IPC::Open3;

my $queryFile = $ARGV[0];
shift;

my %missingSymbols = getSymbols( "nm -Aau", $queryFile );

my %symtbl;

foreach $lib ( @ARGV ) {
  my %temp = getSymbols( "nm -Aa --defined-only", $lib );

  foreach $key ( keys( %temp ) ) {
    $symtbl{$key} =   (defined($symtbl{$key}) ? "${symtbl{$key}} " : "")
                    . $temp{$key};
  }
}

my %dependencies;
foreach $symbol ( keys( %missingSymbols  ) ) {
  if( defined( $symtbl{$symbol} ) ) {
    foreach $lib ( split( / +/, $symtbl{$symbol} ) ) {
      if( !defined( $dependencies{$lib} ) ) {
        $dependencies{$lib} = 1;
      }
    }
  }
}

if( scalar( keys( %dependencies ) ) > 0 ) {
  print( "$queryFile depends on one or more of the following libs:\n\n" );

  print join( "\n", sort( keys( %dependencies ) ) ) . "\n\n";
} else {
  print( "Unable to resolve dependencies for $queryFile.\n\n" );
}

# Done.

sub getSymbols {
  my $cmd   = shift;
  my $fname = shift;

  checkFileType( $fname );

  open3( IN, OUT, ERR, "$cmd $fname" );

  my %symhash;
  close( IN );
  # If you leave ERR open and nm prints to STDERR, reads from
  # OUT can block.  You could make reads from both handles be
  # non-blocking so you could examine STDERR if needed, but I
  # don't need to.
  close( ERR );

  while( <OUT> ) {
    chomp;
    if( m/^(?:[^:]*:)+[a-zA-Z0-9]*\s*[a-zA-Z] ([^\s]+)$/ ) {
      my $temp = defined( $symhash{$1} ) ? "${symhash{$1}} " : "";
      $symhash{$1} = $temp . $fname;
    }
  }
  close( OUT );

  return %symhash;
}

sub checkFileType {
  my $fname = shift;

  die "$fname does not exist\n" if( ! -e $fname );
  die "Not an ELF or archive file\n" if( `file $fname` !~ m/ELF| ar archive/ );
}