如何使用jdb调试android的java程序

如何使用jdb调试android的java程序

习惯了gdb,总觉得eclipse太过臃肿,各种不爽。看到李先静写了一篇“用jdb/jdbshell调试android程序“(http://www.limodev.cn/blog/archives/1281),用了下,感觉比eclipse舒服多了。jdb的命令有那么点别扭,先静写了个jdbshell,加入了命令历史和命令别名(几个常用的gdb命令)。

下面是一个简单的how to,以调试browser应用为例

1)下载jdbshell并编译

www.limodev.cn/blog/?dl_name=jdbshell.tar.gz

因为我基本上每次一开始都要执行threads变量,所以我在开始wile循环前加了一句话

else
{
close(parent_to_child[0]);
                write(parent_to_child[1], "threads\n",strlen("threads\n")); 
while(1)
{
int i = 0;
line = readline ("");

                       ...

                  }

        }

                        

编译后将jdbshell放到~/bin,或者将目录加到PATH里

出现无法打开readline.h的话,安装libreadline6和libreadline6-dev


2)仿照gdbclient,在build/envsetup.sh中加入jdbclient函数

function jdbclient()
{
    local MY_SRC_PATH="$1"
    if [ "$MY_SRC_PATH" ] ; then
        MY_SRC_PATH=$1
        echo $MY_SRC_PATH
    else
        echo "ROOT" $OUR_ROOT
        MY_SRC_PATH="app_process"
    fi


    local PORT="$2"
    if [ "$PORT" ] ; then
        PORT=$2
    else
        PORT=":9000"
    fi


    local PID
    local PROG="$3"
    if [ "$PROG" ] ; then
        PID=`pid $3`
        echo tcp$PORT jdwp$PID
        adb forward "tcp$PORT" "jdwp:$PID"
        echo jdbshell -sourcepath $MY_SRC_PATH -attach localhost$PORT 
        jdbshell -sourcepath $MY_SRC_PATH -attach localhost$PORT 
        sleep 2
    else
        echo ""
        echo "please specify app you want to debug:"
        echo ""
    fi
}


3)启动android模拟器,运行浏览器


4)jdbclient packets/app/Browser/src/ :9000 browser
第一个参数是你要load进来的代码的地址,如果你要load多个代码(调试的时候可以看),可以
export DEBUG_SRC_PATH=
然后
jdbclient $DEBUG_SRC_PATH :9000 browser


第二个参数是attach端口,如果9000有在用,可以用其他端口
第三个参数是要调试的应用,脚本里面根据
pid browser来取得进程id,所以你要保证
adb shell ps |grep browser
能够看到对应的进程

比如我在~/.bashrc里面,设定了DEBUG_SRC_PATH

