Developer Zone

Advanced Software Development with MATLAB

This is machine translation

Translated by Microsoft
Mouseover text to see original. Click the button below to return to the English version of the page.

MEX Debugging. Redefined.

Posted by Andy Campbell,

Folks, today I'd like to introduce a new guest blogger Martijn Aben. Martijn is a support engineer out of our Netherlands office who daydreams about MATLAB's connections to the external world. As part of that he as a great story to tell about how he has integrated with Microsoft's applauded VS Code IDE. Take it away Martijn!

As a MathWorks Technical Support Engineer specializing, among other things, in the MATLAB "external interfaces" areas, I regularly work with MATLAB users having some difficulties with their custom written MEX-files. Sometimes the MEX-files do not produce the expected result, and sometimes they completely crash MATLAB. This can happen because MEX-files are native libraries which can manipulate the native memory inside MATLAB and even the smallest memory corruption can easily lead to a whole application crashing. While we can’t debug your MEX-file source code for you, this is not part of the support which we offer, we can help you with strategies to debug your code yourself. We can provide some hints and tips on what kind of issues to look out for, we can answer questions on the mxArray- and MEX APIs, and we can help you choose and setup your debug environment, which is what I’d like to talk about in this post.

Choosing your debug environment on Windows has historically been pretty simple. We supported the Microsoft Visual C++ compilers for creating MEX-files and if you used that compiler, Microsoft Visual Studio was the obvious choice for a debugger. In fact, getting started with this debugger is part of the actual in-product documentation.

However, in MATLAB R2015b we started to support the MinGW64 compiler which leverages the gdb debugger, and there are various different front-ends/editors/IDEs which can work with gdb. Immediately after the release of MATLAB R2015b, I wrote up a guide on how to debug using Eclipse, which my colleagues turned into a MATLAB Answer Article. Today in this blog post we are looking into a different tool, which is one of my recent-favorite free development tools: Visual Studio Code (VS Code).

Visual Studio Code

When I first tried Visual Studio Code it was still the preview build. It looked like a nice and sleek code editor but I did not immediately recognize how powerful it can be when extensions are added. I recently rediscovered the tool and its extensibility when doing a little hobby IoT project, which showed me how powerful VS Code really has become. As a MathWorks employee and overall MATLAB fan, I then decided to see whether I could use it for debugging MEX-files as well.

Now before we get to the actual setup and debugging, first a few things you need to know about VS Code. In particular, users of the full-fledged Visual Studio may be wondering how to create a Solution and add Projects to it since these do not exist in VS Code, at least not under those names. To create something similar to a Project you essentially Open a Folder and then organize things together in that Folder. Want to open additional projects next to the one you already have open? Add another Folder to your Workspace. Want to create something similar to a Solution with multiple Projects? Open multiple Folders in your Workspace, then Save this Workspace. Opening a solution has then become opening a workspace.

Another important thing to note is that out-of-the-box VS Code is a powerful code editor for many languages but really only a debugger for Javascript and Typescript running in Node.js. For other languages and runtimes you will need to install the relevant extension(s). Since MATLAB MEX-files are written in C/C++ this means we will need an extension, and that extension is aptly named "C/C++". So let's get started by actually installing this extension. Fire up VS Code and head over to the Extensions section in VS Code:

Find the C/C++ Extension:

And install it using that little green Install button, to fully complete the installation make sure to click the Reload option after the extension was downloaded.

MEX-File Debugging in VS Code

Now that we have a VS Code installation which can debug C/C++ code, let's see how we can configure it for the specific task of debugging MEX-files. We go to the Explorer section of VS Code and then use File -> Open Folder... to start a new Project. In my example here I actually open the folder in which the source code of my MEX-file is located. After opening that folder, named Work in my case, and opening the source code of mymex.c in the editor, VS Code will look something like:

First thing we notice is the #include "mex.h" statement being underlined and we also see some PROBLEMS being reported. You do not actually have to resolve these PROBLEMS to be able to debug most parts of your code but you may want to read up on these "include issues" in the VS Code documentation and then create a c_cpp_properties.json with something like:

{
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "c:/ProgramData/MATLAB/SupportPackages/R2018a/3P.instrset/mingw_w64.instrset/x86_64-w64-mingw32/include",
                "c:/MATLAB/R2018a/extern/include",
                "${workspaceRoot}"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE"
            ],
            "intelliSenseMode": "msvc-x64",
            "browse": {
                "path": [
                    "c:/ProgramData/MATLAB/SupportPackages/R2018a/3P.instrset/mingw_w64.instrset/x86_64-w64-mingw32/include",
                    "c:/MATLAB/R2018a/extern/include",
                    "${workspaceRoot}"
                ],
                "limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            }
        }
    ],
    "version": 3
}

In which we tell VS Code where to find the MinGW64 headers as well as where to find the MATLAB headers. My MATLAB R2018a, which I am working with here, is installed in c:\MATLAB\R2018a, update your paths accordingly. My MinGW64 support package is installed in the default location so in most cases you should be able to re-use the location shown above. However, just in case you run into problems check the footnote at the end of this post to double check this location.

