xUnwind is a collection of Android native stack unwinding solutions.
- Support unwinding by:
- CFI (Call Frame Info): Provided by Android system library.
- EH (Exception handling GCC extension): Provided by compiler.
- FP (Frame Pointer): ARM64 only.
- Support unwinding from:
- Current execution position.
- A specified context (which may be obtained from a signal handler).
- Support unwinding for process:
- Local process.
- Remote process: CFI only.
- Support unwinding for thread(s):
- Current thread.
- Specified thread: CFI only.
- All threads: CFI only.
- Provide java method to get native backtrace directly in java code.
- Support Android 4.1 - 13 (API level 16 - 33).
- Support armeabi-v7a, arm64-v8a, x86 and x86_64.
- MIT licensed.
xUnwind is published onMaven Central,and usesPrefabpackage format fornative dependencies,which is supported byAndroid Gradle Plugin 4.0+.
android{
buildFeatures {
prefabtrue
}
}
dependencies{
implementation'io.github.hexhacking:xunwind:2.0.0'
}
NOTE:
- Starting from version
2.0.0
of xUnwind, group ID changed fromio.hexhacking
toio.github.hexhacking
.
version range | group ID | artifact ID | Repository URL |
---|---|---|---|
[1.0.1, 1.1.1] | io.hexhacking | xunwind | repo |
[2.0.0, ) | io.github.hexhacking | xunwind | repo |
- xUnwind uses theprefab package schema v2,which is configured by default sinceAndroid Gradle Plugin 7.1.0.If you are using Android Gradle Plugin earlier than 7.1.0, please add the following configuration to
gradle.properties
:
android.prefabVersion=2.0.0
If you only use the java interface of xUnwind, please skip this step.
CMakeLists.txt
find_package(xunwindREQUIREDCONFIG)
add_library(mylibSHAREDmylib.c)
target_link_libraries(mylib xunwind::xunwind)
Android.mk
include $(CLEAR_VARS)
LOCAL_MODULE:= mylib
LOCAL_SRC_FILES:= mylib.c
LOCAL_SHARED_LIBRARIES += xunwind
include $(BUILD_SHARED_LIBRARY)
$(call import-module,prefab/xunwind)
android{
defaultConfig {
ndk {
abiFilters'armeabi-v7a','arm64-v8a','x86','x86_64'
}
}
}
If you are using xUnwind in an SDK project, you may need to avoid packaging libxunwind.so into your AAR, so as not to encounter duplicate libxunwind.so file when packaging the app project.
android{
packagingOptions {
exclude'**/libxunwind.so'
}
}
On the other hand, if you are using xUnwind in an APP project, you may need to add some options to deal with conflicts caused by duplicate libxunwind.so file.
android{
packagingOptions {
pickFirst'**/libxunwind.so'
}
}
There is a sample app in thexunwind-samplefolder you can refer to.
#include"xunwind.h"
#defineXUNWIND_CURRENT_PROCESS(-1)
#defineXUNWIND_CURRENT_THREAD(-1)
#defineXUNWIND_ALL_THREADS(-2)
voidxunwind_cfi_log(pid_tpid,pid_ttid,void*context,constchar*logtag,android_LogPrioritypriority,constchar*prefix);
voidxunwind_cfi_dump(pid_tpid,pid_ttid,void*context,intfd,constchar*prefix);
char*xunwind_cfi_get(pid_tpid,pid_ttid,void*context,constchar*prefix);
These three functions correspond to three ways of obtaining backtrace. They are:
log
to Android logcat.dump
to a place associated with FD (such as file, pipe, socket, etc.).get
and return a string (which is allocated on the heap withmalloc()
,you need tofree()
it yourself).
Thepid
parameter is used to specify the backtrace of which process needs to be obtained, which can be the current process (XUNWIND_CURRENT_PROCESS
/getpid()
) or another process.
Thetid
parameter is used to specify the backtrace of which thread or threads need to be obtained, which can be the current thread (XUNWIND_CURRENT_THREAD
/gettid()
), a specified thread, or all threads (XUNWIND_ALL_THREADS
).
The optionalcontext
parameter is used to pass a register context information. For example, in signal handler, you may need to start unwinding from a specific context.
The optionalprefix
parameter is used to specify a prefix string for each line of backtrace.
size_txunwind_fp_unwind(uintptr_t*frames,size_tframes_cap,void*context);
size_txunwind_eh_unwind(uintptr_t*frames,size_tframes_cap,void*context);
voidxunwind_frames_log(uintptr_t*frames,size_tframes_sz,constchar*logtag,android_LogPrioritypriority,constchar*prefix);
voidxunwind_frames_dump(uintptr_t*frames,size_tframes_sz,intfd,constchar*prefix);
char*xunwind_frames_get(uintptr_t*frames,size_tframes_sz,constchar*prefix);
Currently, FP unwinding is ARM64 only.
xunwind_fp_unwind
andxunwind_eh_unwind
saves the absolute-PCs of the unwinding result in the array pointed to byframes
(frames_cap
is the size of the array), and returns the number of absolute-PCs actually obtained.
The meaning of the optionalcontext
parameter is the same as that of CFI unwinding.
The remaining three functions are used to convert the absolute-PCs in theframes
array into backtrace (the size of the array is specified byframes_sz
). Same as CFI unwinding, respectively output to Android logcat, FD, and return as a string.
importio.github.hexhacking.xunwind.XUnwind;
publicstaticvoidinit();
The only thinginit()
does isSystem.loadLibrary( "xunwind" )
.If you only use xUnwind in native code, no initialization is required.
publicstaticvoidlogLocalCurrentThread(Stringlogtag,intpriority,Stringprefix);
publicstaticvoidlogLocalThread(inttid,Stringlogtag,intpriority,Stringprefix);
publicstaticvoidlogLocalAllThread(Stringlogtag,intpriority,Stringprefix);
publicstaticvoidlogRemoteThread(intpid,inttid,Stringlogtag,intpriority,Stringprefix);
publicstaticvoidlogRemoteAllThread(intpid,Stringlogtag,intpriority,Stringprefix);
publicstaticvoiddumpLocalCurrentThread(intfd,Stringprefix);
publicstaticvoiddumpLocalThread(inttid,intfd,Stringprefix);
publicstaticvoiddumpLocalAllThread(intfd,Stringprefix);
publicstaticvoiddumpRemoteThread(intpid,inttid,intfd,Stringprefix);
publicstaticvoiddumpRemoteAllThread(intpid,intfd,Stringprefix);
publicstaticStringgetLocalCurrentThread(Stringprefix);
publicstaticStringgetLocalThread(inttid,Stringprefix);
publicstaticStringgetLocalAllThread(Stringprefix);
publicstaticStringgetRemoteThread(intpid,inttid,Stringprefix);
publicstaticStringgetRemoteAllThread(intpid,Stringprefix);
All native CFI unwinding capabilities have corresponding java functions. They call the native CFI unwinding functions through JNI.
FP and EH unwinding do not have corresponding java functions. Because compared to CFI unwinding, their main advantage is faster execution speed (but the backtrace is not as complete as CFI unwinding), so they are always only used in native code. If you are a java programmer, just use the CFI unwinding functions here.
xUnwind is MIT licensed, as found in theLICENSEfile.
xCrash 2.xcontains a set of methodsxcc_unwind_*to get backtrace, which is used to try to get backtrace directly from the signal handler when the dumper child process fails. Now we have improved and expanded this set of functions so that they can be used in more scenarios.