Tôi đã gặp sự cố tương tự: muốn kiểm tra một tòa nhà syscall đến ioctl
được tạo bởi vde_switch
(tạo giao diện mạng ảo TUN/TAP) để biết tôi đang làm gì sai trong mã của mình để làm điều tương tự như vde_switch
, nhưng lập trình)
Bằng cách chạy:.
sudo strace vde_switch -tap tap0
tôi đã có thể biết, như Terry Greentail, rằng syscall đang được thực hiện là ioctl(5, TUNSETIFF, 0x7fffa99404e0)
và con trỏ sẽ là một tài liệu tham khảo đến một cấu trúc loại struct ifreq
. Trong mã của tôi, tôi đã có một cái gì đó như ioctl(tapfd, TUNSETIFF, &ifr_dev)
. Ban đầu tôi cố gắng làm cho gdb dừng trên syscall, thiết lập: catch syscall ioctl
(Tôi đã chạy gdb là gdb --args vde_switch -tap tap0
), nhưng bất cứ khi nào bắt được hit, gdb không cho thấy thông tin về các tham số của ioctl
. Sau khi vật lộn với điều này trong một thời gian, tôi quyết định chạy strace bên trong gdb, như:
gdb --args strace vde_witch -tap -tap0
Mặc dù không có điểm dừng đã làm việc theo cách này, đầu ra cho thấy trong đó mô tả tập tin đã được sử dụng:
open("/dev/net/tun", O_RDWR) = 9
ioctl(9, TUNSETIFF, 0x7fffffffe350) = 0
Vì vậy, tôi đã cố gắng một thời điểm khác với: gdb --args strace vde_witch -tap -tap0
và thiết lập một breakpoint có điều kiện:
b ioctl if $rdi==9
Các quy ước gọi (tôi đang trên một AMD64) sử dụng RDI
f hoặc các tham số đầu tiên, RSI
cho phần thứ hai và RDX
cho thứ ba (xem System V AMD64 ABI.) Cuối cùng, khi breakpoint được hit, tôi đã có thể kiểm tra việc ifreq
cấu trúc:
Breakpoint 6, ioctl() at ../sysdeps/unix/syscall-template.S:81
81 ../sysdeps/unix/syscall-template.S: File or directory not found.
(gdb) p (struct ifreq) *$rdx
$5 = {ifr_ifrn = {ifrn_name = "tap0", '\000' <repete 11 vezes>}, ifr_ifru = {ifru_addr = {sa_family = 4098, sa_data = '\000' <repete 13 vezes>}, ifru_dstaddr = {sa_family = 4098, sa_data = '\000' <repete 13 vezes>}, ifru_broadaddr = {sa_family = 4098, sa_data = '\000' <repete 13 vezes>}, ifru_netmask = {sa_family = 4098, sa_data = '\000' <repete 13 vezes>}, ifru_hwaddr = {sa_family = 4098, sa_data = '\000' <repete 13 vezes>}, ifru_flags = 4098, ifru_ivalue = 4098, ifru_mtu = 4098, ifru_map = {mem_start = 4098, mem_end = 0, base_addr = 0, irq = 0 '\000', dma = 0 '\000', port = 0 '\000'}, ifru_slave = "\002\020", '\000' <repete 13 vezes>, ifru_newname = "\002\020", '\000' <repete 13 vezes>, ifru_data = 0x1002 <Address 0x1002 out of bounds>}}
Liệu nó cung cấp cho bạn địa chỉ của chỉ dẫn? Nếu vậy nó thực sự đơn giản trong GDB để thêm một điểm break và sau đó nhìn vào bộ nhớ ... Làm thế nào bạn muốn xác định cấu trúc thực tế tôi không chắc chắn như vậy. – Matt
Tôi có nghĩa là nếu tôi sẽ viết nó trong chương trình của tôi, nó sẽ trông như thế này: 'ioctl (dev_node, IOCTL_CODE, & ioctl_struct)', trong đó đối số thứ ba là một cấu trúc kiểu Ioctl_Buf_Struct. Khi strace được sử dụng cho chương trình nhị phân như chúng ta thấy trong ví dụ trên, tôi sẽ tò mò muốn biết những gì đằng sau địa chỉ 0x8f0eb18: cấu trúc được gửi ở đó là gì, hoặc ít nhất giá trị của nó là gì. Gdb có thể trợ giúp ở đây không? –
cũng ... Nếu bạn chạy chương trình, hãy dừng lại ngay trước lệnh đó, sau đó bạn có thể tìm các giá trị bằng cách dereferencing con trỏ. Sử dụng strace để tìm tất cả các cuộc gọi malloc, cho đến khi bạn tìm thấy một trong đó trả về con trỏ đó. Điều đó sẽ cho bạn biết kích thước của cấu trúc.Sau đó bạn có thể nhìn vào bộ nhớ, với kích thước đã biết và tái tạo cấu trúc ở dạng nhị phân của nó. Bạn có thể không bao giờ biết * cấu trúc là gì, nhưng bạn có thể tìm thấy giá trị. – Matt