Sent to you by Danny via Google Reader:
via Fred's blog by Fred Chien(錢逢祥) on 9/11/09
自己寫軟體,自己的邏輯,自己的世界,往往不會有什麼困難,這也是很多人從學生時代一路爬上來的歷程,直到進入到職場後撰寫著商業軟體,更是只有自己的一片天。但寫軟體有如寫作文,言之有物前必先廣閱天下文章,否則若是能獨樹一格是好,不能便陳腔濫調且原地踏步。但是看懂別人的程式實在是很困難的一件事,除了要懂他人寫程式的風格和思維外,還要通盤了解架構,這必須要有見山不是山的能力才能勝任。一般人想單靠著程式碼上彎彎曲曲的豆芽菜,反推回去程式的原貌,真有如瞎子摸象。對於做為一般人的我們,這時便要借助些工具,以幫助我們更省時省力的去 Trace 程式碼。
講到閱讀程式碼,『cflow』就是不得不提到的方便工具之一,它能夠幫助我們確認程式的大架構,以及分析程式碼相互的關聯性。這裡是使用 cflow 去演示分析 Android Dalvik VM,分析的檔案是 dalvik/dalvikvm/Main.c:
$ cflow dalvikvm/Main.c main() <int main (int argc,char *const argv[]) at dalvikvm/Main.c:141>: setvbuf() malloc() memset() strdup() strcmp() fprintf() assert() blockSigpipe() <void blockSigpipe () at dalvikvm/Main.c:31>: sigemptyset() sigaddset() sigprocmask() fprintf() JNI_CreateJavaVM() createStringArray() <jobjectArray createStringArray (JNIEnv *env,char *const argv[],int argc) at dalvikvm/Main.c:44>: FindClass() ExceptionCheck() fprintf() assert() NewObjectArray() NewStringUTF() SetObjectArrayElement() DeleteLocalRef() FindClass() GetStaticMethodID() methodIsPublic() <int methodIsPublic (JNIEnv *env,jclass clazz,jmethodID methodId) at dalvikvm/Main.c:92>: ToReflectedMethod() fprintf() FindClass() GetMethodID() CallIntMethod() DeleteLocalRef() CallStaticVoidMethod() ExceptionCheck() DetachCurrentThread() DestroyJavaVM() free()
但是在前一個範例中,很多的 function 並未標示出處,甚至沒有更進一步的資訊,這是因為目前只有對 dalvik/dalvikvm/Main.c 做解析所致,但是我們還是可以一步步將程式碼引入,慢慢尋出一些脈絡,現在假設為了追 JNI_CreateJavaVM(),我們可以多引入其他程式碼檔案(*.c):
$ cflow dalvikvm/Main.c vm/*.c main() <int main (int argc,char *const argv[]) at dalvikvm/Main.c:141>: setvbuf() malloc() memset() strdup() strcmp() fprintf() assert() blockSigpipe() <void blockSigpipe () at dalvikvm/Main.c:31>: sigemptyset() sigaddset() sigprocmask() fprintf() JNI_CreateJavaVM() <jint JNI_CreateJavaVM (JavaVM **p_vm,JNIEnv **p_env,void *vm_args) at vm/Jni.c:3501>: memset() malloc() dvmInitMutex() fprintf() strcmp() strncmp() LOGW() strchr() dvmUseCheckedJniVm() <void dvmUseCheckedJniVm (JavaVMExt *pVm) at vm/CheckJni.c:2422>: assert() dvmCreateJNIEnv() <JNIEnv *dvmCreateJNIEnv (Thread *self) at vm/Jni.c:492>: assert() calloc() dvmSetJniEnvThreadId() dvmUseCheckedJniEnv() <void dvmUseCheckedJniEnv (JNIEnvExt *pEnv) at vm/CheckJni.c:2412>: assert() dvmLockMutex() dvmUnlockMutex() dvmStartup() <int dvmStartup (int argc,const char *const argv[],bool ignoreUnrecognized,JNIEnv *pEnv) at vm/Init.c:910>: assert() LOGV() setCommandLineDefaults() <void setCommandLineDefaults () at vm/Init.c:814>: getenv() strdup() dvmPropertiesStartup() <bool dvmPropertiesStartup (int maxProps) at vm/Properties.c:29>: malloc() dvmProcessOptions() <int dvmProcessOptions (int argc,const char *const argv[],bool ignoreUnrecognized) at vm/Init.c:542>: LOGV() ...(以下省略)
$ cflow dalvikvm/Main.c vm/Jni.c main() <int main (int argc,char *const argv[]) at dalvikvm/Main.c:141>: setvbuf() malloc() memset() strdup() strcmp() fprintf() assert() blockSigpipe() <void blockSigpipe () at dalvikvm/Main.c:31>: sigemptyset() sigaddset() sigprocmask() fprintf() JNI_CreateJavaVM() <jint JNI_CreateJavaVM (JavaVM **p_vm,JNIEnv **p_env,void *vm_args) at vm/Jni.c:3501>: memset() malloc() dvmInitMutex() fprintf() strcmp() strncmp() LOGW() strchr() dvmUseCheckedJniVm() dvmCreateJNIEnv() <JNIEnv *dvmCreateJNIEnv (Thread *self) at vm/Jni.c:492>: assert() calloc() dvmSetJniEnvThreadId() dvmUseCheckedJniEnv() dvmLockMutex() dvmUnlockMutex() dvmStartup() free() dvmChangeStatus() LOGV() createStringArray() <jobjectArray createStringArray (JNIEnv *env,char *const argv[],int argc) at dalvikvm/Main.c:44>: FindClass() <jclass FindClass (JNIEnv *env,const char *name) at vm/Jni.c:1171>: JNI_ENTER() dvmGetCurrentJNIMethod() <const Method *dvmGetCurrentJNIMethod (void) at vm/Jni.c:976>: assert() dvmThreadSelf() SAVEAREA_FROM_FP() dvmIsNativeMethod() ...(以下省略)
$ cflow -m JNI_CreateJavaVM dalvikvm/Main.c vm/Jni.c cflow:vm/Jni.c:3144: gNativeInterface/-1 redefined cflow:vm/Jni.c:221: this is the place of previous definition JNI_CreateJavaVM() <jint JNI_CreateJavaVM (JavaVM **p_vm,JNIEnv **p_env,void *vm_args) at vm/Jni.c:3501>: memset() malloc() dvmInitMutex() fprintf() strcmp() strncmp() LOGW() strchr() dvmUseCheckedJniVm() dvmCreateJNIEnv() <JNIEnv *dvmCreateJNIEnv (Thread *self) at vm/Jni.c:492>: assert() calloc() dvmSetJniEnvThreadId() dvmUseCheckedJniEnv() dvmLockMutex() dvmUnlockMutex() dvmStartup() free() dvmChangeStatus() LOGV()
當然,以上只是演示 cflow 的用法和方便性,並還沒有真的在 Trace Dalvik。透過 cflow 工具的分析,我們可以先行做假設,再針對目標做一步步證明,相較於面對大海茫茫的程式碼而不知從何下手,這卻是一個突破窘境的方法。
Things you can do from here:
- Subscribe to Fred's blog using Google Reader
- Get started using Google Reader to easily keep up with all your favorite sites
No comments:
Post a Comment