strace shows wrong system call

Тема в разделе "WASM.UNIX", создана пользователем Stephenson, 28 ноя 2010.

  1. Stephenson

    Stephenson New Member

    Публикаций:
    0
    Регистрация:
    27 авг 2009
    Сообщения:
    4
    Всем привет

    На 32bit машинах вторым системным вызовом идет fork(), а на 64bit - sys_open().

    Однако этот код запускает fork() на обеих платформах:
    Код (Text):
    1.  #include <stdio.h>
    2.  #include <unistd.h>
    3.  
    4.  int main ()
    5.  {
    6.      printf("--------------------\n");
    7.      __asm__("movl $2, %eax; int $0x80");
    8.      printf("[i am %d]\n", getpid());
    9.  }
    Однако... если мы посмотрим вывод strace, то увидим, что на 64bit действительно запускается open(), а на 32bit fork()

    Debian, x86_64:

    Код (Text):
    1. > gcc asm.c -o asm && ./asm
    2. --------------------
    3. [i am 4628]
    4. [i am 4629]
    5.  
    6. > strace ./asm
    7. execve("./asm", ["./asm"], [/* 41 vars */]) = 0
    8. brk(0)                                  = 0x823000
    9. access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
    10. mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5bbfa2000
    11. access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
    12. open("/etc/ld.so.cache", O_RDONLY)      = 3
    13. fstat(3, {st_mode=S_IFREG|0644, st_size=111792, ...}) = 0
    14. mmap(NULL, 111792, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa5bbf86000
    15. close(3)                                = 0
    16. access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
    17. open("/lib/libc.so.6", O_RDONLY)        = 3
    18. read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\355\1\0\0\0\0\0"..., 832) = 832
    19. fstat(3, {st_mode=S_IFREG|0755, st_size=1432968, ...}) = 0
    20. mmap(NULL, 3541032, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa5bba26000
    21. mprotect(0x7fa5bbb7e000, 2093056, PROT_NONE) = 0
    22. mmap(0x7fa5bbd7d000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x157000) = 0x7fa5bbd7d000
    23. mmap(0x7fa5bbd82000, 18472, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fa5bbd82000
    24. close(3)                                = 0
    25. mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5bbf85000
    26. mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5bbf84000
    27. mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5bbf83000
    28. arch_prctl(ARCH_SET_FS, 0x7fa5bbf84700) = 0
    29. mprotect(0x7fa5bbd7d000, 16384, PROT_READ) = 0
    30. mprotect(0x7fa5bbfa4000, 4096, PROT_READ) = 0
    31. munmap(0x7fa5bbf86000, 111792)          = 0
    32. fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 5), ...}) = 0
    33. mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5bbfa1000
    34. write(1, "--------------------\n", 21--------------------
    35. )  = 21
    36. open(0xffffffff, O_RDONLY|O_SYNC|O_NOFOLLOW|O_CLOEXEC|0xbbf00000) = 4635
    37. getpid()                                = 4634
    38. [i am 4635]
    39. write(1, "[i am 4634]\n", 12)           = ? ERESTARTSYS (To be restarted)
    40. --- SIGCHLD (Child exited) @ 0 (0) ---
    41. write(1, "[i am 4634]\n", 12[i am 4634]
    42. )           = 12
    43. exit_group(12)                          = ?
    CentOS, x86:
    Код (Text):
    1. > gcc asm.c -o asm && ./asm
    2. --------------------
    3. [i am 5163]
    4. [i am 5162]
    5.  
    6. > strace ./asm
    7. execve("./asm", ["./asm"], [/* 22 vars */]) = 0
    8. brk(0)                                  = 0x9a32000
    9. access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
    10. open("/etc/ld.so.cache", O_RDONLY)      = 3
    11. fstat64(3, {st_mode=S_IFREG|0644, st_size=40948, ...}) = 0
    12. mmap2(NULL, 40948, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7ef8000
    13. close(3)                                = 0
    14. open("/lib/libc.so.6", O_RDONLY)        = 3
    15. read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\340_\1\0004\0\0\0"..., 512) = 512
    16. fstat64(3, {st_mode=S_IFREG|0755, st_size=1686224, ...}) = 0
    17. mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7ef7000
    18. mmap2(NULL, 1410500, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x110000
    19. mmap2(0x263000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x152) = 0x263000
    20. mmap2(0x266000, 9668, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x266000
    21. close(3)                                = 0
    22. mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7ef6000
    23. set_thread_area({entry_number:-1 -> 6, base_addr:0xb7ef66c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
    24. mprotect(0x263000, 8192, PROT_READ)     = 0
    25. mprotect(0x79e000, 4096, PROT_READ)     = 0
    26. munmap(0xb7ef8000, 40948)               = 0
    27. fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
    28. mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f01000
    29. write(1, "--------------------\n", 21--------------------
    30. )  = 21
    31. fork()                                  = 5192
    32. [i am 5192]
    33. getpid()                                = 5191
    34. write(1, "[i am 5191]\n", 12[i am 5191]
    35. )           = 12
    36. exit_group(12)
    У меня в openSUSE (x86_64), в файле /usr/src/linux/include/asm-x86/unistd_64.h, стоит второй вызов - sys_open(), так почему же все-таки запускается fork()? Есть у кого какие соображения на данный счет?
     
  2. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    strace наверное, как и ты, не в курсе, что на amd64 сисколл надо вызывать инструкцией syscall. ;)
    strace ведь просто ловит факт сисколла и определяет что именно вызывается по номеру сисколла. И если strace, как и ты, выясняет название сисколла по файлу unistd_64.h, то вот она и получает то же самое, что и ты.
    Делай то же самое, но вместо "int $0x80" пиши "syscall". На amd64, насколько я понимаю, int $0x80 для 32-х битных процессов. AFAIK если собрать ядро без поддержки 32-х битных процессов, то int $0x80 вообще перестанет работать.
     
  3. Stephenson

    Stephenson New Member

    Публикаций:
    0
    Регистрация:
    27 авг 2009
    Сообщения:
    4
    Большое спасибо за ответ!

    Хоть замена "int $0x80" на "syscall" ничего не изменила, все же формулировка, а главное - манера ответа, улыбнули :)
     
  4. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    На debian выполни `uname -a'. И ещё `file my-file' Вместо my-file подставь имя файла, который себя так странно ведёт. Или не `file my-fie', а `ldd my-file'.
    У меня syscall при двойке вызывает именно open.
     
  5. semen

    semen New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2004
    Сообщения:
    334
    Адрес:
    Russia
    Тоже интересна эта тема. Замена на syscall исправляет ситуацию и вызывается open. Но теперь встает другой вопрос - получается strace можно обмануть и вызывать 32 битный номер сискола, когда он думает что это 64битный (и внутри детектирует как 64 битный ABI). Соответственно как можно определить что это был вызов по int 80, а не syscall, чтобы поправить strace?

    UPD: оказывается в strace есть код, чтобы это предотвратить, но он почемуто отключен. Делается путем анализа инструкции. На это надо 2 сискола peekuser+peektext. Остается вопрос, можно ли обойтись одним peekuser?