Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2634746
  • 博文数量: 258
  • 博客积分: 9440
  • 博客等级: 少将
  • 技术积分: 6998
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-03 10:28
个人简介

-- linux爱好者,业余时间热衷于分析linux内核源码 -- 目前主要研究云计算和虚拟化相关的技术,主要包括libvirt/qemu,openstack,opennebula架构和源码分析。 -- 第五届云计算大会演讲嘉宾 微博:@Marshal-Liu

文章分类

全部博文(258)

文章存档

2016年(1)

2015年(4)

2014年(16)

2013年(22)

2012年(41)

2011年(59)

2010年(40)

2009年(75)

分类: LINUX

2011-02-27 20:40:14

1 问题发现
在用gdb调试linux内核网卡驱动时,在多次next之后,会出现下面结果:
执行某条语句后,gdb提示
[New Thread 4]
[New Thread 3]
contiuing ... ...
导致调试无法继续。
2 问题分析
首先想到的是产生了多线程的切换,因为调试环境是在多核机器上进行的,所以猜测其原因可能是当前核上的处于running的调试线程由于某种原因挂起了,因此调试过程切换到了其他核上,但是由于当前核上的调试资源没有被释放,因此,其他某个处于running状态的核得不到调试资源,使整个gdb挂起。今天有个师弟给我发了下面这篇文章,基本证实了这个想法。
3 kgdb多核patch
This is the updated kgdb SMP patch, which is tested on blackfin bf561 dual core
system. A new bug is fixed, which causes debugging halt in SMP kernel if a
breakpoint is hit and cpu is switched in gdb before continue running kernel.

   In blackfin SMP architecture, different core has its own L1 SRAM and MMR
   memory, which code running on the other core can't access. In current kgdb
   impelemntation, cpus are represented by thread with minus prefix.

