如何在Linux内核中设置断点

function q1
{
set -x
        modprobe vfio
        modprobe vfio-pci
        echo 15b3 101a >/sys/bus/pci/drivers/vfio-pci/new_id
        ls /dev/vfio

        qemu-system-x86_64 --enable-kvm \
                -S                      \
                -cpu qemu64             \
                -name vm1               \
                -m 4096                 \
                -hda /var/lib/libvirt/images/vm1-1.qcow2        \
                -smp 4,sockets=4,cores=1,threads=1      \
                -netdev user,id=nat1,hostfwd=tcp:127.0.0.1:8000-10.0.2.15:22    \
                -device e1000,netdev=nat1,mac=52:54:00:13:01:01                 \
                -device vfio-pci,host=04:00.4,id=hostdev0,bus=pci.0,addr=0x9    \
                -vga std        \
                -vnc :1         \
                -daemonize

set +x
}
alias sq1="ssh -p 8000 127.0.0.1"

用如上命令q1启动虚拟机,注意加了-S选项。

# vncviewer :1

进入vnc界面后按ctrl + alt + 2,进入了所谓的QEMU monitor console,

输入

# gdbserver tcp::1234

在物理机上输入:

$ gdb vmlinux
GNU gdb (GDB) 8.0.50.20171229-git
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from vmlinux...done.
(gdb) target remote :1234
Remote debugging using :1234
0xffffffff8175db46 in cpu_idle_poll () at kernel/sched/idle.c:71
71              trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
(gdb) lx-symbols
loading vmlinux
scanning for modules in /home1/chrism/linux
loading @0xffffffffa057e000: /home1/chrism/linux/fs/nfs/nfsv3.ko
loading @0xffffffffa03de000: /home1/chrism/linux/fs/nfs_common/nfs_acl.ko
loading @0xffffffffa041f000: /home1/chrism/linux/net/sunrpc/auth_gss/rpcsec_gss_krb5.ko
loading @0xffffffffa03f7000: /home1/chrism/linux/net/sunrpc/auth_gss/auth_rpcgss.ko
loading @0xffffffffa0716000: /home1/chrism/linux/fs/nfs/nfsv4.ko
loading @0xffffffffa026a000: /home1/chrism/linux/net/dns_resolver/dns_resolver.ko
loading @0xffffffffa06d9000: /home1/chrism/linux/fs/nfs/nfs.ko
loading @0xffffffffa0567000: /home1/chrism/linux/fs/lockd/lockd.ko
loading @0xffffffffa025a000: /home1/chrism/linux/fs/nfs_common/grace.ko
loading @0xffffffffa046f000: /home1/chrism/linux/fs/fscache/fscache.ko
loading @0xffffffffa0642000: /home1/chrism/linux/net/wireless/cfg80211.ko
loading @0xffffffffa01c2000: /home1/chrism/linux/net/rfkill/rfkill.ko
loading @0xffffffffa058d000: /home1/chrism/linux/net/sunrpc/sunrpc.ko
loading @0xffffffffa0497000: /home1/chrism/linux/fs/ext4/ext4.ko
loading @0xffffffffa0255000: /home1/chrism/linux/fs/mbcache.ko
loading @0xffffffffa0455000: /home1/chrism/linux/fs/jbd2/jbd2.ko
loading @0xffffffffa0484000: /home1/chrism/linux/sound/pci/hda/snd-hda-codec-generic.ko
loading @0xffffffffa01ab000: /home1/chrism/linux/arch/x86/crypto/crct10dif-pclmul.ko
loading @0xffffffffa041a000: /home1/chrism/linux/arch/x86/crypto/crc32-pclmul.ko
loading @0xffffffffa025f000: /home1/chrism/linux/sound/pci/hda/snd-hda-intel.ko
loading @0xffffffffa01db000: /home1/chrism/linux/arch/x86/crypto/ghash-clmulni-intel.ko
...

下面就可以设置断点调试了:

(gdb) b mlx5e_xmit
Breakpoint 2 at 0xffffffffa0215f50: file drivers/net/ethernet/mellanox/mlx5/core/en_tx.c, line 371.
(gdb) c
Continuing.

