kprobe inserts a pile at a function offset

For symbols, it is easy to find, just look up the kernel symbol table, but if you want to know the offset of a statement in a function relative to the starting address of the function, you still need a certain method.

Requirement: How to get the corresponding offset if you want to insert the following function struct sk_buff *next = skb->next;.

3253 struct sk_buff *dev_hard_start_xmit(struct sk_buff *first, struct net_device *dev,
3254 struct netdev_queue *txq, int *ret)
3255 {<!-- -->
3256 struct sk_buff *skb = first;
3257 int rc = NETDEV_TX_OK;
3258
3259 while (skb) {<!-- -->
3260 struct sk_buff *next = skb->next;
3261
3262 skb->next = NULL;
3263 rc = xmit_one(skb, dev, txq, next != NULL);
3264 if (unlikely(!dev_xmit_complete(rc))) {<!-- -->
3265 skb->next = next;
3266 goto out;
3267}
3268
3269 skb = next;
3270 if (netif_xmit_stopped(txq) & amp; & amp; skb) {<!-- -->
3271 rc = NETDEV_TX_BUSY;
3272 break;
3273}
3274}
3275
3276 out:
3277 *ret = rc;
3278 return skb;
3279}
  • Method 1: Use the crash dis -l $func_name command to obtain
    Environment setup can refer to Linux crash debugging environment setup
[root@gitclient kernel-4.18.0-80.el8]# crash /usr/lib/debug/usr/lib/modules/4.18.0-80.el8.x86_64/vmlinux /proc/kcore

crash 7.2.9-2.el8
Copyright (C) 2002-2020 Red Hat, Inc.
Copyright (C) 2004, 2005, 2006, 2010 IBM Corporation
Copyright (C) 1999-2006 Hewlett-Packard Co
Copyright (C) 2005, 2006, 2011, 2012 Fujitsu Limited
Copyright (C) 2006, 2007 VA Linux Systems Japan K.K.
Copyright (C) 2005, 2011 NEC Corporation
Copyright (C) 1999, 2002, 2007Silicon Graphics, Inc.
Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
This program is free software, covered by the GNU General Public License,
and you are welcome to change it and/or distribute copies of it under
certain conditions. Enter "help copying" to see the conditions.
This program has absolutely no warranty. Enter "help warranty" for details.

GNU gdb (GDB) 7.6
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3 + : GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
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-unknown-linux-gnu"...

WARNING: kernel relocated [706MB]: patching 91326 gdb minimal_symbol values

      KERNEL: /usr/lib/debug/usr/lib/modules/4.18.0-80.el8.x86_64/vmlinux
    DUMPFILE: /proc/kcore
        CPUS: 8
        DATE: Mon Mar 20 23:11:11 EDT 2023
      UPTIME: 1 days, 00:32:21
LOAD AVERAGE: 0.38, 0.14, 0.10
       TASKS: 585
    NODENAME: gitclient
     RELEASE: 4.18.0-80.el8.x86_64
     VERSION: #1 SMP Tue Jun 4 09:19:46 UTC 2019
     MACHINE: x86_64 (2200Mhz)
      MEMORY: 16GB
         PID: 464226
     COMMAND: "crash"
        TASK: ffff99691c43ad00 [THREAD_INFO: ffff99691c43ad00]
         CPU: 3
       STATE: TASK_RUNNING (ACTIVE)

crash> dis -s dev_hard_start_xmit

crash> help dis

name
  dis-disassemble

SYNOPSIS
  dis [-rfludxs][-b [num]] [address | symbol | (expression)] [count]

DESCRIPTION
  This command disassembles source code instructions starting (or ending) at
  a text address that may be expressed by value, symbol or expression:

            -r (reverse) displays all instructions from the start of the
                routine up to and including the designated address.
            -f (forward) displays all instructions from the given address
                to the end of the routine.
            -l displays source code line number data in addition to the
                disassembly output.
            -u address is a user virtual address in the current context;
                Otherwise the address is assumed to be a kernel virtual address.
                If this option is used, then -r and -l are ignored.
            -x override default output format with hexadecimal format.
            -d override default output format with decimal format.
            -s displays the filename and line number of the source code that
                is associated with the specified text location, followed by a
                source code listing if it is available on the host machine.
                The line associated with the text location will be marked with
                an asterisk; depending upon gdb's internal "listsize" variable,
                several lines will precede the marked location. If a "count"
                argument is entered, it specifies the number of source code
                lines to be displayed after the marked location; otherwise
                The remaining source code of the containing function will be
                displayed.
      -b [num] modify the pre-calculated number of encoded bytes to skip after
                a kernel BUG ("ud2a") instruction; with no argument, displays
                the current number of bytes being skipped. (x86 and x86_64 only)
       address starting hexadecimal text address.
        symbol symbol of starting text address. On ppc64, the symbol
                preceded by '.' is used.
  (expression) expression evaluating to a starting text address.
         count the number of instructions to be disassembled (default is 1).
                If no count argument is entered, and the starting address
                is entered as a text symbol, then the whole routine will be
                disassembled. The count argument is supported when used with
                the -r and -f options.

EXAMPLES
  Disassemble the sys_signal() routine without, and then with, line numbers:

    crash> dis sys_signal
    0xc0112c88 <sys_signal>: push ?p
    0xc0112c89 <sys_signal + 1>: mov %esp,?p
