Условная точка останова с использованием strcmp () в GDB в Mac OS X конфликтует с Objective-C runtime

я пытаюсь отладить программу, для которой у меня нет источника на Mac OS X. Я хотел бы знать, какие аргументы он вызывает gettattrlist() with и проверьте возвращаемое значение для двух разных томов (чтобы сравнить и понять, почему он позволит вам использовать один том, а не другой).

я впервые попробовал dtruss, но это бесполезно для getattrlist(); он показывает только указатели, которые передаются в getattrlist() (и даже не знает, сколько аргументов getattrlist() занимает).

  635/0x1dc5:  getattrlist("/Volumes/MyVolume", 0x113FA6380, 0x113FA5FD0)                 = 0 0
  635/0x1dc5:  getattrlist("/Volumes/MyVolume", 0x113FA4F00, 0x113FA4B30)                 = 0 0
  635/0x1dc5:  getattrlist("/Volumes/MyVolume", 0x113FA5870, 0x113FA54C0)                 = 0 0
  635/0x19c6:  getattrlist("/Volumes/MyVolume", 0x7FFF5FBF9140, 0x7FFF5FBF8D70)           = 0 0
  635/0x19c6:  getattrlist("/Volumes/MyVolume", 0x7FFF5FBFA8A0, 0x7FFF5FBFA4F0)           = 0 0

поэтому я попробовал GDB. Я могу установить безусловную точку останова на getattrlist(), и взгляните на его первый аргумент, но он называется слишком часто, чтобы это было полезно.

(gdb) break getattrlist
Breakpoint 1 at 0x7fff8e90b6ac
(gdb) cont
Continuing.

Breakpoint 1, 0x00007fff8e90b6ac in getattrlist ()
(gdb) p (char *)$rdi
 = 0x7fff5fbfd67e "/some/random/path"

Итак, мне, вероятно, нужна условная точка останова, которая сломается только тогда, когда первый аргумент соответствует интересующему меня пути. Это не должно быть слишком сложно, верно?

(gdb) delete
Delete all breakpoints? (y or n) y
(gdb) break getattrlist if ((int)strcmp((char *)$rdi, "/Volumes/My Volume")) == 0
Breakpoint 2 at 0x7fff8e90b6ac
(gdb) cont
Continuing.
Canceling call as the malloc lock is held so it isn't safe to call the runtime.
Issue the command:
    set objc-non-blocking-mode off 
to override this check if you are sure your call doesn't use the malloc libraries or the ObjC runtime.
Error in testing breakpoint condition:
Canceling call as the malloc lock is held so it isn't safe to call the runtime.
Issue the command:
    set objc-non-blocking-mode off 
to override this check if you are sure your call doesn't use the malloc libraries or the ObjC runtime.

Breakpoint 2, 0x00007fff8e90b6ac in getattrlist ()
(gdb) p (char *)$rdi
  = 0x7fff5fbfd67e "/some/other/random/path"

что это? GDB проигнорировал мое условие, потому что подозревает, что оно может позвонить malloc() или среда выполнения ObjC? Хорошо, хорошо,strcmp() не следует называть malloc(); он должен просто сравнивать строки байт за байтом, пока не получит нулевой символ. Поэтому давайте установим эту опцию, сообщение рекомендует переопределить проверку:

(gdb) set objc-non-blocking-mode off
(gdb) cont
Continuing.
Segmentation fault: 11

нет кости. GDB и приложение умирают.

любые предложения о том, как установить условную точку наблюдения в строке из GDB без запуска этой проблемы? Или другие способы захвата аргументов и возврата значения (которые хранятся через выходной аргумент)getattrlist(), это работает лучше, чем dtruss()?

редактировать

попробовал решение Мэтта, но не повезло:

(gdb) set $vol = (char *) malloc((int)strlen("/Volumes/My Volume") + 1)
(gdb) call (int)strcpy($vol, "/Volumes/My Volume")
 = 236411760
