使用 wmare调试 intel e1000 网卡!!!

朋友们好,我是混元形意太极门掌门人马保国,在今天我给大家展示一下如何使用我传统马家功夫

用来调试 linux intel e1000 网卡驱动。

 

这里推荐 张银奎 张老师的 GDK intel 平台硬件调试器,不依赖操作系统,基于intel DCI 技术.

还提供售后服务,确实好用,我这不是打广告,虽然 GDK 与本文内容关系不大,使用GDK

可用用来调试固件 比如 bios 等,所有 一般 bios 工程师会在 bios 开启 DCI

购买链接: http://advdbg.org/gdk/

使用 vmware 调试 内核 设置 参考 : https://www.cnblogs.com/maojun1998/p/13878813.html

1. 如何 抓到 e1000.ko 加载的事件?

  用过 Windbg的人都知道, 它可以自动抓到内核模块加载的事件然后从微软的调试符号器中加载调试符号

  所以如何写这样的类似Windbg的自动加载驱动符号的功能呢,我猜测Windbg 是通过 NTLoadDriver这个系统调用实现的

  所有在NtLoadDriver下一个断点就抓得到了, bp nt!NtLoadDriver,输入 g命令等待断点段下来,断下来后自然是传统功夫

  的点到为止,然后 bp xxx_module!DriverEntry ,把断点下载驱动的入口函数,左手放在他脸上,没打他,他也承认我断下来。

  

  那么如何在 linux 抓住这样的加载驱动的事件呢?技巧是断点在 do_init_module,这函数很重要

  1 /*
  2  * This is where the real work happens.
  3  *
  4  * Keep it uninlined to provide a reliable breakpoint target, e.g. for the gdb
  5  * helper command 'lx-symbols'.
  6  */
  7 static noinline int do_init_module(struct module *mod)
  8 {
  9     int ret = 0;
 10     struct mod_initfree *freeinit;
 11 
 12     freeinit = kmalloc(sizeof(*freeinit), GFP_KERNEL);
 13     if (!freeinit) {
 14         ret = -ENOMEM;
 15         goto fail;
 16     }
 17     freeinit->module_init = mod->init_layout.base;
 18 
 19     /*
 20      * We want to find out whether @mod uses async during init.  Clear
 21      * PF_USED_ASYNC.  async_schedule*() will set it.
 22      */
 23     current->flags &= ~PF_USED_ASYNC;
 24 
 25     do_mod_ctors(mod);
 26     /* Start the module */
 27     if (mod->init != NULL)
 28         ret = do_one_initcall(mod->init);
 29     if (ret < 0) {
 30         goto fail_free_freeinit;
 31     }
 32     if (ret > 0) {
 33         pr_warn("%s: '%s'->init suspiciously returned %d, it should "
 34             "follow 0/-E convention\n"
 35             "%s: loading module anyway...\n",
 36             __func__, mod->name, ret, __func__);
 37         dump_stack();
 38     }
 39 
 40     /* Now it's a first class citizen! */
 41     mod->state = MODULE_STATE_LIVE;
 42     blocking_notifier_call_chain(&module_notify_list,
 43                      MODULE_STATE_LIVE, mod);
 44 
 45     /*
 46      * We need to finish all async code before the module init sequence
 47      * is done.  This has potential to deadlock.  For example, a newly
 48      * detected block device can trigger request_module() of the
 49      * default iosched from async probing task.  Once userland helper
 50      * reaches here, async_synchronize_full() will wait on the async
 51      * task waiting on request_module() and deadlock.
 52      *
 53      * This deadlock is avoided by perfomring async_synchronize_full()
 54      * iff module init queued any async jobs.  This isn't a full
 55      * solution as it will deadlock the same if module loading from
 56      * async jobs nests more than once; however, due to the various
 57      * constraints, this hack seems to be the best option for now.
 58      * Please refer to the following thread for details.
 59      *
 60      * http://thread.gmane.org/gmane.linux.kernel/1420814
 61      */
 62     if (!mod->async_probe_requested && (current->flags & PF_USED_ASYNC))
 63         async_synchronize_full();
 64 
 65     mutex_lock(&module_mutex);
 66     /* Drop initial reference. */
 67     module_put(mod);
 68     trim_init_extable(mod);
 69 #ifdef CONFIG_KALLSYMS
 70     /* Switch to core kallsyms now init is done: kallsyms may be walking! */
 71     rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms);
 72 #endif
 73     module_enable_ro(mod, true);
 74     mod_tree_remove_init(mod);
 75     disable_ro_nx(&mod->init_layout);
 76     module_arch_freeing_init(mod);
 77     mod->init_layout.base = NULL;
 78     mod->init_layout.size = 0;
 79     mod->init_layout.ro_size = 0;
 80     mod->init_layout.ro_after_init_size = 0;
 81     mod->init_layout.text_size = 0;
 82     /*
 83      * We want to free module_init, but be aware that kallsyms may be
 84      * walking this with preempt disabled.  In all the failure paths, we
 85      * call synchronize_sched(), but we don't want to slow down the success
 86      * path, so use actual RCU here.
 87      * Note that module_alloc() on most architectures creates W+X page
 88      * mappings which won't be cleaned up until do_free_init() runs.  Any
 89      * code such as mark_rodata_ro() which depends on those mappings to
 90      * be cleaned up needs to sync with the queued work - ie
 91      * rcu_barrier_sched()
 92      */
 93     call_rcu_sched(&freeinit->rcu, do_free_init);
 94     mutex_unlock(&module_mutex);
 95     wake_up_all(&module_wq);
 96 
 97     return 0;
 98 
 99 fail_free_freeinit:
