14.3. Switching MDB to Debug a Specific ProcessAn mdb command, <proc address>::context, switches a context to a specified user process. > ffffffff866f1878::context debugger context set to proc ffffffff866f1878 After the context is switched, several mdb commands return process information rather than kernel information. For example: > ::nm Value Size Type Bind Other Shndx Name 0x0000000000000000|0x0000000000000000|NOTY |LOCL |0x0 |UNDEF | 0x0000000008056c29|0x0000000000000076|FUNC |GLOB |0x0 |10 |gethost_revalidate 0x0000000008056ad2|0x0000000000000024|FUNC |GLOB |0x0 |10 |getgr_uid_reaper 0x000000000805be5f|0x0000000000000000|OBJT |GLOB |0x0 |14 |_etext 0x0000000008052778|0x0000000000000000|FUNC |GLOB |0x0 |UNDEF |strncpy 0x0000000008052788|0x0000000000000000|FUNC |GLOB |0x0 |UNDEF |_uncached_getgrnam_r 0x000000000805b364|0x000000000000001b|FUNC |GLOB |0x0 |12 |_fini 0x0000000008058f54|0x0000000000000480|FUNC |GLOB |0x0 |10 |nscd_parse 0x0000000008052508|0x0000000000000000|FUNC |GLOB |0x0 |UNDEF |pause 0x00000000080554e0|0x0000000000000076|FUNC |GLOB |0x0 |10 |getpw_revalidate ... > ::mappings BASE LIMIT SIZE NAME 8046000 8048000 2000 [ anon ] 8050000 805c000 c000 /usr/sbin/nscd 806c000 806e000 2000 /usr/sbin/nscd 806e000 80f0000 82000 [ anon ] fd650000 fd655000 5000 /lib/nss_files.so.1 fd665000 fd666000 1000 /lib/nss_files.so.1 fd680000 fd690000 10000 [ anon ] fd6a0000 fd79e000 fe000 [ anon ] fd7a0000 fd89e000 fe000 [ anon ] ... 14.3.1. Constructing the Process StackUnlike examining the kernel, where we would ordinarily use the stack-related mdb commands like ::stack or ::findstack, we need to use stack pointers to traverse a process stack. In this case, nscd is an x86 32-bit application. So a "stack pointer + 0x38" and a "stack pointer + 0x3c" shows the stack pointer and the program counter of the previous frame. /* * In the Intel world, a stack frame looks like this: * * %fp0->| | * |-------------------------------| * | Args to next subroutine | * |-------------------------------|-\ * %sp0->| One-word struct-ret address | | * |-------------------------------| > minimum stack frame * %fp1->| Previous frame pointer (%fp0)| | * |-------------------------------|-/ * | Local variables | * %sp1->|-------------------------------| * * For amd64, the minimum stack frame is 16 bytes and the frame pointer must * be 16-byte aligned. */ struct frame { greg_t fr_savfp; /* saved frame pointer */ greg_t fr_savpc; /* saved program counter */ }; #ifdef _SYSCALL32 /* * Kernel's view of a 32-bit stack frame. */ struct frame32 { greg32_t fr_savfp; /* saved frame pointer */ greg32_t fr_savpc; /* saved program counter */ }; See sys/stack.h Each individual stack frame is defined as follows: /* * In the x86 world, a stack frame looks like this: * * |---------------------------| * 4n+8(%ebp) ->| argument word n | * | ... | (Previous frame) * 8(%ebp) ->| argument word 0 | * |---------------------------|-------------------- * 4(%ebp) ->| return address | * |---------------------------| * 0(%ebp) ->| previous %ebp (optional) | * |---------------------------| * -4(%ebp) ->| unspecified | (Current frame) * | ... | * 0(%esp) ->| variable size | * |---------------------------| */ See sys/stack.h We can explore the stack frames from Section 14.2.4. > ffffffff866f1878::walk thread |::print kthread_t t_lwp->lwp_regs|::print "struct regs" r_rsp |=X 8047d54 fecc9f80 febbac08 fea9df78 fe99df78 fe89df78 fe79df78 fe69df78 fe59df78 fe49df78 fe39df58 fe29df58 fe19df58 fe09df58 fdf9df58 fde9df58 fdd9df58 fdc9df58 fdb9df58 fda9df58 fd99df58 fd89d538 fd79bc08 > 8047d54/X 0x8047d54: fedac74f > fedac74f/ libc.so.1'pause+0x67: 8e89c933 = xorl %ecx,%ecx > febbac08/X 0xfebbac08: feda83ec > feda83ec/ libc.so.1'_door_return+0xac: eb14c483 = addl $0x14,%esp > fea9df78/X 0xfea9df78: fedabe4c > fedabe4c/ libc.so.1'_sleep+0x88: 8908c483 = addl $0x8,%esp Thus, we observe user stacks of pause(), door_return(), and sleep(), as we expected. 14.3.2. Examining the Process MemoryIn the process context, we can examine process memory as usual. For example, we can dissasemble instructions from a processes's address space: > libc.so.1'_sleep+0x88::dis libc.so.1'_sleep+0x67: pushq $-0x13 libc.so.1'_sleep+0x69: call -0x5cb59 <0xfed4f2d4> libc.so.1'_sleep+0x6e: addl $0x4,%esp libc.so.1'_sleep+0x71: movl %esp,%eax libc.so.1'_sleep+0x73: movl %eax,0x22c(%rsi) libc.so.1'_sleep+0x79: leal 0x14(%rsp),%eax libc.so.1'_sleep+0x7d: pushq %rax libc.so.1'_sleep+0x7e: leal 0x10(%rsp),%eax libc.so.1'_sleep+0x82: pushq %rax libc.so.1'_sleep+0x83: call +0xc419 <0xfedb8260> libc.so.1'_sleep+0x88: addl $0x8,%esp libc.so.1'_sleep+0x8b: movl %edi,0x22c(%rsi) libc.so.1'_sleep+0x91: movb 0xb3(%rsi),%cl libc.so.1'_sleep+0x97: movb %cl,0xb2(%rsi) libc.so.1'_sleep+0x9d: jmp +0x14 <libc.so.1'_sleep+0xb1> libc.so.1'_sleep+0x9f: leal 0x14(%rsp),%eax libc.so.1'_sleep+0xa3: pushq %rax libc.so.1'_sleep+0xa4: leal 0x10(%rsp),%eax libc.so.1'_sleep+0xa8: pushq %rax libc.so.1'_sleep+0xa9: call +0xc3f3 <0xfedb8260> libc.so.1'_sleep+0xae: addl $0x8,%esp |