export ANDROID_SRC=/home/tom/work/gingerbread
export DEBUG_SRC_PATH=$ANDROID_SRC/frameworks/base/opengl/java:$ANDROID_SRC/frameworks/base/awt/java:$ANDROID_SRC/frameworks/base/core/java:$ANDROID_SRC/frameworks/base/location/java:$ANDROID_SRC/frameworks/base/sax/java:$ANDROID_SRC/frameworks/base/graphics/java:$ANDROID_SRC/frameworks/base/telephony/java:$ANDROID_SRC/frameworks/base/services/java:$ANDROID_SRC/frameworks/base/media/java:$ANDROID_SRC/frameworks/base/wifi/java:$ANDROID_SRC/frameworks/base/im/java:$ANDROID_SRC/dalvik/libcore/suncompat/src/main/java:$ANDROID_SRC/dalvik/libcore/nio_char/src/main/java:$ANDROID_SRC/dalvik/libcore/nio_char/src/main/java/java:$ANDROID_SRC/dalvik/libcore/security-kernel/src/main/java:$ANDROID_SRC/dalvik/libcore/security-kernel/src/main/java/java:$ANDROID_SRC/dalvik/libcore/security/src/main/java:$ANDROID_SRC/dalvik/libcore/security/src/main/java/java:$ANDROID_SRC/dalvik/libcore/archive/src/main/java:$ANDROID_SRC/dalvik/libcore/archive/src/main/java/java:$ANDROID_SRC/dalvik/libcore/awt-kernel/src/main/java:$ANDROID_SRC/dalvik/libcore/awt-kernel/src/main/java/java:$ANDROID_SRC/dalvik/libcore/luni/src/main/java:$ANDROID_SRC/dalvik/libcore/luni/src/main/java/java:$ANDROID_SRC/dalvik/libcore/math/src/main/java:$ANDROID_SRC/dalvik/libcore/math/src/main/java/java:$ANDROID_SRC/dalvik/libcore/x-net/src/main/java:$ANDROID_SRC/dalvik/libcore/openssl/src/main/java:$ANDROID_SRC/dalvik/libcore/dalvik/src/main/java:$ANDROID_SRC/dalvik/libcore/auth/src/main/java:$ANDROID_SRC/dalvik/libcore/concurrent/src/main/java:$ANDROID_SRC/dalvik/libcore/concurrent/src/main/java/java:$ANDROID_SRC/dalvik/libcore/sql/src/main/java:$ANDROID_SRC/dalvik/libcore/sql/src/main/java/java:$ANDROID_SRC/dalvik/libcore/prefs/src/main/java:$ANDROID_SRC/dalvik/libcore/prefs/src/main/java/java:$ANDROID_SRC/dalvik/libcore/xml/src/main/java:$ANDROID_SRC/dalvik/libcore/text/src/main/java:$ANDROID_SRC/dalvik/libcore/text/src/main/java/java:$ANDROID_SRC/dalvik/libcore/luni-kernel/src/main/java:$ANDROID_SRC/dalvik/libcore/luni-kernel/src/main/java/java:$ANDROID_SRC/dalvik/libcore/regex/src/main/java:$ANDROID_SRC/dalvik/libcore/regex/src/main/java/java:$ANDROID_SRC/dalvik/libcore/nio/src/main/java:$ANDROID_SRC/dalvik/libcore/nio/src/main/java/java:$ANDROID_SRC/dalvik/libcore/json/src/main/java:$ANDROID_SRC/dalvik/libcore/crypto/src/main/java:$ANDROID_SRC/dalvik/libcore/icu/src/main/java:$ANDROID_SRC/dalvik/libcore/annotation/src/main/java:$ANDROID_SRC/dalvik/libcore/annotation/src/main/java/java:$ANDROID_SRC/dalvik/libcore/junit/src/main/java:$ANDROID_SRC/dalvik/libcore/logging/src/main/java:$ANDROID_SRC/dalvik/libcore/logging/src/main/java/java:$ANDROID_SRC/dalvik/libcore-disabled/instrument/src/main/java:$ANDROID_SRC/dalvik/libcore-disabled/instrument/src/main/java/java:$ANDROID_SRC/dalvik/libcore-disabled/sound/src/main/java:packages/apps/Browser/src/


5)显示如下信息,说明调试器启动
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
Initializing jdb ...
Group system:
  (java.lang.Thread)0xc14050d0c0                  <6> Compiler             cond. waiting
  (java.lang.Thread)0xc14050cf50                  <4> Signal Catcher       cond. waiting
  (java.lang.Thread)0xc14050cea8                  <3> GC                   cond. waiting
  (java.lang.Thread)0xc14050cdf0                  <2> HeapWorker           cond. waiting
