On Tue, Mar 01, 2016 at 11:50:28PM +0100, Martin Pieuchot wrote:
> Trying to get a backtrace after setting a breakpoint on the ``syscall''
> symbol on ddb(4) does not work well.  On am64 it faults:
> 
>   Breakpoint at   syscall:        pushq   %rbp
>   ddb{0}> tr
>   syscall() at syscall
>   Xsyscall() at Xsyscall+0xcb
>   uvm_fault(0xffffff000f6c3100, 0x1008, 0, 1) -> e
>   kernel: page fault trap, code=0
>   Faulted in DDB; continuing...
> 
> This is simply because the logic in db_stack_trace_print()/db_nextframe()
> is rather simple and assume the first frame is completely in kernel.
> 
> The diff below improves the situation, but is not completely correct
> since we cannot really compare the frame pointers.
> 
>   Breakpoint at   syscall:        pushq   %rbp
>   ddb{0}> tr
>   syscall() at syscall
>   --- syscall (number 74) ---
>   Bad user frame pointer: 0x1000
>   end trace frame: 0x1000, count: -1
>   0x70116b2845a:
> 
> I'm interested in any input as I'm facing the same problem when I'm
> instrumenting any kernel entry point.  But if you think the approach
> below is still a step forward I'll happily commit it.

The diff below seems to improve things, so I would say go for it.

-ml

> 
> 
> Index: arch/amd64/amd64/db_trace.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/amd64/db_trace.c,v
> retrieving revision 1.16
> diff -u -p -r1.16 db_trace.c
> --- arch/amd64/amd64/db_trace.c       1 Mar 2016 21:35:13 -0000       1.16
> +++ arch/amd64/amd64/db_trace.c       1 Mar 2016 22:49:10 -0000
> @@ -176,7 +176,7 @@ db_stack_trace_print(db_expr_t addr, boo
>      char *modif, int (*pr)(const char *, ...))
>  {
>       struct callframe *frame, *lastframe;
> -     long            *argp;
> +     long            *argp, *arg0;
>       db_addr_t       callpc;
>       int             is_trap = 0;
>       boolean_t       kernel_only = TRUE;
> @@ -235,7 +235,7 @@ db_stack_trace_print(db_expr_t addr, boo
>                               offset = 0;
>                       }
>               }
> -             if (INKERNEL(frame) && name) {
> +             if (INKERNEL(callpc) && name) {
>                       if (!strcmp(name, "trap")) {
>                               is_trap = TRAP;
>                       } else if (!strcmp(name, "ast")) {
> @@ -265,14 +265,15 @@ db_stack_trace_print(db_expr_t addr, boo
>               if (lastframe == 0 && offset == 0 && !have_addr) {
>                       /*
>                        * We have a breakpoint before the frame is set up
> -                      * Use %esp instead
> +                      * Use %rsp instead
>                        */
> -                     argp = &((struct callframe 
> *)(ddb_regs.tf_rsp-8))->f_arg0;
> +                     arg0 =
> +                         &((struct callframe *)(ddb_regs.tf_rsp-8))->f_arg0;
>               } else {
> -                     argp = &frame->f_arg0;
> +                     arg0 = &frame->f_arg0;
>               }
>  
> -             while (narg) {
> +             for (argp = arg0; narg > 0; ) {
>                       (*pr)("%lx", db_get_value((db_addr_t)argp, 8, FALSE));
>                       argp++;
>                       if (--narg != 0)
> @@ -282,7 +283,7 @@ db_stack_trace_print(db_expr_t addr, boo
>               db_printsym(callpc, DB_STGY_PROC, pr);
>               (*pr)("\n");
>  
> -             if (lastframe == 0 && offset == 0 && !have_addr) {
> +             if (lastframe == 0 && offset == 0 && !have_addr && !is_trap) {
>                       /* Frame really belongs to next callpc */
>                       lastframe = (struct callframe *)(ddb_regs.tf_rsp-8);
>                       callpc = (db_addr_t)
> @@ -299,9 +300,11 @@ db_stack_trace_print(db_expr_t addr, boo
>                        * trapframe as with syscalls and traps.
>                        */
>                       frame = (struct callframe *)&lastframe->f_retaddr;
> +                     arg0 = &frame->f_arg0;
>               }
> +
>               lastframe = frame;
> -             db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap, pr);
> +             db_nextframe(&frame, &callpc, arg0, is_trap, pr);
>  
>               if (frame == 0) {
>                       /* end of chain */
> Index: arch/i386/i386/db_trace.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/i386/i386/db_trace.c,v
> retrieving revision 1.18
> diff -u -p -r1.18 db_trace.c
> --- arch/i386/i386/db_trace.c 1 Mar 2016 21:35:13 -0000       1.18
> +++ arch/i386/i386/db_trace.c 1 Mar 2016 22:32:08 -0000
> @@ -158,7 +158,7 @@ db_stack_trace_print(db_expr_t addr, boo
>      char *modif, int (*pr)(const char *, ...))
>  {
>       struct callframe *frame, *lastframe;
> -     int             *argp;
> +     int             *argp, *arg0;
>       db_addr_t       callpc;
>       int             is_trap = 0;
>       boolean_t       kernel_only = TRUE;
> @@ -224,7 +224,7 @@ db_stack_trace_print(db_expr_t addr, boo
>                               offset = 0;
>                       }
>               }
> -             if (INKERNEL((int)frame) && name) {
> +             if (INKERNEL(callpc) && name) {
>                       if (!strcmp(name, "trap")) {
>                               is_trap = TRAP;
>                       } else if (!strcmp(name, "ast")) {
> @@ -255,12 +255,13 @@ db_stack_trace_print(db_expr_t addr, boo
>                        * We have a breakpoint before the frame is set up
>                        * Use %esp instead
>                        */
> -                     argp = &((struct callframe 
> *)(ddb_regs.tf_esp-4))->f_arg0;
> +                     arg0 =
> +                         &((struct callframe *)(ddb_regs.tf_esp-4))->f_arg0;
>               } else {
> -                     argp = &frame->f_arg0;
> +                     arg0 = &frame->f_arg0;
>               }
>  
> -             while (narg) {
> +             for (argp = arg0; narg > 0; ) {
>                       (*pr)("%x", db_get_value((int)argp, 4, FALSE));
>                       argp++;
>                       if (--narg != 0)
> @@ -270,7 +271,7 @@ db_stack_trace_print(db_expr_t addr, boo
>               db_printsym(callpc, DB_STGY_PROC, pr);
>               (*pr)("\n");
>  
> -             if (lastframe == 0 && offset == 0 && !have_addr) {
> +             if (lastframe == 0 && offset == 0 && !have_addr && !is_trap) {
>                       /* Frame really belongs to next callpc */
>                       lastframe = (struct callframe *)(ddb_regs.tf_esp-4);
>                       callpc = (db_addr_t)
> @@ -279,7 +280,7 @@ db_stack_trace_print(db_expr_t addr, boo
>               }
>  
>               lastframe = frame;
> -             db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap, pr);
> +             db_nextframe(&frame, &callpc, arg0, is_trap, pr);
>  
>               if (frame == 0) {
>                       /* end of chain */
> 

Reply via email to