100     kfree(freeinit);
101 fail:
102     /* Try to protect us from buggy refcounters. */
103     mod->state = MODULE_STATE_GOING;
104     synchronize_sched();
105     module_put(mod);
106     blocking_notifier_call_chain(&module_notify_list,
107                      MODULE_STATE_GOING, mod);
108     klp_module_going(mod);
109     ftrace_release_mod(mod);
110     free_module(mod);
111     wake_up_all(&module_wq);
112     return ret;
113 }

  ok, 断点下来了,

  print /x (mod.sect_attrs.attrs[2]).address
  print /x (mod.sect_attrs.attrs[14]).address
  print /x (mod.sect_attrs.attrs[20]).address
  print /x (mod.sect_attrs.attrs[4]).address

  分别打印模块的 .text .data .bss .init.text  的地址

  然后把在e1000.ko 调试符号加入 gdb,使用如下命令

  add-symbol-file e1000.ko 0xffffffffc053a000 -s .data 0xffffffffc0555000 -s .bss 0xffffffffc0557840 -s .init.text 0xffffffffc006b000

  把 上面4个0xffffffffc053a000 ,0xffffffffc0555000, 0xffffffffc0557840 ,  0xffffffffc006b000 地址替换成 打印的地址

  然后断点断在 e1000_init_module 他的完整原型是 static int __init e1000_init_module(void)

 1 /**
 2  * e1000_init_module - Driver Registration Routine
 3  *
 4  * e1000_init_module is the first routine called when the driver is
 5  * loaded. All it does is register with the PCI subsystem.
 6  **/
 7 static int __init e1000_init_module(void)
 8 {
 9     int ret;
10     pr_info("%s - version %s\n", e1000_driver_string, e1000_driver_version);
11 
12     pr_info("%s\n", e1000_copyright);
13 
14     ret = pci_register_driver(&e1000_driver);
15     if (copybreak != COPYBREAK_DEFAULT) {
16         if (copybreak == 0)
17             pr_info("copybreak disabled\n");
18         else
19             pr_info("copybreak enabled for "
20                    "packets <= %u bytes\n", copybreak);
21     }
22     return ret;
23 }
24 
25 module_init(e1000_init_module);