Group main:
  (java.lang.Thread)0xc14001f1a8                  <1> main                 running
  (java.lang.Thread)0xc140562ad8                  <21> AsyncTask #5        cond. waiting
  (android.os.HandlerThread)0xc1405528f8          <20> WebViewWorkerThread running
  (android.net.http.ConnectionThread)0xc14053a780 <19> http3               cond. waiting
  (android.net.http.ConnectionThread)0xc14053a5a8 <18> http2               cond. waiting
  (android.net.http.ConnectionThread)0xc140530f90 <17> http1               cond. waiting
  (android.net.http.ConnectionThread)0xc140530da0 <16> http0               cond. waiting
  (java.lang.Thread)0xc14058c008                  <15> Thread-18           running
  (java.lang.Thread)0xc140593370                  <14> AsyncTask #4        cond. waiting
  (java.lang.Thread)0xc140595dd0                  <13> AsyncTask #3        cond. waiting
  (java.lang.Thread)0xc14058f9f0                  <12> AsyncTask #2        cond. waiting
  (java.lang.Thread)0xc14055a820                  <11> WebViewCoreThread   running
  (java.lang.Thread)0xc140591bc8                  <10> AsyncTask #1        cond. waiting
  (java.lang.Thread)0xc140589710                  <9> CookieSyncManager    running
  (java.lang.Thread)0xc14050f288                  <8> Binder Thread #2     running
  (java.lang.Thread)0xc14050e900                  <7> Binder Thread #1     running


6)选择感兴趣的线程
大部分应用跑在main线程里面,browser也不例外
命令 thread 线程ID

> thread 0xc14001f1a8
<1> main[1] 


7)挂起线程
命令 suspend 线程ID
<1> main[1] suspend 0xc14001f1a8


8)设置断点
命令:
stop at <类>:<行号> 或
stop in <类>.<方法名>[(参数类型,...)]


<1> main[1] stop at com.android.browser.BrowserActivity:2689
Set breakpoint com.android.browser.BrowserActivity:2689

这个地方要写类名稍微麻烦一点,哪位大虾可以转化成像gdb那样,直接文件名?


9)继续执行
命令 c(ont)

<1> main[1] c



10)点击网页中的某一个链接
就会看到程序在BrowserActivty:2689(shouldOverideUrlLoading)处断住了
此时可以看堆栈
命令:bt/wherei
<1> main[1]bt
  [1] com.android.browser.BrowserActivity.shouldOverrideUrlLoading (BrowserActivity.java:2,689), pc = 8
  [2] com.android.browser.Tab$2.shouldOverrideUrlLoading (Tab.java:552), pc = 44
  [3] android.webkit.CallbackProxy.uiOverrideUrlLoading (CallbackProxy.java:216), pc = 19
  [4] android.webkit.CallbackProxy.handleMessage (CallbackProxy.java:323), pc = 347
  [5] android.os.Handler.dispatchMessage (Handler.java:99), pc = 20
  [6] android.os.Looper.loop (Looper.java:123), pc = 75
  [7] android.app.ActivityThread.main (ActivityThread.java:3,683), pc = 31
  [8] java.lang.reflect.Method.invokeNative (native method)
  [9] java.lang.reflect.Method.invoke (Method.java:507), pc = 18
  [10] com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:839), pc = 11
  [11] com.android.internal.os.ZygoteInit.main (ZygoteInit.java:597), pc = 84
  [12] dalvik.system.NativeStart.main (native method)


