Debugging applications with Intel® SDE

Debugging Applications with Intel ® SDE

Using the system debugger to directly debug applications that runs under Intel SDE will result in debugging SDE and not the application. Intel SDE provides the means to use the standard system debugger to debug applications with emulated instructions that run with Intel SDE.

Quick Links:


Debugging Emulated Code on Windows*

 

Starting with Intel SDE version 5.38, we support debugging with emulated instructions and registers when using Microsoft Visual Studio 2012*. You can compile your application with earlier versions of Visual Studio if required. But to use the debugging features with SDE, you must use Microsoft Visual Studio 2012.  Installing the MSI on the Intel SDE download page adds the required support for debugging.

The Intel SDE extensions to MSVS give you the following new features:

  • The ability to launch a debug session under SDE.
  • An extension to the standard MSVS disassembly window that knows about the new instructions. You can set breakpoints and single-step over new instructions.
  • A new emulated register window that displays the new register values that are emulated by SDE. The values can be displayed in various formats.
  • A new “SDE console” window which can be used to pass additional commands to SDE for debugging.

Prerequisites:

  • Windows 7 (or windows server 2008)
  • Visual Studio 2012 – You can use any of the editions (Ultimate, Professional, etc.), except the Express edition. Also, make sure you have an RTM release.
  • Installing the latest SDE kit (5.38 or later)

Instructions: First, install the prerequisites listed above.  Then, do the following to enable debugging with SDE: 

  • If you do not already have an MSVS project file, you must create one.  I typically create an empty project and specify the executable that I want to debug in the “Application Command” property.  Also set the “Application Command Arguments”, if you have any. 
  • Under Debug->Options and Settings...->Intel® SDE Debugger, set the “SDE Kit Directory” property to point to the root of your (unpacked) SDE kit.  There is a <Browse> option that allows you to choose the directory with the file browser.  Click OK to save your changes.
  • Open the project properties. At the top of the project properties there is a drop-down labeled “Debugger to launch”.  Change this drop-down to “SDE Debugger”. 
  • If you have a pre-built executable, you can replace the Application Command field with the path to your executable.
  • Click OK to save your changes.
  • Before starting the debugger, you probably want to set some breakpoints in your application.  Do this by opening a source file in MSVS, navigate to a line, and press F9.  When you are ready, start debugging either by pressing F5 or by clicking on
  • Once a debugger session is started, you can view the emulated registers and see the emulated instructions.  Open the Emulated Registers window by choosing “DEBUG->Windows->Emulated Registers” in the IDE.  You can change the output format for individual register by right clicking.  Open the disassembly window by choosing “DEBUG->Windows->Disassembly”.
  • By right clicking on a register, you can change its display format to various signed/unsigned integer widths, single, double, hex and binary.
  • In the SDE console window, you have various lower level options for talking to SDE using the same command syntax we use with GDB on Linux.  Open this window by choosing “DEBUG->Windows->Intel(R) SDE Console”.

Known issues and limitations of the Intel SDE debugging feature on Windows*:

  1. You cannot attach to running processes.
  2.  You cannot use the "Express" edition of MSVS; It does not support the required extensions. You cannot use windbg; It does not support the required APIs

 


 

Debugging Emulated Code on Linux*

For Intel SDE version 6.7 and later, you must use the new version of gdb available in the attachments section at the lower section of Intel SDE main article. This version of gdb provides an XML protocol for communication between Intel SDE and the debugger. 

In general you need two windows to do this.
In window #1:

% sde -debug -- yourapp

In window #2

% gdb yourapp

Then from within gdb, you issue a "target remote :portnumber" where "portnumber" is the number shown in window #1. Don't forget the colon before the port number. This gdb is internally using python, therefore you must set the PYTHONHOME environment variable to the home of a python 2.7 (one is provided with the same gdb package).

Debugging Example

In one window:

% sde-external-6.7.0-2013-09-21-lin/sde -mpx-mode -debug -- mpx-test 
Application stopped until continued from debugger.
Start GDB, then issue this command at the (gdb) prompt:

  target remote :48617 

In another window:

gdb mpx-test
GNU gdb (GDB) 7.5-4.0.61
Copyright (C) 2010 Free Software Foundation, Inc; (C) 2013 Intel Corp.
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".
For information about how to find Technical Support, Product Updates,
User Forums, FAQs, tips and tricks, and other support information, please visit:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /nfs/iil/ptl/bistro/atal/tmp/SDE/mpx-test...done.

(gdb) target remote :48617
Remote debugging using :48617
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
0x00002aaaaaaabb00 in _start () from /lib64/ld-linux-x86-64.so.2

(gdb) break main
Breakpoint 1 at 0x4007b0

Here we set a breakpoint in the main of our application.

(gdb) c
Continuing.
Breakpoint 1, 0x00000000004007b0 in main ()
(gdb) x/20i $pc
=> 0x4007b0 <main+4>:   sub    $0x30,%rsp
   0x4007b4 <main+8>:   mov    %edi,-0x18(%rbp)
   0x4007b7 <main+11>:  bndstx %bnd0,-0x10(%rbp,%rsi,1)
   0x4007bc <main+16>:  mov    %rsi,-0x10(%rbp)
   0x4007c0 <main+20>:  movl   $0x11,-0x24(%rbp)
   0x4007c7 <main+27>:  movl   $0x0,-0x20(%rbp)
   0x4007ce <main+34>:  mov    $0x1,%eax
   0x4007d3 <main+39>:  add    -0x20(%rbp),%eax
   0x4007d6 <main+42>:  mov    %eax,-0x1c(%rbp)
   0x4007d9 <main+45>:  mov    -0x1c(%rbp),%eax
   0x4007dc <main+48>:  mov    %eax,-0x20(%rbp)
   0x4007df <main+51>:  mov    -0x1c(%rbp),%eax
   0x4007e2 <main+54>:  test   %eax,%eax
   0x4007e4 <main+56>:  bnd je 0x400811 <main+101>
   0x4007e7 <main+59>:  lea    -0x30(%rbp),%rax
   0x4007eb <main+63>:  bndmk  0x9(%rax),%bnd0
   0x4007f0 <main+68>:  mov    -0x20(%rbp),%edx
   0x4007f3 <main+71>:  movslq %edx,%rdx
   0x4007f6 <main+74>:  add    %rdx,%rax
   0x4007f9 <main+77>:  bndcl  %rax,%bnd0

Show the disassembly of the main function. This function has some MPX instructions.
Set a breakpoint before the "bndmk" instruction at address 0x4007eb.

(gdb) b *0x4007eb
Breakpoint 2 at 0x4007eb
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00000000004007b7 in main ()

The SIGSEGV signal that we see here is due to the execution of the "bndstx" instruction at address 0x4007b7. This signal is handled by the MPX runtime library.

(gdb) c
Continuing.
Breakpoint 2, 0x00000000004007eb in main ()
(gdb) x/i $pc
=> 0x4007eb <main+63>:  bndmk  0x9(%rax),%bnd0

Stop before the execution of the "bndmk" instruction and see the initial value of the bnd0 register.

(gdb) p/x $bnd0
$1 = {lbound = 0x0, ubound = 0xffffffffffffffff} : size -1
(gdb) si
0x00000000004007f0 in main ()

After a single step, we see that the value has changed.

(gdb) p/x $bnd0
$2 = {lbound = 0x7fffffffdcf0, ubound = 0x7fffffffdcf9} : size 10

To print all the bnd registers in hex:

(gdb) monitor bnd-get-regs
bnd0: 0xffff800000002306_00007fffffffdcf0
bnd1: 0x0000000000000000_0000000000000000
bnd2: 0x0000000000000000_0000000000000000
bnd3: 0x0000000000000000_0000000000000000

