Binamıma yapı bilgisi eklemek için ld's --build-id seçeneğini kullanmak istiyorum. Ancak, bu bilgiyi programın içinde nasıl hazırlayacağımı bilmiyorum. Bir istisna her gerçekleştiğinde bir backtrace yazan bir program yazmak istiyorum ve bu bilgiyi ayrıştıran bir betik yazalım. Komut, programın sembol tablosunu okur ve backtrace'de yazdırılan adresleri arar (program statik olarak bağlandığından ve backtrace_symbols çalışmadığı için böyle bir betik kullanmaya zorlanıyorum). Komut dosyasının düzgün çalışması için, programın sürümünün, backtrace'i oluşturan programın derleme sürümüyle eşleşmesi gerekir. Programın oluşturulmuş sürümünü (.note.gnu.build-id elf bölümünde bulunan) programın kendisinden nasıl yazdırabilirim?bir program kendi elf bölümünü okuyabilir mi?
cevap
Programdan kendisinden (.note.gnu.build kimliği elf bölümünde bulunan) Programın inşa sürümünü yazdırmak nasıl?
Okumak gerek
ElfW(Ehdr)
program başlıkları bulmak için (dosyasının başında), kayıt ikili (.e_phoff
ve.e_phnum
programı başlıkları nerede söyleyecektir ve bunların nasıl okunacağını çok) .Programınızın
PT_NOTE
bölümünü bulana kadar program başlıklarını okuyun. Bu bölüm size ikili dosyanızdaki tüm notaların başlangıcına denk geleceğini söyleyecektir.Daha sonra
.n_type == NT_GNU_BUILD_ID
içeren bir not buluncaya kadarElfW(Nhdr)
okuyup notu geri kalanını (not toplam boyutu, düzgün hizalanmışsizeof(Nhdr) + .n_namesz + .n_descsz
olan) atlamak gerekir.Not
NT_GNU_BUILD_ID
notunu bulduktan sonra,.n_namesz
numarasını atlayın ve gerçek yapı kimliğini okumak için.n_descsz
bayt değerini okuyun.
Sen sen readelf -n a.out
çıkışı ile okuduklarım karşılaştırarak doğru verileri okuduğunuz olduğunu doğrulayabilir.
P.S. çalıştırılabilir elimden değilse sadece deşifre ve baskı sembolü isimleri yerine etmek için
Eğer yukarıdaki gibi birikmesi id çözmek için zahmete girsin yapacaksanızve , bu (yani daha iyi olabilir backtrace_symbols
'un ne yaptığını yineleyin) - sembol tablosunun sabit boyutlu girişler içerdiğinden, ELF notlarının kodunu çözmekten daha kolaydır.
Temel olarak, bu, soruma verilen cevaba dayanarak yazdığım kod. Kodu derlemek için bazı değişiklikler yapmak zorunda kaldım ve umarım mümkün olduğu kadar çok platform türü için çalışır. Ancak, sadece bir yapı makinesinde test edildi. Kullandığım varsayımlardan biri, programın makine üzerinde çalıştığı ve program ile makine arasındaki endianite uyumluluğunu kontrol etmenin bir anlamı olmadığıydı. cevaplanması için
[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;
}
teşekkürler. – e271p314