看代码 
命令:l(ist)
<1> main[1] l
2,685            }
2,686        }
2,687    
2,688        boolean shouldOverrideUrlLoading(WebView view, String url) {
2,689 =>         if (url.startsWith(SCHEME_WTAI)) {
2,690                // wtai://wp/mc;number
2,691                // number=string(phone-number)
2,692                if (url.startsWith(SCHEME_WTAI_MC)) {
2,693                    Intent intent = new Intent(Intent.ACTION_VIEW,
2,694                            Uri.parse(WebView.SCHEME_TEL +


看变量
命令:print
<1> main[1] print url
 url = "http://m.baidu.com/img?tn=bdidxiphone&ssid=0&from=844b&bd_page_type=1&uid=wiaui_1320452293_7438&pu=sz%401320_480&itj=41"


继续执行
s(tep) – 执行当前行
step up – 执行到当前方法返回到其调用程序
s(tep)i – 执行当前指令
n(ext) – 跳过一行(跨过调用)
c(ont) – 从断点处继续执行


不说了,help是一种美德
<1> main[1] help
** command list **
connectors                -- list available connectors and transports in this VM


run [class [args]]        -- start execution of application's main class


threads [threadgroup]     -- list threads
thread <thread id>        -- set default thread
suspend [thread id(s)]    -- suspend threads (default: all)
resume [thread id(s)]     -- resume threads (default: all)
where [<thread id> | all] -- dump a thread's stack
wherei [<thread id> | all]-- dump a thread's stack, with pc info
up [n frames]             -- move up a thread's stack
down [n frames]           -- move down a thread's stack
kill <thread id> <expr>   -- kill a thread with the given exception object
interrupt <thread id>     -- interrupt a thread


print <expr>              -- print value of expression
dump <expr>               -- print all object information
eval <expr>               -- evaluate expression (same as print)
set <lvalue> = <expr>     -- assign new value to field/variable/array element
locals                    -- print all local variables in current stack frame


classes                   -- list currently known classes
class <class id>          -- show details of named class
methods <class id>        -- list a class's methods
fields <class id>         -- list a class's fields


threadgroups              -- list threadgroups
threadgroup <name>        -- set current threadgroup


stop in <class id>.<method>[(argument_type,...)]
                          -- set a breakpoint in a method
stop at <class id>:<line> -- set a breakpoint at a line
clear <class id>.<method>[(argument_type,...)]
                          -- clear a breakpoint in a method
clear <class id>:<line>   -- clear a breakpoint at a line
clear                     -- list breakpoints
catch [uncaught|caught|all] <class id>|<class pattern>
                          -- break when specified exception occurs
ignore [uncaught|caught|all] <class id>|<class pattern>
                          -- cancel 'catch' for the specified exception
watch [access|all] <class id>.<field name>
                          -- watch access/modifications to a field
unwatch [access|all] <class id>.<field name>
                          -- discontinue watching access/modifications to a field
trace [go] methods [thread]
                          -- trace method entries and exits.
                          -- All threads are suspended unless 'go' is specified
trace [go] method exit | exits [thread]
                          -- trace the current method's exit, or all methods' exits
                          -- All threads are suspended unless 'go' is specified
untrace [methods]         -- stop tracing method entrys and/or exits
step                      -- execute current line
step up                   -- execute until the current method returns to its caller
stepi                     -- execute current instruction
next                      -- step one line (step OVER calls)
cont                      -- continue execution from breakpoint


list [line number|method] -- print source code
use (or sourcepath) [source file path]
                          -- display or change the source path
exclude [<class pattern>, ... | "none"]
                          -- do not report step or method events for specified classes
classpath                 -- print classpath info from target VM


monitor <command>         -- execute command each time the program stops
monitor                   -- list monitors
unmonitor <monitor#>      -- delete a monitor
read <filename>           -- read and execute a command file


lock <expr>               -- print lock info for an object
threadlocks [thread id]   -- print lock info for a thread


pop                       -- pop the stack through and including the current frame
reenter                   -- same as pop, but current frame is reentered
redefine <class id> <class file name>
                          -- redefine the code for a class


disablegc <expr>          -- prevent garbage collection of an object
enablegc <expr>           -- permit garbage collection of an object


!!                        -- repeat last command
<n> <command>             -- repeat command n times
# <command>               -- discard (no-op)
help (or ?)               -- list commands
version                   -- print version information
exit (or quit)            -- exit debugger


<class id>: a full class name with package qualifiers
<class pattern>: a class name with a leading or trailing wildcard ('*')
<thread id>: thread number as reported in the 'threads' command
<expr>: a Java(tm) Programming Language expression.
Most common syntax is supported.


Startup commands can be placed in either "jdb.ini" or ".jdbrc"
in user.home or user.dir

如果要看别名映射,在终端执行

tom@tom-laptop:~/work/gingerbread$ jdbshell
usage: jdbshell [jdb args]
example: ./jdbshell -sourcepath $ANDROID_SRC_PATH -attach 6107
command alias:
c -- cont
l -- list
n -- next
r -- run
s -- step
si -- stepi
f -- step up
bt -- wherei


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值