pci_register_driver 是最核心的函数

 1 static SIMPLE_DEV_PM_OPS(e1000_pm_ops, e1000_suspend, e1000_resume);
 2 
 3 static struct pci_driver e1000_driver = {
 4     .name     = e1000_driver_name,
 5     .id_table = e1000_pci_tbl,
 6     .probe    = e1000_probe,
 7     .remove   = e1000_remove,
 8     .driver = {
 9         .pm = &e1000_pm_ops,
10     },
11     .shutdown = e1000_shutdown,
12     .err_handler = &e1000_err_handler
13 };

 

  e1000_probe是probe 函数,所有 断点断在 e1000_probe, break e1000_probe

  断下来后,自然研究 是谁调用的 这个函数,使用 bt命令

 

 1 #0  e1000_probe (pdev=0xffff8881381ca000, ent=0xffffffffc054e660) at drivers/net/ethernet/intel/e1000/e1000_main.c:924
 2 #1  0xffffffff8161a1a8 in local_pci_probe (_ddi=0xffffc90000d8bab0) at drivers/pci/pci-driver.c:306
 3 #2  0xffffffff8161bbe5 in pci_call_probe (id=<optimized out>, dev=<optimized out>, drv=<optimized out>) at drivers/pci/pci-driver.c:361
 4 #3  __pci_device_probe (pci_dev=<optimized out>, drv=<optimized out>) at drivers/pci/pci-driver.c:386
 5 #4  pci_device_probe (dev=0xffff8881381ca0b0) at drivers/pci/pci-driver.c:429
 6 #5  0xffffffff817a0577 in really_probe (dev=0xffff8881381ca0b0, drv=0xffffffffc0555080 <e1000_driver+96>) at drivers/base/dd.c:521
 7 #6  0xffffffff817a0b97 in really_probe_debug (drv=<optimized out>, dev=<optimized out>) at drivers/base/dd.c:624
 8 #7  driver_probe_device (drv=0xffffffffc0555080 <e1000_driver+96>, dev=0xffff8881381ca0b0) at drivers/base/dd.c:695
 9 #8  0xffffffff817a0f6b in device_driver_attach (drv=0xffffffffc0555080 <e1000_driver+96>, dev=0xffff8881381ca0b0) at drivers/base/dd.c:972
10 #9  0xffffffff817a0fff in __driver_attach (dev=0xffff8881381ca0b0, data=0xffffffffc0555080 <e1000_driver+96>) at drivers/base/dd.c:1049
11 #10 0xffffffff8179dfae in bus_for_each_dev (bus=<optimized out>, start=<optimized out>, data=0xffffffffc0555080 <e1000_driver+96>, fn=0xffffffff817a0f70 <__driver_attach>)
12     at drivers/base/bus.c:305
13 #11 0xffffffff8179fd7e in driver_attach (drv=<optimized out>) at drivers/base/dd.c:1065
14 #12 0xffffffff8179f715 in bus_add_driver (drv=0xffffffffc0555080 <e1000_driver+96>) at drivers/base/bus.c:622
15 #13 0xffffffff817a1bf1 in driver_register (drv=0xffff8881381ca000) at drivers/base/driver.c:171
16 #14 0xffffffff81619c84 in __pci_register_driver (drv=<optimized out>, owner=<optimized out>, mod_name=<optimized out>) at drivers/pci/pci-driver.c:1414
17 #15 0xffffffffc006b052 in e1000_init_module () at drivers/net/ethernet/intel/e1000/e1000_main.c:228
18 #16 0xffffffff8100387a in do_one_initcall (fn=0xffffffffc006b000 <e1000_init_module>) at init/main.c:1202
19 #17 0xffffffff8115c652 in do_init_module (mod=0xffffffffc05574c0) at kernel/module.c:3582
20 #18 0xffffffff8115ed0c in load_module (info=0xffffc90000d8be70, uargs=<optimized out>, flags=<optimized out>) at kernel/module.c:3933
21 #19 0xffffffff8115f26e in __do_sys_finit_module (fd=3, uargs=0x5613acd0e358 "", flags=0) at kernel/module.c:4023
22 #20 0xffffffff8115f2ea in __se_sys_finit_module (flags=<optimized out>, uargs=<optimized out>, fd=<optimized out>) at kernel/module.c:3999
23 #21 __x64_sys_finit_module (regs=<optimized out>) at kernel/module.c:3999
24 #22 0xffffffff81b986d9 in do_syscall_64 (nr=<optimized out>, regs=0xffffc90000d8bf58) at arch/x86/entry/common.c:392
25 #23 0xffffffff81c0008c in entry_SYSCALL_64 () at arch/x86/entry/entry_64.S:117

 

 

 

没有用户态调用栈,当然可以自己实现

 

明天继续分析。。。。

posted @ 2020-12-14 20:48  maojun1998  阅读(720)  评论(0编辑  收藏  举报