Thread 7 hit Breakpoint 2, mlx5e_xmit (skb=0xffff8801277e0200, dev=0xffff8801225c0000) at drivers/net/ethernet/mellanox/mlx5/core/en_tx.c:371
371     {
(gdb) bt
#0  mlx5e_xmit (skb=0xffff8801277e0200, dev=0xffff8801225c0000) at drivers/net/ethernet/mellanox/mlx5/core/en_tx.c:371
#1  0xffffffff81625652 in trace_net_dev_start_xmit (dev=, skb=) at ./include/trace/events/net.h:13
#2  xmit_one (more=, txq=, dev=, skb=) at net/core/dev.c:2982
#3  dev_hard_start_xmit (first=0xffff8801277e0200, dev=0xffff8801225c0000, txq=0xffff8801225c0000, ret=0xffffc900001b7a2c) at net/core/dev.c:2999
#4  0xffffffff816525a8 in qdisc_qlen (q=) at ./include/net/sch_generic.h:281
#5  sch_direct_xmit (skb=0xffff8801277e0200, q=0xffff880126f34800, dev=0xffff8801225c0000, txq=0xffff8801233f8000, root_lock=0xffff880126f3489c, validate=) at net/sched/sch_generic.c:187
#6  0xffffffff81625d9a in sch_handle_egress (dev=, ret=, skb=) at net/core/dev.c:3280
#7  __dev_queue_xmit (skb=0xffff8801277e0200, accel_priv=0xffff880126f34800) at net/core/dev.c:3429
#8  0xffffffff81625f70 in netif_receive_skb_internal (skb=0xffff8801277e0200) at net/core/dev.c:4465
#9  0xffffffff81672c17 in ip_finish_output2 (net=0xffff8801277e0200, sk=0xffff8801225c0000, skb=0xffffffff81625f70 ) at net/ipv4/ip_output.c:194
#10 0xffffffff81672ef7 in ip_finish_output_gso (mtu=, skb=, sk=, net=) at net/ipv4/ip_output.c:275
#11 ip_finish_output (net=0xffffffff81cd6e40 , sk=0xffff8801265c0000, skb=) at net/ipv4/ip_output.c:312
#12 0xffffffff816739e2 in nf_hook_state_init (okfn=, net=, sk=, outdev=, indev=, pf=, hook=, p=)
    at ./include/linux/netfilter.h:121
#13 nf_hook (indev=, okfn=, outdev=, skb=, sk=, net=, hook=, pf=) at ./include/linux/netfilter.h:200
#14 NF_HOOK_COND (pf=, hook=, in=, okfn=, cond=, out=, skb=, sk=, net=)
    at ./include/linux/netfilter.h:235
#15 ip_output (net=0xffffffff81cd6e40 , sk=0xffff8801265c0000, skb=0xffff8801277e0200) at net/ipv4/ip_output.c:405
#16 0xffffffff816730e5 in ip_build_and_send_pkt (skb=0xffffffff81cd6e40 , sk=0x0 , saddr=2686628480, daddr=1800748, opt=0xffff880126f3489c) at net/ipv4/ip_output.c:152
#17 0xffffffff81674389 in ip_push_pending_frames (sk=0xffffc900001b7c28, fl4=) at net/ipv4/ip_output.c:1512
#18 0xffffffff816743e3 in ip_make_skb (sk=0xffff8801277e0200, fl4=0xffff8801225c0000, getfrag=0xffffffffa022b280 , from=0xffffc900001b7a2c, length=653478044, transhdrlen=1, ipc=0xffff8801118a0000,
    rtp=0x0 , flags=1801776) at net/ipv4/ip_output.c:1546
#19 0xffffffff8169cda5 in sock_tx_timestamp (tx_flags=, tsflags=, sk=) at ./include/net/sock.h:2269
#20 raw_sendmsg (sk=0xffffffff81674389 , msg=, len=18446612137252749312) at net/ipv4/raw.c:647
#21 0xffffffff816acf5e in rps_record_sock_flow (hash=, table=) at ./include/linux/netdevice.h:665
#22 sock_rps_record_flow_hash (hash=) at ./include/net/sock.h:927
#23 sock_rps_record_flow (sk=) at ./include/net/sock.h:947
#24 inet_sendmsg (sock=, msg=0xffff8801225c0000, size=18446744072101212800) at net/ipv4/af_inet.c:755
#25 0xffffffff81605038 in sock_sendmsg_nosec (msg=, sock=) at net/socket.c:633
#26 sock_sendmsg (sock=0xffff88011622c000, msg=0xffffc900001b7e30) at net/socket.c:643
#27 0xffffffff8160559f in SYSC_sendto (fd=, buff=, len=, flags=0, addr=0x5ee3998500, addr_len=16) at net/socket.c:1736
#28 0xffffffff8160607e in SyS_sendto (fd=, buff=, len=, flags=, addr=, addr_len=) at net/socket.c:1704
#29 0xffffffff8175e6b7 in entry_SYSCALL_64 () at arch/x86/entry/entry_64.S:236
#30 0x0000000000000401 in irq_stack_union ()
#31 0x00007ffcb6d011a4 in ?? ()
#32 0x00007ffcb6d00100 in ?? ()
#33 0x00007ffcb6d00c80 in ?? ()
#34 0x0000000000000401 in irq_stack_union ()
#35 0x0000000000000000 in ?? ()
(gdb) print *(struct net_device*) 0xffff8801225c0000
$1 = {
  name = "ens9", '\000' ,
  name_hlist = {
    next = 0x0 ,
    pprev = 0xffff88012950cfc0
  },

如果要用KVM,而不是QEMU的话,加上如下内容:

# virsh edit vm1

  
    
  

参考链接:

https://lwn.net/Articles/631167/

https://www.kernel.org/doc/html/v4.11/dev-tools/gdb-kernel-debugging.html

https://wiki.libvirt.org/page/QEMUSwitchToLibvirt#-S

http://blog.csdn.net/heli007/article/details/7187586

需要说明的是,虚拟机需要重新编译内核,加上如下选项:

CONFIG_GDB_SCRIPTS=y
物理机需要和虚拟机有同样的vmlinux

你可能感兴趣的:(如何在Linux内核中设置断点)