One can also query Intel SDE to disassemble things using XED. This is a request for disassembly of 30 bytes at the indicated address:

(gdb) monitor xdis 0x4007f0 30

XDIS 0000004007f0: BASE 8B55E0          mov edx, dword ptr [rbp-0x20]
XDIS 0000004007f3: LONGMODE 4863D2      movsxd rdx, edx
XDIS 0000004007f6: BASE 4803C2          add rax, rdx
XDIS 0000004007f9:  MPX F3480F1AC0      bndcl bnd0, rax
XDIS 0000004007fe:  MPX F2480F1AC0      bndcu bnd0, rax
XDIS 000000400803: BASE C60041          mov byte ptr [rax], 0x41
XDIS 000000400806: BASE 8B45E0          mov eax, dword ptr [rbp-0x20]
XDIS 000000400809: BASE 8B55DC          mov edx, dword ptr [rbp-0x24]
XDIS 00000040080c: BASE 3BC2            cmp eax, edx

Debugging applications with AVX-512 code

As in the previous example, to debug applications with AVX-512 code you need two windows.

In the first window run Intel SDE:

sde-external-6.7.0-2013-09-21-lin/sde -knl -debug -- vgatherdps.exe
 
Application stopped until continued from debugger.

Start GDB, then issue this command at the (gdb) prompt:
    target remote :60738

In the second window run GDB supporting AVX-512.

% gdb vgatherdps.exe
GNU gdb (GDB) 7.5-4.0.61
Copyright (C) 2010 Free Software Foundation, Inc; (C) 2013 Intel Corp.
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".
For information about how to find Technical Support, Product Updates,
User Forums, FAQs, tips and tricks, and other support information, please visit:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /nfs/iil/disks/sde/atal/SDE/SKY/sde/tests/uisatest/skylake/homebrew/vgatherdps.exe...done. 

Type the target remote command from the other windows.

(gdb) target remote :60738
Remote debugging using :60738
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2

0x00002aaaaaaaba80 in _start () from /lib64/ld-linux-x86-64.so.2

Now you can type GDB commands and debug your application.

(gdb) break main
Breakpoint 1 at 0x400618: file vgatherdps.c, line 40.

(gdb) cont
Continuing.
Breakpoint 1, main ()
    at vgatherdps.c:40
