Quando uso strace
para examinar um programa, muitas vezes tenho dificuldade em encontrar onde as syscalls do carregador dinâmico terminam e as syscalls do programa começam.
A saída de strace ./hello
onde hello
um programa simples de hello world C tem 36 linhas. Aqui está uma amostra:
execve("./hello", ["./hello"], 0x7fffb38f4a30 /* 73 vars */) = 0
brk(NULL) = 0x1304000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe6715fe60) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=92340, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 92340, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f78d9fbd000
close(3) = 0
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260|\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
Existe uma maneira de ignorar as syscalls do carregador dinâmico?
Em x86_64 o programa principal inicia logo após
arch_prctl(ARCH_SET_FS)
e algunsmprotect()
s, então você podesed 1,/ARCH_SET_FS/d
nastrace
saída do 's.Um truque que você pode usar em todas as plataformas é
LD_PRELOAD
uma pequena biblioteca que substitui__libc_start_main()
e faz uma chamada de sistema inútil comowrite(-1, "IT_STARTS_HERE", 14)
antes de chamar o arquivo__libc_start_main()
.