Native code - how to get function call stack (backtrace) programatically 附带源代码
自己根据 https://github.com/zhuowei/libcorkscrew-ndk 上的库做了一个包装库并附带使用的例子(executable 分支),具体代码在自己的代码仓库里,名字叫 libbacktrace-ndk.tar。已经完美解决。但是它无法打印没有符号导出的函数(打印出来是 ???),但已经很全了。 如果要吹毛求疵打印call stack所有的函数,这时可以让程序崩溃(用static 变量控制崩溃的index,即调用几次后发生崩溃),根据打印出来的信息,再进行 ndk-stack 的crash log分析,得到某次(index)调用的完整调用栈。 还有另外一种更简便的方法,先用 ndk-stack 一直监听adb 的logcat输出,然后让程序崩溃一次(且仅一次),这时ndk-stack就已经进入crash打印模式(遇到 pc 001f4c18 /data/app-lib/com.csipsimple-2/libpjsipjni.so (unwind_backtrace+112) 即进行分析并打印callstack),以后任何时候调用libcorkscrew-ndk的dump_backtrace()的输出将被ndk-stack解析打印。
http://stackoverflow.com/questions/7710151/native-code-how-to-get-function-call-stack-backtrace-programatically
https://bitbucket.org/xg/android-game-base/src/c0d969d44a55/jni/NativeActivityJNI.cpp?fileviewer=file-view-default#cl-40
https://bitbucket.org/xg/android-game-base/src/c0d969d44a55/src/com/gmail/whittock/tom/Util/NativeActivity.java?fileviewer=file-view-default#cl-91
android-game-base/jni/NativeActivityJNI.cpp
#include <jni.h>
#include <stdlib.h>
#include <signal.h>
#include "NativeActivity.hpp"
#include <android/log.h> #define DO_TRY
#define DO_CATCH(loc) extern "C"
{ static struct sigaction old_sa[NSIG]; static JNIEnv *g_sigEnv;
static jobject g_sigObj;
static jmethodID g_sigNativeCrashed; void android_sigaction(int signal, siginfo_t *info, void *reserved)
{
g_sigEnv->CallVoidMethod(g_sigObj, g_sigNativeCrashed);
old_sa[signal].sa_handler(signal);
} JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv *env = NULL;
if (jvm->GetEnv((void **)&env, JNI_VERSION_1_2))
return JNI_ERR; jclass cls = env->FindClass("com/gmail/whittock/tom/Util/NativeActivity"); g_sigEnv = env;
g_sigNativeCrashed = env->GetMethodID(cls, "onNativeCrashed", "()V"); return JNI_VERSION_1_2;
} JNIEXPORT jint JNICALL
Java_com_gmail_whittock_tom_Util_NativeActivity_nativeOnCreate(JNIEnv *env, jobject this_, jbyteArray savedState)
{
DO_TRY
{
// Try to catch crashes...
g_sigObj = env->NewGlobalRef(this_);
struct sigaction handler;
memset(&handler, , sizeof(struct sigaction)); handler.sa_sigaction = android_sigaction;
handler.sa_flags = SA_RESETHAND;
#define CATCHSIG(X) sigaction(X, &handler, &old_sa[X])
CATCHSIG(SIGILL);
CATCHSIG(SIGABRT);
CATCHSIG(SIGBUS);
CATCHSIG(SIGFPE);
CATCHSIG(SIGSEGV);
CATCHSIG(SIGSTKFLT);
CATCHSIG(SIGPIPE); // Create the C++ activity proxy.
NativeActivity *a = CreateNativeActivity(); // Call onCreate with the savedState bytes.
jbyte *stateBytes = NULL;
jsize stateSize = ;
if (savedState != NULL)
{
stateBytes = env->GetByteArrayElements(savedState, );
stateSize = env->GetArrayLength(savedState);
}
a->onCreate(stateBytes, stateSize);
if (stateBytes)
env->ReleaseByteArrayElements(savedState, stateBytes, JNI_ABORT); return (jint)a;
}
DO_CATCH("onCreate");
} JNIEXPORT jbyteArray JNICALL
Java_com_gmail_whittock_tom_Util_NativeActivity_nativeOnSaveInstanceState(JNIEnv *env, jobject this_, jint handle)
{
DO_TRY {
NativeActivity *a = (NativeActivity*)handle; // Query app for instance data.
void *data = NULL;
int dataLen = ;
a->onSaveInstanceState(&data, &dataLen); // Write instance data out.
jbyteArray outArray = NULL;
if (data)
{
outArray = env->NewByteArray(dataLen);
env->SetByteArrayRegion(outArray, , dataLen, (const jbyte*)data); a->onDeleteInstanceState(data);
}
return outArray;
}
DO_CATCH("onSaveInstanceState")
} JNIEXPORT void JNICALL
Java_com_gmail_whittock_tom_Util_NativeActivity_nativeOnDestroy(JNIEnv *env, jobject this_, jint handle)
{
DO_TRY
{
NativeActivity *a = (NativeActivity*)handle;
a->onDestroy(); // Uninstall the signal handlers.
#define REMOVESIG(X) sigaction(X, &old_sa[X], NULL)
REMOVESIG(SIGILL);
REMOVESIG(SIGABRT);
REMOVESIG(SIGBUS);
REMOVESIG(SIGFPE);
REMOVESIG(SIGSEGV);
REMOVESIG(SIGSTKFLT);
REMOVESIG(SIGPIPE); env->DeleteGlobalRef(g_sigObj);
}
DO_CATCH("onDestroy");
} JNIEXPORT void JNICALL
Java_com_gmail_whittock_tom_Util_NativeActivity_nativeOnPause(JNIEnv *env, jobject this_, jint handle)
{
DO_TRY
{
NativeActivity *a = (NativeActivity*)handle;
a->onPause();
}
DO_CATCH("onPause");
} JNIEXPORT void JNICALL
Java_com_gmail_whittock_tom_Util_NativeActivity_nativeOnResume(JNIEnv *env, jobject this_, jint handle)
{
DO_TRY
{
NativeActivity *a = (NativeActivity*)handle;
a->onResume();
}
DO_CATCH("onResume");
} JNIEXPORT jboolean JNICALL
Java_com_gmail_whittock_tom_Util_NativeActivity_nativeOnTouchEvent(JNIEnv *env, jobject this_, jint handle, jobject ev)
{
DO_TRY
{
NativeActivity *a = (NativeActivity*)handle;
a->onTouchEvent();
}
DO_CATCH("onTouchEvent");
} JNIEXPORT void JNICALL
Java_com_gmail_whittock_tom_Util_NativeActivity_nativeOnDrawFrame(JNIEnv *env, jobject this_, jint handle)
{
DO_TRY
{
NativeActivity *a = (NativeActivity*)handle;
a->onDrawFrame();
}
DO_CATCH("onDrawFrame");
} JNIEXPORT void JNICALL
Java_com_gmail_whittock_tom_Util_NativeActivity_nativeOnSurfaceChanged(JNIEnv *env, jobject this_, jint handle, jint w, jint h)
{
DO_TRY
{
NativeActivity *a = (NativeActivity*)handle;
a->onSurfaceChanged(w, h);
}
DO_CATCH("onSurfaceChanged");
} JNIEXPORT void JNICALL
Java_com_gmail_whittock_tom_Util_NativeActivity_nativeOnSurfaceCreated(JNIEnv *env, jobject this_, jint handle)
{
DO_TRY
{
NativeActivity *a = (NativeActivity*)handle;
a->onSurfaceCreated();
}
DO_CATCH("onSurfaceCreated");
} }
android-game-base/src/com/gmail/whittock/tom/Util/NativeActivity.java
package com.gmail.whittock.tom.Util; import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10; import android.app.Activity;
import android.util.Log;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.MotionEvent; public class NativeActivity extends Activity { private static final String NATIVE_STATE = "NATIVE_STATE";
private static final String META_DATA_LIB_NAME = "LIB_NAME"; private GLSurfaceView mGLView;
private int mNativeHandle; @Override
public void onCreate(Bundle savedInstanceState) { try {
ActivityInfo ai = getPackageManager().getActivityInfo(getIntent().getComponent(), PackageManager.GET_META_DATA);
String libName;
if (ai.metaData != null) {
libName = ai.metaData.getString(META_DATA_LIB_NAME);
System.loadLibrary(libName);
}
else
{
throw new RuntimeException("Can't get meta data");
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException("Error getting activity info", e);
} mGLView = new NativeGLSurfaceView(this);
setContentView(mGLView); byte[] array = null;
if (savedInstanceState != null)
array = savedInstanceState.getByteArray(NATIVE_STATE);
mNativeHandle = nativeOnCreate(array);
Log.e("GameBase", "Post create: " + mNativeHandle); super.onCreate(savedInstanceState);
} @Override
public void onSaveInstanceState(Bundle outState) {
byte[] array = nativeOnSaveInstanceState(mNativeHandle);
if (array != null)
outState.putByteArray(NATIVE_STATE, array);
} @Override
public void onPause() {
super.onPause();
mGLView.onPause();
nativeOnPause(mNativeHandle);
} @Override
public void onResume() {
super.onResume();
mGLView.onResume();
Log.e("GameBase", "Pre resume: " + mNativeHandle);
nativeOnResume(mNativeHandle);
} public boolean onTouchEvent(MotionEvent event) {
return nativeOnTouchEvent(mNativeHandle, event);
} public void onDrawFrame(GL10 gl) {
nativeOnDrawFrame(mNativeHandle);
} public void onSurfaceChanged(GL10 gl, int w, int h) {
nativeOnSurfaceChanged(mNativeHandle, w, h);
} public void onSurfaceCreated(GL10 gl, EGLConfig config) {
nativeOnSurfaceCreated(mNativeHandle);
} public void onNativeCrashed() {
// http://stackoverflow.com/questions/1083154/how-can-i-catch-sigsegv-segmentation-fault-and-get-a-stack-trace-under-jni-on-a
new RuntimeException("crashed here (native trace should follow after the Java trace)").printStackTrace();
startActivity(new Intent(this, CrashHandler.class));
} private native int nativeOnCreate(byte[] savedState); private native byte[] nativeOnSaveInstanceState(int handle); private native void nativeOnDestroy(int handle); private native void nativeOnPause(int handle); private native void nativeOnResume(int handle); private native boolean nativeOnTouchEvent(int handle, MotionEvent ev); private native void nativeOnDrawFrame(int handle); private native void nativeOnSurfaceChanged(int handle, int w, int h); private native void nativeOnSurfaceCreated(int handle); } class NativeGLSurfaceView extends GLSurfaceView {
private NativeActivity mNativeActivity;
private NativeRenderer mRenderer; public NativeGLSurfaceView(NativeActivity nativeActivity) {
super(nativeActivity);
mRenderer = new NativeRenderer(nativeActivity);
mNativeActivity = nativeActivity;
setRenderer(mRenderer);
} public boolean onTouchEvent(final MotionEvent event) {
return mNativeActivity.onTouchEvent(event);
}
} class NativeRenderer implements GLSurfaceView.Renderer { private NativeActivity mNativeActivity; public NativeRenderer(NativeActivity nativeActivity) {
mNativeActivity = nativeActivity;
} public void onSurfaceCreated(GL10 gl, EGLConfig config) {
mNativeActivity.onSurfaceCreated(gl, config);
} public void onSurfaceChanged(GL10 gl, int w, int h) {
mNativeActivity.onSurfaceChanged(gl, w, h);
} public void onDrawFrame(GL10 gl) {
mNativeActivity.onDrawFrame(gl);
}
}
Native code - how to get function call stack (backtrace) programatically 附带源代码的更多相关文章
- [Xamarin] 透過Native Code呼叫 JavaScript function (转帖)
今天我們來聊聊關於如何使用WebView 中的Javascript 來呼叫 Native Code 的部分 首先,你得先來看看這篇[Xamarin] 使用Webview 來做APP因為這篇文章至少講解 ...
- 打印发现function toUpperCase() { [native code] }
var s='hello' undefined s.toUpperCase function toUpperCase() { [native code] } s.toUpperCase() " ...
- GDB + gdbserver 远程调试android native code
原文地址:GDB + gdbserver 远程调试android native code 作者:tq08g2z 以调试模拟器中的native library code为例. Host: ubuntuT ...
- 优秀开源代码解读之JS与iOS Native Code互调的优雅实现方案
简介 本篇为大家介绍一个优秀的开源小项目:WebViewJavascriptBridge. 它优雅地实现了在使用UIWebView时JS与ios 的ObjC nativecode之间的互调,支持消息发 ...
- Hybrid----优秀开源代码解读之JS与iOS Native Code互调的优雅实现方案-备
本篇为大家介绍一个优秀的开源小项目:WebViewJavascriptBridge. 它优雅地实现了在使用UIWebView时JS与ios 的ObjC nativecode之间的互调,支持消息发送.接 ...
- webview的javascript与Native code交互
http://my.oschina.net/u/1376187/blog/172296 项目中使用了webview显示网页,其中需要网页和native方法有交互,搜索到一篇文章,转发分享一下: === ...
- Calling a Java Method from Native Code
http://journals.ecs.soton.ac.uk/java/tutorial/native1.1/implementing/method.html Calling Java Method ...
- native method与so中function的关联
在Android中,可以通过JNI的方式来调用和访问用C/C++实现的代码,这些代码以SharedLibrary的方式存在于so中.从Java Code到Native Code的一般使用过程为: 在J ...
- cordova与ios native code交互的原理
非常早曾经写了一篇博客,总结cordova插件怎么调用到原生代码:cordova调用过程,只是写得太水.基本没有提到原理.近期加深了一点理解,又一次补充说明一下 js调用native 以下是我们产品中 ...
随机推荐
- 利用ZABBIX的RPC-JSON作API扩展应用示例
计划将ZABBIX的一些状态可以在另一个应用的显示GRAPH及链接. 故而在网上找了几个文档,作了一个测试. https://www.zabbix.com/documentation/2.4/manu ...
- 【NOIP 2012 开车旅行】***
题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 ...
- cocos2d-html5 Layer 和 Scene 创建模式
var myLayer = cc.Layer.extend({ init:function() {//2 界面 var bRet = false; if (this._super()) { bRet ...
- SQL Server中时间段查询和数据类型转换
不知道什么时候对数据独有情种,也许是因为所学专业的缘故,也许是在多年的工作中的亲身经历,无数据,很多事情干不了,数据精度不够,也很多事情干不了,有一次跟一个朋友开玩笑说,如果在写论文的时候,能有一份独 ...
- proc 文件系统调节参数介绍
/proc/net/* snmp文件 Ip: ip项 Forwarding : 是否开启ip_forward,1开启,2关闭 DefaultTTL : IP默认ttl. In ...
- Android 完全退出程序,以及再按一次返回键退出程序
再按一次返回键退出最终完整方案: boolean isExit; @Override protected void onCreate(Bundle savedInstanceState) { ...
- vi/vim 基本使用
摘要: 在minicom终端里修改开发板中的文件时,必须要用到vi,因为开发板中并不像开发主机那样,有gedit和kscope这样的编辑器:还有,即便是在开发主机上,也会经常用到vi,因为vi使用起来 ...
- 监控Nginx负载均衡器脚本
1.编写脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 vim nginx_pid.sh #!/bin/bash while : do nginxpid=`ps -C ...
- Linux 性能监测工具总结
前言: Linux系统出现问题时,我们不仅需要查看系统日志信息,而且还要使用大量的性能监测工具来判断究竟是哪一部分(内存.CPU.硬盘……)出了问题.在Linux系统中,所有的运行参数保存在虚拟目录/ ...
- puppy 制作linux
经过一段时间的使用以后,我们每个人电脑里的Puppy Linux都是独一无二的,我们可以通过简单的方法将自己电脑上的Puppy制作成iso或Live-CD,成为自己玩的“Only You”Puppy ...