With VS Code all happy now, let's add a Debug configuration. We go to go to Debug -> Add Configuration… and select C++ (GDB/LLDB):

This will create a new launch.json file for us and it should immediately show a menu to add new configurations. Alternatively you can use the Add Configuration… button. Since it is faster/easiest to attach to an already running MATLAB for debugging rather than launching a new one through the debugger, we choose to Add a C/C++: (gdb) Attach configuration:

VS Code then automatically adds a new section to launch.json:

{ 
    "name": "(gdb) Attach",
    "type": "cppdbg",
    "request": "attach",
    "program": "enter program name, for example ${workspaceRoot}/a.exe",
    "processId": "${command:pickProcess}",
    "MIMode": "gdb",
    "miDebuggerPath": "/path/to/gdb"
}

We need to update the program setting to point to MATLAB.exe from the bin/win64 directory of our MATLAB installation and miDebuggerPath to point to the gdb debugger from the MinGW64 Support Package. Also, the gdb debugger tends to stop on all first chance SIGSEGVs, so it actually stops on any thrown SIGSEGV even if that SIGSEGV is going to be caught and dealt with correctly. The JVM inside MATLAB throws these SIGSEGVs on purpose and then catches these as part of its JIT process and we do not want to stop in the debugger every time this happens. To tell the debugger to ignore these SIGSEGVs we add setupCommands which are essentially gdb commands which are automatically run when the debugger is started. All this combined then gives:

{ 
    "name": "(gdb) Attach",
    "type": "cppdbg",
    "request": "attach",
    "program": "c:/MATLAB/R2018a/bin/win64/MATLAB.exe",
    "processId": "${command:pickProcess}",
    "MIMode": "gdb",
    "setupCommands": [
        {
            "text": "handle SIGSEGV nostop"
        },
        {
             "text": "handle SIGSEGV noprint"
        }
    ],
    "miDebuggerPath": "c:/ProgramData/MATLAB/SupportPackages/R2018a/3P.instrset/mingw_w64.instrset/bin/gdb.exe"
}

From there I usually delete the (gdb) Launch configuration which had been added by default as well. That should complete the setup of our project, now we can get to the actual debugging.

Actual Debugging

If you paid closed attention in the screenshots above, you could see that I had already compiled mymex.c into mymex.mexw64, I had prepared this earlier in MATLAB with:

mex -g mymex.c

Where the -g flag disabled optimizations and made sure symbolic information which we need for debugging was added. You will likewise need to build your mex files with this debug information using the -g flag.

So really all we need to do now is place a breakpoint somewhere in the code:

Switch to the debug view

Make sure MATLAB is actually running (we configured VS Code to attach the debugger to an already running MATLAB after all) and we then hit the play button:

Which shows a dialog with running processes where we then choose MATLAB:

VS Code should now be attached to MATLAB and we should see some lines like

[New Thread 18404.0x473c]
[New Thread 18404.0x3294]

in the Debug Console which shows us that the debugger is definitely doing something and is logging information about what MATLAB is doing. We can then switch to our MATLAB session and run the MEX-file:

mymex([1 2 pi 21])

When we do that we will see VS Code will stop on our breakpoint, stepping (F10) a few lines we can then see:

    1. We were able to successfully obtain a pointer to the native input data and the first element had value 1

    2. The size of the input was indeed a 1x4 vector.

We can also step through our for-loop and see:

    1. How i updates with each iteration, here we are at i = 3.

    2. Inspect certain elements in our array in the DEBUG CONSOLE. The screenshot shows that the fourth element in the input is indeed 21, just like we passed in from MATLAB.

To find out what else you can do, read the Debugging Documentation of VS Code.

Conclusion

I realize we did not actually debug and fix any bugs in any super advanced real-world MEX-files here today, but I did show you how you can get started on debugging MEX-files using one of my recent-favorite free development tools and I hope this has inspired you to give this workflow a try if you ever need to debug one of your MinGW64 MEX-files. Happy hunting for those bugs!

Oh, and for you Linux users out there, while the story above is about MinGW64 and Windows, since VS Code is available for Linux as well, you can also apply this workflow on Linux to debug your GCC MEX-files. Obviously some of the paths will be somewhat different, but I am sure you can figure it out; let us know though if you have any further questions on that.

Footnote

    While configuring VS Code we needed the location of the MinGW64 include directory as well as the location of the gdb debugger. When MinGW64 is installed through the support package these locations may be somewhat hidden from you; also the exact locations may vary with different support package versions for different MATLAB releases. So how do you determine those locations? Well, gdb.exe is typically found in the same directory as gcc/g++ which is the actual compiler used for compilation, and you can easily see where the compiler is located if you add the verbose -v flag when compiling your code: mex -g -v mymex.c. In the verbose output, the last few lines show the literal calls that are being made to gcc/g++. If you also want to find the include directory you go one directory up from gcc/g++ and then into x86_64-w64-mingw32 where there will be a directory named include.

Add A Comment

Your email address will not be published. Required fields are marked *

Preview: hide