Use the (engine) source, Luke!

On how to set up debug symbols for Unreal Engine C++ on Macs
Published August 27th, 2023
Jason Tu

One of the great touted benefits of Unreal Engine (over an engine such as Unity¹) is source code access.

That is, when an engine API doesn't work as expected or online documentation fails you — or if you're simply curious how things work — you can trace through engine-level code with a debugger to understand what's actually going on.

All you need is to install the engine source along with debug symbols in the Epic Launcher —  no need to re-build the engine from source:

Epic launcher

Though large in size, debug symbols are worth every byte of disk space.

And you're set! Right?

Sadly, while the buck stops here for Windows users, Mac users may be frustrated to see that debug symbols are not automatically used:

stack trace

I see function names but I don't see source code 😢

That is, if you set a breakpoint on a line in your game's C++ source, the call stack might display function signatures, yet display no line mappings to engine source code. Effectively, the engine remains a black box to you.

The solution?

You need to load those debug symbols somehow, so that lldb (the debugger technology behind all visual debuggers on Macs) knows of them.

Surprisingly, this is not automatic nor is it documented in Unreal's official docs for Mac users, but it is the key to unlocking source code transparency on your Unreal projects.

So here's how to do it 👇

Step 1: Install the source and debug symbols through the Epic Launcher

Open up the Epic Games Launcher, navigate to your Unreal Engine version's install options, and tick the Engine Source and Editor symbols for debugging checkboxes. Then hit apply:

Epic launcher

This will kick off downloads for the engine source code and debug symbols, respectively. At nearly 80 GB, they are hefty (but worthwhile) downloads, so make sure you have disk space available before hitting apply.

It will take a bit of time, so set your Mac to not sleep in your Lock Screen System Settings, and kick off the download before doing some chores (or otherwise).

Step 2: Verify that .dSYM files have been installed

Once both the source code and debug symbols have finished installing, you should verify that those files are present.

For source code, you can run the following command to verify the presence of C++ engine source:

$ cd '/Users/Shared/Epic Games/UE_5.2/Engine/Source'
$ find . -name '*.cpp'

Likewise for debug symbols. Note that the file extension on Macs is .dSYM, not .pdb as it is on Windows:

$ cd '/Users/Shared/Epic Games/UE_5.2/Engine/Binaries/Mac'
$ find . -name '*.dSYM'

Once verified, you can move onto the next step...

Step 3: Understand how .dSYM files work

Sadly, these .dSYM files don't do anything unless you load them. That is, you won't see useful line numbers in your debugging call stacks by default:

image of call stacks with no line numbers

To configure lldb to load your .dSYM files automatically, you need a bit of tribal knowledge. To quote the docs,

Since dSYM files are bundles, you can also place UUID info plists files inside your dSYM bundles in the Contents/Resources directory. One of the main reasons to create the UUID plists inside the dSYM bundles is that it will help LLDB and other developer tools show you source. LLDB currently knows how to check for these plist files so it can automatically remap the source location information in the debug info.

Basically, your .dSYM files currently contain hard-coded paths to source code at their original build location, such as:

/build/Epic Games/UE_5.2/Engine/Source/Runtime/Engine/Private/EngineTypes.cpp

But we should remap those hard-coded paths to point to source code files on your machine:

/Users/Shared/UE_5.2/Engine/Source/Runtime/Engine/Private/EngineTypes.cpp

To perform this remapping, each of your .dSYM files require a bit of additional metadata in the form of .plist XML files. Adding this additional metadata will tell lldb to automatically load your .dSYM files:

plist file example

So let's add the metadata...

Step 4: Configure the remappings in your .dSYM files

There are a lot of .dSYM files in your Unreal Engine install. You can count them:

$ find . -name '*.dSYM' | awk '!/Resources/' | wc -l # prints 1772 on my install

So writing all of these .plist files by hand is out of the question. You need a little script to write these .plist files for you.

Luckily, a developer who goes by intvoker on the Unreal Engine forums has customized a script to do just that. The steps:

  1. Download the (Ruby) script to your machine.
  2. Install the script's dependencies: $ sudo gem install fileutils optimist plist.
  3. At the bottom of the script, customize the default :path and :source_path. For Unreal Engine 5.2, the updated code block will contain these strings at the ends of the lines:
options = Optimist.options do
  opt :path, 'Path to the binaries and dSYMs (e.g. "/Users/Shared/Epic Games/UE_4.23/Engine/Binaries/Mac")', type: :string, default: '/Users/Shared/Epic Games/UE_5.2/Engine/Binaries/Mac'
  opt :source_path, 'Path to the local source directory (e.g. "/Users/Shared/Epic Games/UE_4.23")', type: :string, default: '/Users/Shared/Epic Games/UE_5.2'
end

Then run the script: $ ruby binary_dsym_plist_gen.rb. The script's logs should report your .plist files being generated and placed within the .dSYM bundles' Contents/Resources directories:

plist generation

Once complete, your debug symbols should be ready to go. Let's test it out.

Step 5: Try debugging in your Unreal IDE

With your .dSYM files properly configured for lldb to automatically load them, your call stacks will now map to the underlying engine source. Here's me giving the setup a go in JetBrains Rider:

debugging experience

And you can click on functions within your call stack to understand what's going on in the engine. Nifty, eh? Where the docs lie, the source code tells all.

Conclusion

You don't need to build Unreal from source to use debug symbols.

Yet, while debug symbols Just Work™ on Windows, Mac users need just an extra bit of under-documented configuration.

If you're a Mac user like myself, I hope this allows us to build a deep understanding of our engine technology.

That's all. Until next time!

Resources

Here are some helpful links for further learning:


¹ Unity offers source code access as part of its Source Code offering, but you'd need an enterprise plan/contract to access it. Which is out of reach if you're just getting started. 🔝

If you liked this post, you'll like this too.

I publish blog posts just like this one when I have something to say.

I rarely send out emails, but if you enter your email below, you'll get an email if I decide to announce similar blog posts.