Vorrei utilizzare l'opzione --dot -build di ld per aggiungere informazioni di build al mio binario. Tuttavia, non sono sicuro di come rendere queste informazioni disponibili all'interno del programma. Supponiamo di voler scrivere un programma che scriva un backtrace ogni volta che si verifica un'eccezione e uno script che analizzi queste informazioni. Lo script legge la tabella dei simboli del programma e cerca gli indirizzi stampati nel backtrace (sono obbligato a usare tale script perché il programma è collegato staticamente e backtrace_symbols non funziona). Affinché lo script funzioni correttamente, devo abbinare la versione build del programma con la versione build del programma che ha creato il backtrace. Come posso stampare la versione build del programma (che si trova nella sezione elfo .note.gnu.build-id) dal programma stesso?un programma può leggere la propria sezione elfo?
risposta
Come posso stampare la versione di build del programma (che si trova nella sezione .note.gnu.build-id elf) dal programma stesso?
è necessario leggere il
ElfW(Ehdr)
(all'inizio del file) per trovare le intestazioni di programma nel vostro binario (.e_phoff
e.e_phnum
vi dirà dove le intestazioni del programma sono, e quanti di loro a leggere) .Quindi leggi le intestazioni del programma, finché non trovi il segmento
PT_NOTE
del tuo programma. Quel segmento ti dirà offset rispetto all'inizio di tutte le note nel tuo binario.È quindi necessario leggere il
ElfW(Nhdr)
e saltare il resto della nota (dimensione totale della nota èsizeof(Nhdr) + .n_namesz + .n_descsz
, allineato correttamente), fino a trovare una nota con.n_type == NT_GNU_BUILD_ID
.Una volta trovato
NT_GNU_BUILD_ID
nota, saltare oltre la sua.n_namesz
, e leggere i.n_descsz
byte da leggere l'attuale accumulo di id.
È possibile verificare che si sta leggendo i dati giusti confrontando ciò che si legge con l'uscita di readelf -n a.out
.
P.S.
Se avete intenzione di passare attraverso la briga di decodificare l'accumulo di id come sopra, e se l'eseguibile non è spogliato, può essere meglio per voi di decodificare solo e stampare simbolo nomi invece (vale a dire replicare ciò che fa backtrace_symbols
) - in realtà è più facile da fare rispetto alla decodifica delle note ELF, perché la tabella dei simboli contiene voci di dimensioni fisse.
Fondamentalmente, questo è il codice che ho scritto in base alla risposta data alla mia domanda. Per compilare il codice ho dovuto apportare alcune modifiche e spero che funzionerà per il maggior numero possibile di piattaforme. Tuttavia, è stato testato solo su una macchina di compilazione. Una delle ipotesi che ho usato è che il programma è stato costruito sulla macchina che lo esegue, quindi non ha alcun senso nel controllare la compatibilità endianness tra il programma e la macchina.
[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. Come leggere la sezione system.web da web.config
- 2. Un programma C in esecuzione può accedere alla propria tabella dei simboli?
- 3. Un programma può assegnare direttamente la memoria?
- 4. Baffi: leggere le variabili dalla sezione genitore nella sezione secondaria
- 5. Come leggere la sezione appSettings nel file web.config?
- 6. PowerShell: leggere una sezione di un file in una variabile
- 7. Perché un socket può connettersi() alla propria porta effimera?
- 8. Un programma può calcolare la complessità di un algoritmo?
- 9. Un lavoro Hudson può impostare una descrizione della propria build?
- 10. Perl può sostituire più parole chiave con la propria parola sostitutiva in un colpo solo?
- 11. In un programma Java multithread, ogni thread ha la propria copia di System.out?
- 12. La sezione di configurazione 'customErrors' non può essere letta perché manca una dichiarazione di sezione
- 13. La sezione di configurazione 'connectionStrings' non può essere letta perché manca una dichiarazione di sezione
- 14. Può org.bouncycastle.openssl.PEMReader leggere java.security.PrivateKey?
- 15. Come Elixir può leggere la tabella mnesia del nodo remoto
- 16. x86 ASM Linux - Utilizzando la Sezione .bss
- 17. Cosa può causare perdite nella sezione?
- 18. Come passare e leggere argomenti in un programma lua?
- 19. Un web.config può leggere da un file xml esterno?
- 20. Boost opzioni di programma - ottenere tutte le voci nella sezione
- 21. Plugin per utilizzare la propria app.config
- 22. rispetta la scala durata animatore nella propria animazione
- 23. Come creare la propria estensione di dominio?
- 24. Perché Leiningen mantiene attiva la propria JVM?
- 25. Come restituire la "propria" pagina 404 personalizzata?
- 26. Studio Android - Impossibile specificare la propria minSdkVersion
- 27. Come evitare errori "non può leggere la proprietà di undefined"?
- 28. Un programma semplice può essere responsabile di un BSOD?
- 29. La sezione sincronizzata non blocca!
- 30. Un delegato anonimo può annullare la propria sottoscrizione da un evento una volta che è stato licenziato?
grazie per la risposta. – e271p314