If user run thread command in gdb to switch to the thread of the other cpu,
kgdb should:
1. send IPI signal to master cpu
2. release the specific passive cpu waiting in IPI handler
3. exit kgdb exception loop on master cpu and trap into kgdb wait in IPI handler
4. trap the released passive cpu into kgdb exception in IPI handler

  1. Signed-off-by: Sonic Zhang <sonic.adi@gmail.com>
  2. ---
  3.  include/linux/kgdb.h
  4.  kernel/kgdb.c
  5. Andrew Morton - Feb. 20, 2009, 12:55 a.m.
  6. On Wed, 18 Feb 2009 17:37:54 +0800
  7. sonic zhang <sonic.adi@gmail.com> wrote:

  8. > This is the updated kgdb SMP patch, which is tested on blackfin bf561 dual core
  9. > system. A new bug is fixed, which causes debugging halt in SMP kernel if a
  10. > breakpoint is hit and cpu is switched in gdb before continue running kernel.
  11. >
  12. > In blackfin SMP architecture, different core has its own L1 SRAM and MMR
  13. > memory, which code running on the other core can't access. In current kgdb
  14. > impelemntation, cpus are represented by thread with minus prefix.
  15. >
  16. > If user run thread command in gdb to switch to the thread of the other cpu,
  17. > kgdb should:
  18. > 1. send IPI signal to master cpu
  19. > 2. release the specific passive cpu waiting in IPI handler
  20. > 3. exit kgdb exception loop on master cpu and trap into kgdb wait in IPI handler
  21. > 4. trap the released passive cpu into kgdb exception in IPI handler
  22. >

  23. x86_64 allmodconfig:

  24. kernel/kgdb.c: In function 'kgdb_wait':
  25. kernel/kgdb.c:589: error: 'KGDB_THR_PROC_SWAP' undeclared (first use in this function)
  26. kernel/kgdb.c:589: error: (Each undeclared identifier is reported only once
  27. kernel/kgdb.c:589: error: for each function it appears in.)
  28. kernel/kgdb.c: In function 'gdb_cmd_query':
  29. kernel/kgdb.c:1087: error: 'KGDB_THR_PROC_SWAP' undeclared (first use in this function)
  30. kernel/kgdb.c: In function 'gdb_cmd_task':
  31. kernel/kgdb.c:1113: error: 'KGDB_THR_PROC_SWAP' undeclared (first use in this function)
  32. kernel/kgdb.c: In function 'gdb_cmd_thread':
  33. kernel/kgdb.c:1163: error: 'KGDB_THR_PROC_SWAP' undeclared (first use in this function)
  34. kernel/kgdb.c: In function 'gdb_serial_stub':
  35. kernel/kgdb.c:1275: error: 'KGDB_THR_PROC_SWAP' undeclared (first use in this function)
  36. kernel/kgdb.c: In function 'kgdb_handle_exception':
  37. kernel/kgdb.c:1575: error: 'KGDB_THR_PROC_SWAP' undeclared (first use in this function)
  38. kernel/kgdb.c: In function 'kgdb_nmicallback':
  39. kernel/kgdb.c:1606: warning: suggest parentheses around && within ||
  40. kernel/kgdb.c:1606: warning: suggest parentheses around && within ||
  41. kernel/kgdb.c:1606: warning: suggest parentheses around && within ||
  42. --
  43. To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
  44. the body of a message to majordomo@vger.kernel.org
  45. More majordomo info at http://vger.kernel.org/majordomo-info.html
  46. Please read the FAQ at http://www.tux.org/lkml/
  47. Patch
  48. diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
  49. index 6adcc29..664e396 100644
  50. --- a/include/linux/kgdb.h
  51. +++ b/include/linux/kgdb.h
  52. @@ -203,6 +204,19 @@ kgdb_arch_handle_exception(int vector, int signo, int err_code,
  53.   */
  54.  extern void kgdb_roundup_cpus(unsigned long flags);

  55. +/**
  56. + *    kgdb_roundup_cpu - Get spcific CPU into a holding pattern
  57. + *    @cpu: Specific cpu id
  58. + *    @flags: Current IRQ state
  59. + *
  60. + *    On SMP systems, we need to switch cpu from current active one to
  61. + *    the other passive one. This get current active CPU into a known state
  62. + *    in kgdb_wait().
  63. + *
  64. + *    On non-SMP systems, this is not called.
  65. + */
  66. +extern void kgdb_roundup_cpu(int cpu, unsigned long flags);
  67. +
  68.  /* Optional functions. */
  69.  extern int kgdb_validate_break_address(unsigned long addr);
  70.  extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr);
  71. diff --git a/kernel/kgdb.c b/kernel/kgdb.c
  72. index e4dcfb2..277986d 100644
  73. --- a/kernel/kgdb.c
  74. +++ b/kernel/kgdb.c
  75. @@ -565,6 +565,7 @@
  76.  {
  77.      unsigned long flags;
  78.      int cpu;
  79. +    struct task_struct *thread;

  80.      local_irq_save(flags);
  81.      cpu = raw_smp_processor_id();
  82. @@ -577,10 +578,26 @@
  83.      smp_wmb();
  84.      atomic_set(&cpu_in_kgdb[cpu], 1);

  85. +    kgdb_disable_hw_debug(regs);
  86. +
  87.      /* Wait till primary CPU is done with debugging */
  88.      while (atomic_read(&passive_cpu_wait[cpu]))
  89.          cpu_relax();

  90. +    /* Trap into kgdb as the active CPU if gdb asks to switch. */
  91. +    thread = getthread(regs, -raw_smp_processor_id() - 2);
  92. +    if ((arch_kgdb_ops.flags & KGDB_THR_PROC_SWAP) &&
  93. +        kgdb_contthread && kgdb_contthread == current) {
  94. +        kgdb_breakpoint();
  95. +
  96. +        kgdb_info[cpu].debuggerinfo = NULL;
  97. +        kgdb_info[cpu].task = NULL;
  98. +
  99. +        clocksource_touch_watchdog();
  100. +        local_irq_restore(flags);
  101. +        return;
  102. +    }
  103. +
  104.      kgdb_info[cpu].debuggerinfo = NULL;
  105.      kgdb_info[cpu].task = NULL;

  106. @@ -1066,13 +1083,16 @@
  107.              sprintf(tmpstr, "shadowCPU%d",
  108.                      (int)(-ks->threadid - 2));
  109.              kgdb_mem2hex(tmpstr, remcom_out_buffer, strlen(tmpstr));
  110. +
  111. +            if (arch_kgdb_ops.flags & KGDB_THR_PROC_SWAP)
  112. +                ks->thr_query = 1;
  113.          }
  114.          break;
  115.      }
  116.  }

  117.  /* Handle the 'H' task query packets */
  118. -static void gdb_cmd_task(struct kgdb_state *ks)
  119. +static int gdb_cmd_task(struct kgdb_state *ks)
  120.  {
  121.      struct task_struct *thread;
  122.      char *ptr;
  123. @@ -1089,6 +1109,15 @@
  124.          kgdb_usethread = thread;
  125.          ks->kgdb_usethreadid = ks->threadid;
  126.          strcpy(remcom_out_buffer, "OK");
  127. +#ifdef CONFIG_SMP
  128. +        if ((arch_kgdb_ops.flags & KGDB_THR_PROC_SWAP) &&
  129. +            !ks->thr_query && ks->kgdb_usethreadid < -1 &&
  130. +            - ks->kgdb_usethreadid - 2 != raw_smp_processor_id()) {
  131. +            kgdb_roundup_cpu(raw_smp_processor_id(), 0);
  132. +            kgdb_contthread = kgdb_usethread;
  133. +            return 1;
  134. +        }
  135. +#endif
  136.          break;
  137.      case 'c':
  138.          ptr = &remcom_in_buffer[2];
  139. @@ -1102,10 +1131,27 @@
  140.                  break;
  141.              }
  142.              kgdb_contthread = thread;
  143. +#ifdef CONFIG_SMP
  144. +            if ((arch_kgdb_ops.flags & KGDB_THR_PROC_SWAP) &&
  145. +                thread != current) {
  146. +                int cpu;
  147. +                for_each_online_cpu(cpu) {
  148. +                    if (thread == kgdb_info[cpu].task) {
  149. +                        kgdb_roundup_cpu(
  150. +                            raw_smp_processor_id(),
  151. +                            0);
  152. +                        ks->kgdb_usethreadid = -cpu-2;
  153. +                        return 1;
  154. +                    }
  155. +                }
  156. +            }
  157. +#endif
  158.          }
  159.          strcpy(remcom_out_buffer, "OK");
  160.          break;
  161.      }
  162. +
  163. +    return 0;
  164.  }

  165.  /* Handle the 'T' thread query packets */
  166. @@ -1114,6 +1160,9 @@
  167.      char *ptr = &remcom_in_buffer[1];
  168.      struct task_struct *thread;

  169. +    if (arch_kgdb_ops.flags & KGDB_THR_PROC_SWAP)
  170. +        ks->thr_query = 0;
  171. +
  172.      kgdb_hex2long(&ptr, &ks->threadid);
  173.      thread = getthread(ks->linux_regs, ks->threadid);
  174.      if (thread)
  175. @@ -1223,7 +1272,12 @@
  176.      /* Clear the out buffer. */
  177.      memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));

  178. -    if (kgdb_connected) {
  179. +    if ((arch_kgdb_ops.flags & KGDB_THR_PROC_SWAP) && kgdb_contthread) {
  180. +        remcom_out_buffer[0] = 'O';
  181. +        remcom_out_buffer[1] = 'K';
  182. +        remcom_out_buffer[2] = 0;
  183. +        put_packet(remcom_out_buffer);
  184. +    } else if (kgdb_connected) {
  185.          unsigned char thref[8];
  186.          char *ptr;

  187. @@ -1238,6 +1292,7 @@
  188.          put_packet(remcom_out_buffer);
  189.      }

  190. +    kgdb_contthread = current;
  191.      kgdb_usethread = kgdb_info[ks->cpu].task;
  192.      ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid);
  193.      ks->pass_exception = 0;
  194. @@ -1284,7 +1339,8 @@
  195.              gdb_cmd_query(ks);
  196.              break;
  197.          case 'H': /* task related */
  198. -            gdb_cmd_task(ks);
  199. +            if (gdb_cmd_task(ks))
  200. +                goto kgdb_exit;
  201.              break;
  202.          case 'T': /* Query thread status */
  203.              gdb_cmd_thread(ks);
  204. @@ -1324,6 +1380,7 @@
  205.              if (error >= 0 || remcom_in_buffer[0] == 'D' ||
  206.               remcom_in_buffer[0] == 'k') {
  207.                  error = 0;
  208. +                kgdb_contthread = NULL;
  209.                  goto kgdb_exit;
  210.              }

  211. @@ -1464,11 +1521,15 @@
  212.       * Get the passive CPU lock which will hold all the non-primary
  213.       * CPU in a spin state while the debugger is active
  214.       */
  215. -    if (!kgdb_single_step) {
  216. +    if (!kgdb_single_step && !kgdb_contthread) {
  217.          for (i = 0; i < NR_CPUS; i++)
  218.              atomic_set(&passive_cpu_wait[i], 1);
  219.      }

  220. +    if (kgdb_contthread)
  221. +        atomic_set(&passive_cpu_wait[raw_smp_processor_id()], 1);
  222. +
  223. +
  224.      /*
  225.       * spin_lock code is good enough as a barrier so we don't
  226.       * need one here:
  227. @@ -1477,7 +1538,7 @@

  228.  #ifdef CONFIG_SMP
  229.      /* Signal the other CPUs to enter kgdb_wait() */
  230. -    if ((!kgdb_single_step) && kgdb_do_roundup)
  231. +    if ((!kgdb_single_step && !kgdb_contthread) && kgdb_do_roundup)
  232.          kgdb_roundup_cpus(flags);
  233.  #endif

  234. @@ -1496,7 +1557,6 @@
  235.      kgdb_post_primary_code(ks->linux_regs, ks->ex_vector, ks->err_code);
  236.      kgdb_deactivate_sw_breakpoints();
  237.      kgdb_single_step = 0;
  238. -    kgdb_contthread = current;
  239.      exception_level = 0;

  240.      /* Talk to debugger with gdbserial protocol */
  241. @@ -1510,7 +1570,14 @@
  242.      kgdb_info[ks->cpu].task = NULL;
  243.      atomic_set(&cpu_in_kgdb[ks->cpu], 0);

  244. -    if (!kgdb_single_step) {
  245. +#ifdef CONFIG_SMP
  246. +    i = -(ks->kgdb_usethreadid + 2);
  247. +    if ((arch_kgdb_ops.flags & KGDB_THR_PROC_SWAP) &&
  248. +        kgdb_contthread && i != cpu) {
  249. +        atomic_set(&passive_cpu_wait[i], 0);
  250. +    }
  251. +#endif
  252. +    if (!kgdb_single_step && !kgdb_contthread) {
  253.          for (i = NR_CPUS-1; i >= 0; i--)
  254.              atomic_set(&passive_cpu_wait[i], 0);
  255.          
阅读(3706) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~