Upload shared object mapping files to allow BugSnag to de-obfuscate your Android NDK stack traces.
This documentation is for the legacy NDK symbol mapping and symbol mapping table file upload APIs. Where possible we recommend using the latest endpoint, for which documentation can be found here.
For Android applications, when native code is used it will be compiled into shared object files, usually with the symbol names removed.
In order to replace the obfuscated data with a human-readable stack trace, BugSnag requires a shared object mapping file.
If you’re using Android Studio/Gradle to build your Android projects, the best way to send your shared object mapping files to BugSnag is to use our Android Gradle plugin.
If you’re building an Android project from Unity, the best way to send your shared object and symbol table mapping files to BugSnag is to use our Android Gradle plugin for Unity.
In cases where you cannot use our Gradle plugin, you’ll need to manually upload your mapping file to BugSnag using our API.
There are two different types of mapping file that can be used to map a stack trace depending on what debug information is available in the shared object file:
In general the intermediate shared object files generated for an Android NDK build should contain the required details for a symbol mapping file but the shared object files generated for some native Android libraries, for example Unity libraries, will only contain the information for a symbol table mapping file.
To send symbol mapping files to BugSnag, POST them to https://upload.bugsnag.com/so-symbol with the following parameters:
soSymbolFile
- the path to the shared object mapping file.apiKey
- your BugSnag integration API key for this application.appId
- the Android applicationId
for this application.versionCode
- the Android versionCode
for this application release.arch
- the architecture of the shared object that the symbols are for (e.g. x86, armeabi-v7a).sharedObjectName
- the name of the shared object that the symbols are for.versionName
(optional) - the Android versionName
for this application release.projectRoot
(optional) - a path to remove from the beginning of the filenames in the mapping filebuildUUID
(optional) - a UUID to identify this builds. This is required if you build multiple different apps with the same appId
and versionCode
. If you use this, you’ll also need to set the com.bugsnag.android.BUILD_UUID
value in your AndroidManifest.xml
.overwrite
(optional) - overwrite any existing mappings for this version of your app.If you are creating the shared object mapping files without using the BugSnag Android Gradle plugin then you must run the objdump
command with the following parameters, and save the output to a file:
objdump --dwarf=info --dwarf=rawline <path_to_intermediate_so_file> > output_file
Locate the correct objdump
binary for a given architecture using find $ANDROID_HOME/ndk-bundle -iname "*objdump"
on macOS, Linux, and Cygwin.
objdump
is not included in the NDK v23 and up. We recommend using the latest upload endpoint, which is documented here.
The output should look something like:
Contents of the .debug_info section:
Compilation Unit @ offset 0x0:
Length: 0x8417 (32-bit)
Version: 4
Abbrev Offset: 0x0
Pointer Size: 4
<0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
<c> DW_AT_producer : (indirect string, offset: 0x0): Android (4751641 based on r328903) clang version 7.0.2 (https://android.googlesource.com/toolchain/clang 003100370607242ddd5815e4a043907ea9004281) (https://android.googlesource.com/toolchain/llvm 1d739ffb0366421d383e04ff80ec2ee591315116) (based on LLVM 7.0.2svn)
<10> DW_AT_language : 4 (C++)
<12> DW_AT_name : (indirect string, offset: 0x107): /app/src/main/source.cpp
If the output does not look like this it may be due to the objdump
command being run on a shared object file where the debug symbols have been stripped.
The command needs to be run against an intermediate shared object file that is output from the build process before the symbols are stripped.
If the intermediate shared object files don’t produce output like this, it may be the case that the full debug information isn’t available. In some cases (e.g. with native Android Unity libraries) it may be possible to extract the symbol table from the shared object file so that the method names can be mapped. See the Uploading symbol table mapping files section for how to generate and upload these mappings.
The API also supports uploading compressed mapping files. For example, to compress the file using gzip:
objdump --dwarf=info --dwarf=rawline <path_to_intermediate_so_file> \
| gzip -c > output_file.gz
Here’s an example request with curl:
$ curl --http1.1 https://upload.bugsnag.com/so-symbol \
-F soSymbolFile=@/path/to/objdump/output \
-F apiKey=YOUR_API_KEY_HERE \
-F versionCode=123 \
-F appId=com.example.android.app \
-F arch=x86 \
-F sharedObjectName=libmy-ndk-library.so \
-F versionName=2.3.0
If the file is accepted then an HTTP 200 response will be returned with the body “OK”.
If not, there are several possible problems which will be indicated with an HTTP 4XX response:
appId
or versionCode
parameters are missing.--dwarf=info
wasn’t passed to objdump
).--dwarf=rawline
wasn’t passed to objdump
).In some cases the shared object files don’t contain the full debug information required to map back to the original file, line and method but they do contain a symbol table which can be used to map the method. This is normally the case for native Android libraries in Unity.
To send symbol table mapping files to BugSnag, POST them to https://upload.bugsnag.com/so-symbol-table with the following parameters:
soSymbolTableFile
- the path to the shared object symbol table mapping file.apiKey
- your BugSnag integration API key for this application.appId
- the Android applicationId
for this application.versionCode
- the Android versionCode
for this application release.arch
- the architecture of the shared object that the symbols are for (e.g. x86, armeabi-v7a).sharedObjectName
- the name of the shared object that the symbols are for.versionName
(optional) - the Android versionName
for this application release.projectRoot
(optional) - a path to remove from the beginning of the filenames in the mapping filebuildUUID
(optional) - a UUID to identify this builds. This is required if you build multiple different apps with the same appId
and versionCode
. If you use this, you’ll also need to set the com.bugsnag.android.BUILD_UUID
value in your AndroidManifest.xml
.overwrite
(optional) - overwrite any existing mappings for this version of your app.If you are creating the shared object symbol table mapping files without using the BugSnag Android Gradle plugin then you must run the objdump
command with the following parameters, and save the output to a file:
objdump --sym <path_to_intermediate_so_file> > output_file
Locate the correct objdump
binary for a given architecture using find $ANDROID_HOME/ndk-bundle -iname "*objdump"
on macOS, Linux, and Cygwin.
The output should look something like:
SYMBOL TABLE:
0004df48 l F .text 00000010 __on_dlclose
0004df5c l F .text 00000004 __on_dlclose_late
0004ebd8 l F .text 00000018 _ZL24CleanupModule_AndroidJNIv
000524b0 l F .text 00000614 _ZL12GlobalXToTRS23TransformAccessReadOnlyRN4math4trsXE
00052c50 l F .text 00000888 _ZL13TRSToGlobalTR15TransformAccessRKN4math4trsXE
If the output does not look like this it may be due to the objdump
command being run on a shared object file where the all the debug symbols have been stripped. The command needs to be run against an intermediate shared object file that is output from the build process before the symbols are stripped.
For native Android Unity libraries the shared object files with the symbol table within them normally have a .sym.so
file extension
The API also supports uploading compressed mapping files. For example, to compress the file using gzip:
objdump --sym <path_to_intermediate_so_file> | gzip -c > output_file.gz
Here’s an example request with curl:
$ curl --http1.1 https://upload.bugsnag.com/so-symbol-table \
-F soSymbolTableFile=@/path/to/objdump/output \
-F apiKey=YOUR_API_KEY_HERE \
-F versionCode=123 \
-F appId=com.example.android.app \
-F arch=x86 \
-F sharedObjectName=libmy-ndk-library.so \
-F versionName=2.3.0
If the file is accepted then an HTTP 200 response will be returned with the body “OK”.
If not, there are several possible problems which will be indicated with an HTTP 4XX response:
appId
or versionCode
parameters are missing.