(gdb) break getattrlist if ((int)strcmp((char *)$rdi, $vol)) == 0
Breakpoint 1 at 0x7fff8e90b6ac
(gdb) cont
Continuing.
Unsafe to run code: malloc zone lock is held for some zone..
Error in testing breakpoint condition:
Canceling call as the malloc lock is held so it isn't safe to call the runtime.
Issue the command:
    set objc-non-blocking-mode off 
to override this check if you are sure your call doesn't use the malloc libraries or the ObjC runtime.

Breakpoint 1, 0x00007fff8e90b6ac in getattrlist ()
(gdb) p (char *)$rdi
 = 0x11a715838 "/some/other/random/path"

я решил попробовать memcmp() вместо strcmp(); тоже не повезло:

(gdb) break getattrlist if ((int)memcmp((char *)$rdi, $vol, 18)) == 0
Breakpoint 1 at 0x7fff8e90b6ac
(gdb) cont
Continuing.
Unsafe to run code: malloc zone lock is held for some zone..
Error in testing breakpoint condition:
Canceling call as the malloc lock is held so it isn't safe to call the runtime.
Issue the command:
    set objc-non-blocking-mode off 
to override this check if you are sure your call doesn't use the malloc libraries or the ObjC runtime.

Breakpoint 1, 0x00007fff8e90b6ac in getattrlist ()
(gdb)

в этот момент я подумал: "Хорошо, теперь действительно не должно быть ничего, использующего malloc()", поэтому я решил попробовать set objc-non-blocking-mode off снова. Все равно не повезло:

(gdb) set objc-non-blocking-mode off
(gdb) cont
Continuing.
Reading symbols for shared libraries ... done
Reading symbols for shared libraries . done
Reading symbols for shared libraries ....... done
[Switching to process 5456 thread 0x2971b]
[Switching to process 5456 thread 0x29e2f]
warning: Unable to restore previously selected frame.

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000000
[Switching to process 5456 thread 0x29e2f]
0x0000000000000000 in ?? ()
Error in testing breakpoint condition:
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on"
Evaluation of the expression containing the function (memcmp) will be abandoned.

Breakpoint 1, 0x0000000000000000 in ?? ()
Error in testing breakpoint condition:
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on"
Evaluation of the expression containing the function (memcmp) will be abandoned.

Breakpoint 1, 0x0000000000000000 in ?? ()

Мда. В каком я состоянии? внутрь?

(gdb) bt
#0  0x0000000000000000 in ?? ()
#1  0x000000011e6ec070 in ?? ()

Ick. Это выглядит не очень хорошо. Что если я продолжу здесь?

(gdb) cont
Continuing.
[Switching to process 5456 thread 0x2971b]
(gdb) bt
#0  0x00007fff8e90b6ac in getattrlist ()
#1  0x00007fff897c9c4b in GetPathVolFSAttributes ()
#2  0x00007fff897c9459 in PathGetObjectInfo ()
#3  0x00007fff897c9279 in FSPathMakeRefInternal ()
#4  0x00007fff8767b3ee in FSNodePrepareFSRef ()
... snip ...
(gdb) p (char *)$rdi
 = 0x10db1c2b0 "/System/Library/CoreServices/CoreTypes.bundle"

Неа. Все еще не на самом деле ломается на правильный вызов getattrlist(); и все это время умерло из-за разыменования нулевого указателя.

2 ответов


Я считаю, что что-то вроде следующего должно работать.

(gdb) start
...
(gdb) set $x = malloc(strlen("foobar") + 1)
(gdb) call strcpy($x, "foobar")
(gdb) break a_leg if strcmp(foo, $x) == 0

в последних версиях GDB:

(gdb) start
(gdb) break a_leg if $_streq(foo, "foobar")

Я не уверен, в какой версии это было введено, но по крайней мере присутствует в 7.7.1.