Chciałbym użyć opcji ld's --build-id w celu dodania informacji o kompilacji do mojego pliku binarnego. Jednak nie jestem pewien, jak udostępnić te informacje w programie. Załóżmy, że chcę napisać program, który zapisuje ślad za każdym razem, gdy wystąpi wyjątek, i skrypt, który analizuje te informacje. Skrypt odczytuje tabelę symboli programu i wyszukuje adresy wydrukowane w backtrace (jestem zmuszony użyć takiego skryptu, ponieważ program jest statycznie połączony i backtrace_symbols nie działa). Aby skrypt działał poprawnie, muszę dopasować wersję kompilacji programu do wersji build programu, który utworzył ślad. Jak mogę wydrukować wersję kompilacji programu (znajdującą się w sekcji .note.gnu.build-id elf) z samego programu?Czy program może czytać własną sekcję elfa?
Odpowiedz
Jak mogę wydrukować wersję kompilacji programu (znajdującą się w sekcji .note.gnu.build-id elf) z samego programu?
Trzeba czytać
ElfW(Ehdr)
(na początku pliku), aby znaleźć nagłówki programu w binarnym (.e_phoff
i.e_phnum
powie Ci, gdzie nagłówki programowe są i ilu z nich, aby przeczytać) .Następnie czytasz nagłówki programów, dopóki nie znajdziesz odcinka
PT_NOTE
twojego programu. Ten segment powie Ci przesunięcie do początku wszystkich notatek w twoim pliku binarnym.Następnie należy odczytać
ElfW(Nhdr)
i pominąć resztę Note (całkowity rozmiar banknotu jestsizeof(Nhdr) + .n_namesz + .n_descsz
, prawidłowo ustawione), aż znajdziesz notatkę z.n_type == NT_GNU_BUILD_ID
.Po znalezieniu notatki
NT_GNU_BUILD_ID
pomiń jej numer.n_namesz
i przeczytaj bajty.n_descsz
, aby odczytać rzeczywisty identyfikator kompilacji.
Można sprawdzić, czy czytasz odpowiednie dane, porównując to, co czytasz z wyjściem readelf -n a.out
.
P.S.
Jeśli zamierzasz przejść przez kłopotów zdekodować gromadzeniu id jak wyżej, a jeśli plik wykonywalny nie jest usuwany, może być lepiej, aby po prostu zdekodować i druk symbol nazwy zamiast (tj replikuj co robi backtrace_symbols
) - jest to łatwiejsze niż dekodowanie notatek ELF, ponieważ tablica symboli zawiera wpisy o ustalonej wielkości.
Zasadniczo jest to kod, który napisałem na podstawie odpowiedzi udzielonej na moje pytanie. Aby skompilować kod, musiałem wprowadzić pewne zmiany i mam nadzieję, że będzie działać na tylu typach platform, jak to tylko możliwe. Został jednak przetestowany tylko na jednej maszynie. Jednym z założeń, którego używałem, było to, że program został zbudowany na komputerze, który go uruchamia, więc nie ma sensu sprawdzać zgodności endianów między programem a maszyną.
[email protected]:~/$ uname -s -r -m -o
Linux 3.2.0-45-generic x86_64 GNU/Linux
[email protected]:~/$ g++ test.cpp -o test
[email protected]:~/$ readelf -n test | grep Build
Build ID: dc5c4682e0282e2bd8bc2d3b61cfe35826aa34fc
[email protected]:~/$ ./test
Build ID: dc5c4682e0282e2bd8bc2d3b61cfe35826aa34fc
#include <elf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#if __x86_64__
# define ElfW(type) Elf64_##type
#else
# define ElfW(type) Elf32_##type
#endif
/*
detecting build id of a program from its note section
http://stackoverflow.com/questions/17637745/can-a-program-read-its-own-elf-section
http://www.scs.stanford.edu/histar/src/pkg/uclibc/utils/readelf.c
http://www.sco.com/developers/gabi/2000-07-17/ch5.pheader.html#note_section
*/
int main (int argc, char* argv[])
{
char *thefilename = argv[0];
FILE *thefile;
struct stat statbuf;
ElfW(Ehdr) *ehdr = 0;
ElfW(Phdr) *phdr = 0;
ElfW(Nhdr) *nhdr = 0;
if (!(thefile = fopen(thefilename, "r"))) {
perror(thefilename);
exit(EXIT_FAILURE);
}
if (fstat(fileno(thefile), &statbuf) < 0) {
perror(thefilename);
exit(EXIT_FAILURE);
}
ehdr = (ElfW(Ehdr) *)mmap(0, statbuf.st_size,
PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(thefile), 0);
phdr = (ElfW(Phdr) *)(ehdr->e_phoff + (size_t)ehdr);
while (phdr->p_type != PT_NOTE)
{
++phdr;
}
nhdr = (ElfW(Nhdr) *)(phdr->p_offset + (size_t)ehdr);
while (nhdr->n_type != NT_GNU_BUILD_ID)
{
nhdr = (ElfW(Nhdr) *)((size_t)nhdr + sizeof(ElfW(Nhdr)) + nhdr->n_namesz + nhdr->n_descsz);
}
unsigned char * build_id = (unsigned char *)malloc(nhdr->n_descsz);
memcpy(build_id, (void *)((size_t)nhdr + sizeof(ElfW(Nhdr)) + nhdr->n_namesz), nhdr->n_descsz);
printf(" Build ID: ");
for (int i = 0 ; i < nhdr->n_descsz ; ++i)
{
printf("%02x",build_id[i]);
}
free(build_id);
printf("\n");
return 0;
}
- 1. określić sekcję program w kodzie C (GCC)
- 2. Czy metoda cfc ColdFusion może określić własną nazwę?
- 3. Czy można zagnieździć sekcję krytyczną?
- 4. W jaki sposób moduł perla może znaleźć własną ścieżkę?
- 5. WebPACK nie może czytać spoza katalogu
- 6. Gdzie jest zmienna globalna w pliku elfa
- 7. Czy mogę odtworzyć inżynierię własną bibliotekę dll?
- 8. Czy mój program Visual C++ może odsłuchiwać własne wyniki debugowania?
- 9. W jaki sposób mój program może powiedzieć, czy działa Delphi?
- 10. Czy program Java może znać swój bieżący katalog?
- 11. Czy program Visual Studio 2010 może monitować przed przebudowaniem?
- 12. Czy program Resharper może mieć specjalne ustawienia wyliczania?
- 13. Czy program SymPy może renderować LaTeX do użycia w GUI?
- 14. Czy MatchCollection może zawiesić program podczas próby iteracji?
- 15. Czy program Visual Studio może wygenerować plik konfiguracyjny?
- 16. Czy program C może kontynuować wykonywanie po odebraniu sygnału?
- 17. Czy program JavaFX FileChooser może "zapamiętać" ostatnio otwierany katalog?
- 18. Usuwanie wpisu z sekcji DYNAMIC pliku elfa
- 19. Narzędzie do prostej modyfikacji pliku elfa?
- 20. GNU ld usuwa sekcję
- 21. zaimplementować własną sizeof
- 22. NSFetchedResultsController poprzedzający wiersz lub sekcję
- 23. Czy program Visual Studio może ponownie uruchomić program IIS Express w nowej sesji debugowania?
- 24. Czy czytać zmienną Pythona w skrypcie powłoki?
- 25. Ile sposobów może zakończyć się program java?
- 26. Utwórz własną niestandardową przeglądarkę
- 27. Czy program pakujący ASP.net automatycznie minimalizuje pliki?
- 28. Jak znaleźć odsunięcie tabeli ciągów nagłówka sekcji pliku elfa?
- 29. Dlaczego ten program nie może przechwycić wyjątku?
- 30. Jak czytać znaczniki plików MP3
dzięki za odpowiedzi. – e271p314