Можно ли загрузить файл, полный двоичных данных, в GDB, когда GDB отлаживает основной файл? - PullRequest
3 голосов
/ 26 мая 2010

Я отлаживаю сбой с помощью GDB и файла ядра. Большая часть пространства памяти отображается в процессе. Эта часть памяти не сохраняется в основной файл. У меня есть файл, который содержит все данные в этой памяти.

Я хотел бы найти способ загрузки данных из этого файла в GDB с определенным смещением, чтобы я мог отображать структуры данных в этом адресном пространстве. Это возможно?

Обратите внимание, что я попробовал команду 'restore' в GDB, но она работает только при отладке запущенного процесса.

Возможно, существуют инструменты, которые позволяют файлу ядра добавлять к нему дополнительные данные? Я экспериментирую с objcopy, чтобы посмотреть, смогу ли я дополнить основной файл этими двоичными данными, но я пока не добился успеха.

Ответы [ 3 ]

2 голосов
/ 26 мая 2010

Единственный способ, которым я смог заставить это работать, состоял в том, чтобы изменить сам файл ядра, чтобы иметь дополнительный заголовок / раздел программы, который содержал новые данные.

Теоретически, я считаю, что objcopy должен быть в состоянии сделать это, но после большого тестирования я не смог заставить его работать. Вместо этого я прибег к написанию Perl-скрипта, который модифицировал основной файл.

Вот сценарий для тех из вас, кто застрял в аналогичной ситуации (обратите внимание, что это для основных файлов ELF в арке i386):

#!/usr/bin/perl

my @elfHeader = (
  [ident => 'A16'],
  [e_type => 'v'],
  [e_machine => 'v'],
  [e_version => 'V'],
  [e_entry => 'V'],
  [e_phoff => 'V'],
  [e_shoff => 'V'],
  [e_flags => 'V'],
  [e_ehsize => 'v'],
  [e_phentsize => 'v'],
  [e_phnum => 'v'],
  [e_shentsize => 'v'],
  [e_shnum => 'v'],
  [e_shstrndx => 'v']
);

my @progHeader = (
  [ptype => 'V'],
  [poffset => 'V'],
  [pvaddr => 'V'],
  [ppaddr => 'V'],
  [pfilesz => 'V'],
  [pmemsz => 'V'],
  [pflags => 'V'],
  [palign => 'V'],
);


my ($core, $dataFile, $outFile) = @ARGV;

main();


sub main {

  my @stat = stat($core);
  my $coreSize = $stat[7];

  @stat = stat($dataFile);
  my $dfSize = $stat[7];

  my ($in, $out, $df);
  open($in, "", $outFile) || die("Couldn't open $outFile: $!");

  my $buf;
  my $bytes = sysread($in, $buf, 52);

  my $hdr = unpackStruct(\@elfHeader, $buf);

  # Fix the elf header to have an additional program header
  my $phNum = $hdr->{e_phnum};
  $hdr->{e_phnum}++;

  # Fix the header to point to a new location for the program headers (at the end of the file)
  my $phOff = $hdr->{e_phoff};
  $hdr->{e_phoff} = $coreSize;

  # Read in the full program header table
  my $phTable;
  sysseek($in, $phOff, 0);
  my $readSize = $hdr->{e_phentsize} * $phNum;
  $bytes = sysread($in, $phTable, $readSize);

  # Add an additional entry to the end of the ph table
  my $entry = packStruct(\@progHeader, {ptype => 1, 
                                        poffset => $coreSize + $hdr->{e_phentsize} * $hdr->{e_phnum},
                                        pvaddr => 0x80f95000,
                                        ppaddr => 0,
                                        pfilesz => $dfSize,
                                        pmemsz => $dfSize,
                                        pflags => 7,
                                        palign => 4096});

  $phTable .= $entry;

  # Form the new elf header
  my $elf = packStruct(\@elfHeader, $hdr);

  # Output the new header
  syswrite($out, $elf, length($elf));

  # Copy the full core file after the header
  sysseek($in, 52, 0);
  copyData($in, $out, $coreSize - 52);

  # Output the new program table
  syswrite($out, $phTable, length($phTable));

  # Add the data on the end
  copyData($df, $out, $dfSize);

}


sub copyData {
  my ($in, $out, $numBytes) = @_;

  my $buf;

  while ($numBytes > 0) {
    my $readBytes = sysread($in, $buf, 8192);
    syswrite($out, $buf, $readBytes);
    $numBytes -= $readBytes;
  }

}


sub unpackStruct {
  my ($fields, $data) = @_;

  my $unpack;
  map {$unpack .= $_->[1]} @{$fields};

  my @vals = unpack($unpack, $data);

  my %res;
  foreach my $field (@{$fields}) {
    $res{$field->[0]} = shift(@vals);
  }

  return \%res;

}


sub packStruct {
  my ($fields, $data) = @_;

  my $pack;
  map {$pack .= $_->[1]} @{$fields};

  my @vals;
  foreach my $field (@{$fields}) {
    push(@vals, $data->{$field->[0]})
  }

  my $res = pack($pack, @vals);

  return $res;

}
1 голос
/ 27 мая 2010
0 голосов
/ 26 мая 2010

Насколько я знаю, gdb работает либо с файлом ядра, либо с запущенным процессом.Похоже, вы описываете гибрид: запуск файла ядра.Я не думаю, что это возможно, и документация gdb предполагает, что других вариантов нет.

...