crash> dis -s dev_hard_start_xmit
FILE: net/core/dev.c
LINE: 3255

  3250 return rc;
  3251}
  3252
  3253 struct sk_buff *dev_hard_start_xmit(struct sk_buff *first, struct net_device *dev,
  3254 struct netdev_queue *txq, int *ret)
* 3255 {<!-- -->
  3256 struct sk_buff *skb = first;
  3257 int rc = NETDEV_TX_OK;
  3258
  3259 while (skb) {<!-- -->
  3260 struct sk_buff *next = skb->next;
  3261
  3262 skb->next = NULL;
  3263 rc = xmit_one(skb, dev, txq, next != NULL);
  3264 if (unlikely(!dev_xmit_complete(rc))) {<!-- -->
  3265 skb->next = next;
  3266 goto out;
  3267}
  3268
  3269 skb = next;
  3270 if (netif_xmit_stopped(txq) & amp; & amp; skb) {<!-- -->
  3271 rc = NETDEV_TX_BUSY;
  3272 break;
  3273}
  3274}
  3275
  3276 out:
  3277 *ret = rc;
  3278 return skb;
  3279}
  crash> dis -l dev_hard_start_xmit
/usr/src/debug/kernel-4.18.0-80.el8/linux-4.18.0-80.el8.x86_64/net/core/dev.c: 3255
0xffffffffad8ca510 <dev_hard_start_xmit>: data32 data32 data32 xchg %ax,%ax [FTRACE NOP]
/usr/src/debug/kernel-4.18.0-80.el8/linux-4.18.0-80.el8.x86_64/net/core/dev.c: 3259
0xffffffffad8ca515 <dev_hard_start_xmit + 5>: push %r15
0xffffffffad8ca517 <dev_hard_start_xmit + 7>: push %r14
0xffffffffad8ca519 <dev_hard_start_xmit + 9>: push %r13
0xffffffffad8ca51b <dev_hard_start_xmit + 11>: push %r12
0xffffffffad8ca51d <dev_hard_start_xmit + 13>: push %rbp
0xffffffffad8ca51e <dev_hard_start_xmit + 14>: push %rbx
0xffffffffad8ca51f <dev_hard_start_xmit + 15>: sub $0x20,%rsp
0xffffffffad8ca523 <dev_hard_start_xmit + 19>: mov %rcx,0x18(%rsp)
0xffffffffad8ca528 <dev_hard_start_xmit + 24>: test %rdi,%rdi
0xffffffffad8ca52b <dev_hard_start_xmit + 27>: je 0xffffffffad8ca706 <dev_hard_start_xmit + 502>
0xffffffffad8ca531 <dev_hard_start_xmit + 33>: lea 0x90(%rsi),%rax
0xffffffffad8ca538 <dev_hard_start_xmit + 40>: mov %rsi,%rbx
0xffffffffad8ca53b <dev_hard_start_xmit + 43>: mov %rdi,%r15
0xffffffffad8ca53e <dev_hard_start_xmit + 46>: mov %rdx,%r13
0xffffffffad8ca541 <dev_hard_start_xmit + 49>: mov %rax,0x8(%rsp)
/usr/src/debug/kernel-4.18.0-80.el8/linux-4.18.0-80.el8.x86_64/net/core/dev.c: 3260
0xffffffffad8ca546 <dev_hard_start_xmit + 54>: mov (%r15),%r12
/usr/src/debug/kernel-4.18.0-80.el8/linux-4.18.0-80.el8.x86_64/net/core/dev.c: 3262
0xffffffffad8ca549 <dev_hard_start_xmit + 57>: mov $0xffffffffae609090,%rax
0xffffffffad8ca550 <dev_hard_start_xmit + 64>: movq $0x0,(%r15)
/usr/src/debug/kernel-4.18.0-80.el8/linux-4.18.0-80.el8.x86_64/net/core/dev.c: 3263
0xffffffffad8ca557 <dev_hard_start_xmit + 71>: mov (%rax),%rax
0xffffffffad8ca55a <dev_hard_start_xmit + 74>: test %r12,%r12
0xffffffffad8ca55d <dev_hard_start_xmit + 77>: setne %bpl
/usr/src/debug/kernel-4.18.0-80.el8/linux-4.18.0-80.el8.x86_64/./include/linux/list.h: 203
0xffffffffad8ca561 <dev_hard_start_xmit + 81>: cmp $0xffffffffae609090,%rax
0xffffffffad8ca567 <dev_hard_start_xmit + 87>: je 0xffffffffad8ca6db <dev_hard_start_xmit + 459>
/usr/src/debug/kernel-4.18.0-80.el8/linux-4.18.0-80.el8.x86_64/net/core/dev.c: 3243
0xffffffffad8ca56d <dev_hard_start_xmit + 93>: mov %rbx,%rsi
0xffffffffad8ca570 <dev_hard_start_xmit + 96>: mov %r15,%rdi
0xffffffffad8ca573 <dev_hard_start_xmit + 99>: callq 0xffffffffad8c7fe0 <dev_queue_xmit_nit>
?…

Use dis -s to view the source code of the kernel function, and dis -l to obtain the line number of the source code corresponding to the assembly code, as shown below is the offset corresponding to struct sk_buff *next = skb->next; code>0x54.

0xffffffffad8ca546 <dev_hard_start_xmit + 54>: mov (%r15),%r12
/usr/src/debug/kernel-4.18.0-80.el8/linux-4.18.0-80.el8.x86_64/net/core/dev.c: 3262
  • Method 2: Use the kernel driver to dump the function memory and obtain it through disassembly
    The Linux driver reads the code segment data in the current kernel