40      int main() {

(gdb) list
35          if ((uint32_t) *v1 == (uint32_t) *v2)
36            return 1;
37          return 0;
38      }
39
40      int main() {
41          int i = 0;
42          uint64_t z = 0;
43          uint16_t mask_result = 0xffff;
44          data_t indices,output;

(gdb) list 58
53
54          __asm {
55              // make k1 = all 1s
56              kxnorw k1, k1, k1
57              lea REG, base
58              vmovdqu32  zmm2, indices
59              vgatherdps  zmm1{k1}, [REG+zmm2*4]
60              vmovdqu32  output, zmm1
61              kmovw [mask_result],k1
62          }

Now set a breakpoint at line 59, and examine the ZMM register content before the execution of the instruction.

(gdb) b 59
Breakpoint 2 at 0x400703: file vgatherdps.c, line 59.

(gdb) c
Continuing.
Breakpoint 2, main ()
    at vgatherdps.c:59
59              vgatherdps  zmm1{k1}, [REG+zmm2*4]

(gdb) p/x $zmm1
$1 = {v16_float = {0x0 <repeats 16 times>}, v8_double = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  v64_int8 = {0x0 <repeats 64 times>}, v32_int16 = {0x0 <repeats 32 times>}, v16_int32 = {
    0x0 <repeats 16 times>}, v8_int64 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, v4_int128 = {
    0x00000000000000000000000000000000, 0x00000000000000000000000000000000,
    0x00000000000000000000000000000000, 0x00000000000000000000000000000000}}

Now execute the single instruction and see how the register content has changed.

(gdb) ni
60              vmovdqu32  output, zmm1

(gdb) disass 0x4006ee,0x400730
Dump of assembler code from 0x4006ee to 0x400730:
   0x000004006ee <main+214>:   kxnorw %k1,%k1,%k1
   0x000004006f2 <main+218>:   lea    -0x10e8(%rbp),%rdx
   0x000004006f9 <main+225>:   vmovdqu32 -0xb0(%rbp),%zmm2
   0x00000400703 <main+235>:   vgatherdps (%rdx,%zmm2,4),%zmm1{%k1}
=> 0x0000040070a <main+242>:   vmovdqu32 %zmm1,-0x70(%rbp)
   0x00000400714 <main+252>:   kmovw  %k1,-0x10f0(%rbp)
   0x0000040071c <main+260>:   movl   $0x0,-0xe8(%rbp)
   0x00000400726 <main+270>:   movl   $0x0,-0x10ec(%rbp)

End of assembler dump.

(gdb) p/x $zmm1
$3 = {v16_float = {0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14},
  v8_double = {0x2000, 0x20000, 0x80000, 0x200000, 0x800002, 0x2000008, 0x4000010, 0x8000020},
  v64_int8 = {0x0, 0x0, 0xa0, 0x40, 0x0, 0x0, 0xc0, 0x40, 0x0, 0x0, 0xe0, 0x40, 0x0, 0x0, 0x0, 0x41, 0x0,
    0x0, 0x10, 0x41, 0x0, 0x0, 0x20, 0x41, 0x0, 0x0, 0x30, 0x41, 0x0, 0x0, 0x40, 0x41, 0x0, 0x0, 0x50,
    0x41, 0x0, 0x0, 0x60, 0x41, 0x0, 0x0, 0x70, 0x41, 0x0, 0x0, 0x80, 0x41, 0x0, 0x0, 0x88, 0x41, 0x0,
    0x0, 0x90, 0x41, 0x0, 0x0, 0x98, 0x41, 0x0, 0x0, 0xa0, 0x41}, v32_int16 = {0x0, 0x40a0, 0x0, 0x40c0,
    0x0, 0x40e0, 0x0, 0x4100, 0x0, 0x4110, 0x0, 0x4120, 0x0, 0x4130, 0x0, 0x4140, 0x0, 0x4150, 0x0,
    0x4160, 0x0, 0x4170, 0x0, 0x4180, 0x0, 0x4188, 0x0, 0x4190, 0x0, 0x4198, 0x0, 0x41a0}, v16_int32 = {
    0x40a00000, 0x40c00000, 0x40e00000, 0x41000000, 0x41100000, 0x41200000, 0x41300000, 0x41400000,
    0x41500000, 0x41600000, 0x41700000, 0x41800000, 0x41880000, 0x41900000, 0x41980000, 0x41a00000},
  v8_int64 = {0x40c0000040a00000, 0x4100000040e00000, 0x4120000041100000, 0x4140000041300000,
    0x4160000041500000, 0x4180000041700000, 0x4190000041880000, 0x41a0000041980000}, v4_int128 = {
    0x4100000040e0000040c0000040a00000, 0x41400000413000004120000041100000,
    0x41800000417000004160000041500000, 0x41a00000419800004190000041880000}} 

You can also use the Intel SDE monitor command for disassembly and for viewing register content.

(gdb) monitor xdis 0x4006ee 46

XDIS 00004006ee: AVX512VEX C5F446C9               kxnorw k1, k1, k1
XDIS 00004006f2: BASE 488D9518EFFFFF              lea rdx, ptr [rbp-0x10e8]
XDIS 00004006f9: AVX512EVEX 62F17E486F9550FFFFFF  vmovdqu32 zmm2, k0, zmmword ptr [rbp-0xb0]
XDIS 0000400703: AVX512EVEX 62F27D49920C92        vgatherdps zmm1, k1, zmmword ptr [rdx+zmm2*4]
XDIS 000040070a: AVX512EVEX 62F17E487F8D90FFFFFF  vmovdqu32 zmmword ptr [rbp-0x70], k0, zmm1
XDIS 0000400714: AVX512VEX C5F8918D10EFFFFF       kmovw word ptr [rbp-0x10f0], k1

(gdb) monitor zmm-get-reg 1

zmm01:  0x41a00000_41980000_41900000_41880000_41800000_41700000_41600000_41500000_
 41400000_41300000_41200000_41100000_41000000_40e00000_40c00000_40a00000
int8:   65 -96 0 0 65 -104 0 0 65 -112 0 0 65 -120 0 0 65 -128 0 0 65 112 0 0 65 96 0 0 65 80 0 0 
 65 64 0 0 65 48 0 0 65 32 0 0 65 16 0 0 65 0 0 0 64 -32 0 0 64 -64 0 0 64 -96 0 0
int16:  16800 0 16792 0 16784 0 16776 0 16768 0 16752 0 16736 0 16720 0 
 16704 0 16688 0 16672 0 16656 0 16640 0 16608 0 16576 0 16544 0
int32:  1101004800 1100480512 1099956224 1099431936 1098907648 1097859072 1096810496 1095761920 
 1094713344 1093664768 1092616192 1091567616 1090519040 1088421888 1086324736 1084227584
int64:  4728779609839501312 4724276010211082240 4719772410582138880 4710765211325300736 
 4701758012068462592 4692750812811624448 4683743613553737728 4665729215040061440
uint8:  65 160 0 0 65 152 0 0 65 144 0 0 65 136 0 0 65 128 0 0 65 112 0 0 65 96 0 0 65 80 0 0 
 65 64 0 0 65 48 0 0 65 32 0 0 65 16 0 0 65 0 0 0 64 224 0 0 64 192 0 0 64 160 0 0
uint16: 16800 0 16792 0 16784 0 16776 0 16768 0 16752 0 16736 0 16720 0 
 16704 0 16688 0 16672 0 16656 0 16640 0 16608 0 16576 0 16544 0
uint32: 1101004800 1100480512 1099956224 1099431936 1098907648 1097859072 1096810496 1095761920 
 1094713344 1093664768 1092616192 1091567616 1090519040 1088421888 1086324736 1084227584
uint64: 4728779609839501312 4724276010211082240 4719772410582138880 
 4710765211325300736 4701758012068462592 4692750812811624448 4683743613553737728 4665729215040061440
float:  20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5
double: 1.34218e+08 6.71089e+07 3.35544e+07 8.38861e+06 2.09715e+06 524288 131072 8192

To see all monitor commands:

(gdb) monitor help sde

xdis ADDRESS NBYTES        - Disassemble NBYTES at ADDRESS
xdis-xml ADDRESS NBYTES    - Disassemble NBYTES at ADDRESS with XML formatting
register-information       - Description of supported registers
bnd-get-regs               - Dump all the BND regs
bnd-get-reg N              - Dump the BND reg N
bndstatus-get-regs         - Dump the BNDSTATUS
bndstatus-get-reg          - Dump the BNDSTATUS
bndcfgu-get-regs           - Dump the BNDCFGU
bndcfgu-get-reg            - Dump the BNDCFGU
bnd-set-reg N UB_LB        - Set the bounds of BND reg N. UB,LB can be empty
bndstatus-set-reg VALUE    - Set the BNDSTATUS
bndcfgu-set-reg VALUE      - Set the BNDCFGU
k-set-reg N VALUE          - Set the mask register N to hex VALUE
zmm-set-reg N VALUE        - Set the ZMM register N to hex VALUE
k-get-regs                 - Dump the mask registers
k-get-reg N                - Dump the mask register N
zmm-get-reg N              - Dump the ZMM register N in various formats
zmm-get-regs               - Dump the ZMM registers in hex

(gdb) cont
Continuing.

[Inferior 1 (Remote target) exited normally]

(gdb)

 


Debugging Emulated Code on Mac OSX*

Staring with Intel SDE version 6.20 and later, you now can use lldb to debug emulated code on Mac OSX. 
Note: the 'monitor' command available when debugging with GDB on Linux is not yet available with lldb.

In general you need two windows to do this.
In window #1:

% sde -debug -- yourapp

In window #2

% lldb yourapp

Then from within lldb, you issue a "gdb-remote portnumber" where "portnumber" is the number shown in window #1. Now you can use you normal lldb commands to debug the application.

Debugging Example

In one window:

% sde-external-6.20.0-2014-02-13-mac/sde -knl -debug -- knl-test 
Application stopped until continued from debugger.
Start LLDB, then issue this command at the (lldb) prompt:
  gdb-remote 53196

In another window:

lldb knl-test
Current executable set to 'knl-test' (x86_64).
(lldb) gdb-remote 53196
Process 7683 stopped
* thread #1: tid = 0x1e03, 0x00007fff69acd028 dyld`_dyld_start, stop reason = signal SIGINT
    frame #0: 0x00007fff69acd028 dyld`_dyld_start
dyld`_dyld_start:
-> 0x7fff69acd028:  pushq  $0
   0x7fff69acd02a:  movq   %rsp, %rbp
   0x7fff69acd02d:  andq   $-16, %rsp
   0x7fff69acd031:  movq   8(%rbp), %rdi
(lldb) b main
Breakpoint 1: where = knl-test`main + 43 at test.c:43, address = 0x00000001000008ab
(lldb) c
Process 7683 resuming
Process 7683 stopped
* thread #1: tid = 0x1e03, 0x0000000109ecc8ab knl-test`main + 43 at test.c:43, stop reason = breakpoint 1.1
    frame #0: 0x0000000109ecc8ab knl-test`main + 43 at test.c:43
   40   int main() {
   41       int i = 0;
   42       uint64_t z = 0;
-> 43       uint16_t mask_result = 0xffff;
   44       data_t indices,output;
   45       for(i=0;i<16;i++)  {
   46           indices.i[i] = i;
(lldb) list
   47       }
   48       float base[1024];
   49       for(i=0;i<1024;i++)  {
   50           base[i]=i + 5;
   51       }
   52
   53
(lldb) list
   54       __asm {
   55           // make k1 = all 1s
   56           kxnorw k1, k1, k1
   57           lea REG, base
   58           vmovdqu32  zmm2, indices
   59           vgatherdps  zmm1{k1}, [REG+zmm2*4]
   60           vmovdqu32  output, zmm1
(lldb) b 60
Breakpoint 2: where = knl-test`main + 202 at test.c:60, address = 0x0000000109ecc94a
(lldb) c
Process 7683 resuming
Process 7683 stopped
* thread #1: tid = 0x1e03, 0x0000000109ecc94a knl-test`main + 202 at test.c:60, stop reason = breakpoint 2.1
    frame #0: 0x0000000109ecc94a knl-test`main + 202 at test.c:60
   57           lea REG, base
   58           vmovdqu32  zmm2, indices
   59           vgatherdps  zmm1{k1}, [REG+zmm2*4]
-> 60           vmovdqu32  output, zmm1
   61           kmovw [mask_result],k1
   62       }
   63
(lldb) register read zmm1
    zmm1 = {0x00 0x00 0x50 0x41 0x00 0x00 0x60 0x41 0x00 0x00 0x70 0x41 0x00 0x00 0x80 0x41 0x00 0x00 0x88 0x41 0x00 0x00 0x90 0x41 0x00 0x00 0x98 0x41 0x00 0x00 0xa0 0x41}
(lldb) register read k1
      k1 = 0x0000000000000000
(lldb)
 
For more complete information about compiler optimizations, see our Optimization Notice.