This is an automated email from the ASF dual-hosted git repository.

jamesge pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-brpc.git


The following commit(s) were added to refs/heads/master by this push:
     new f3d46b7  tools: add gdb_bthread_stack.py
     new 95339cb  Merge pull request #903 from lorinlee/bthread-tool
f3d46b7 is described below

commit f3d46b7a3f2ec0823259c150c94602520e8d8008
Author: LorinLee <[email protected]>
AuthorDate: Sun Aug 25 18:44:44 2019 +0800

    tools: add gdb_bthread_stack.py
---
 tools/gdb_bthread_stack.py | 243 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 243 insertions(+)

diff --git a/tools/gdb_bthread_stack.py b/tools/gdb_bthread_stack.py
new file mode 100644
index 0000000..582ba9e
--- /dev/null
+++ b/tools/gdb_bthread_stack.py
@@ -0,0 +1,243 @@
+#!/usr/bin/env python
+# coding=utf-8
+
+"""
+Bthread Stack Print Tool
+
+this only for running process, core dump is not supported.
+
+Get Started:
+    1. gdb attach <pid>
+    2. source gdb_bthread_stack.py
+    3. bthread_begin
+    4. bthread_list
+    5. bthread_frame 0
+    6. bt / up / down
+    7. bthread_end
+
+Commands:
+    1. bthread_num: print all bthread nums
+    2. bthread_begin <num>: enter bthread debug mode, `num` is max scanned 
bthreads, default will scan all
+    3. bthread_list: list all bthreads
+    4. bthread_frame <id>: switch stack to bthread, id will displayed in 
bthread_list
+    5. bthread_meta <id>: print bthread meta
+    6. bthread_reg_restore: bthread_frame will modify registers, reg_restore 
will restore them
+    7. bthread_end: exit bthread debug mode
+    8. bthread_regs <id>: print bthread registers
+
+when call bthread_frame, registers will be modified,
+remember to call bthread_end after debug, or process will be corrupted
+
+after call bthread_frame, you can call `bt`/`up`/`down`, or other gdb command
+"""
+
+import gdb
+
+bthreads = []
+status = False
+
+def get_bthread_num():
+    root_agent = 
gdb.parse_and_eval("&(((((*bthread::g_task_control)._nbthreads)._combiner)._agents).root_)")
+    global_res = 
int(gdb.parse_and_eval("((*bthread::g_task_control)._nbthreads)._combiner._global_result"))
+    get_agent = "(*(('bvar::detail::AgentCombiner<long, long, 
bvar::detail::AddTo<long> >::Agent' *){}))"
+    last_node = root_agent
+    while True:
+        agent = gdb.parse_and_eval(get_agent.format(last_node))
+        if last_node != root_agent:
+            val = int(agent["element"]["_value"]["_M_i"])
+            global_res += val
+        if agent["next_"] == root_agent:
+            return global_res
+        last_node = agent["next_"]
+
+def get_all_bthreads(total):
+    global bthreads
+    bthreads = []
+    count = 0
+    groups = 
int(gdb.parse_and_eval("'butil::ResourcePool<bthread::TaskMeta>::_ngroup'")["val"])
+    for group in range(groups):
+        blocks = 
int(gdb.parse_and_eval("(*((*((('butil::static_atomic<butil::ResourcePool<bthread::TaskMeta>::BlockGroup*>'
 *)('butil::ResourcePool<bthread::TaskMeta>::_block_groups')) + 
{})).val)).nblock._M_i".format(group)))
+        for block in range(blocks):
+            items = 
int(gdb.parse_and_eval("(*(*(('butil::atomic<butil::ResourcePool<bthread::TaskMeta>::Block*>'
 
*)((*((*((('butil::static_atomic<butil::ResourcePool<bthread::TaskMeta>::BlockGroup*>'
 *)('butil::ResourcePool<bthread::TaskMeta>::_block_groups')) + 
{})).val)).blocks) + {}))._M_b._M_p).nitem".format(group, block)))
+            for item in range(items):
+                task_meta = gdb.parse_and_eval("*(('bthread::TaskMeta' 
*)((*(*(('butil::atomic<butil::ResourcePool<bthread::TaskMeta>::Block*>' 
*)((*((*((('butil::static_atomic<butil::ResourcePool<bthread::TaskMeta>::BlockGroup*>'
 *)('butil::ResourcePool<bthread::TaskMeta>::_block_groups')) + 
{})).val)).blocks) + {}))._M_b._M_p).items) + {})".format(group, block, item))
+                version_tid = (int(task_meta["tid"]) >> 32)
+                version_butex = gdb.parse_and_eval("*(uint32_t 
*){}".format(task_meta["version_butex"]))
+                if version_tid == int(version_butex) and 
int(task_meta["attr"]["stack_type"]) != 0:
+                    bthreads.append(task_meta)
+                    count += 1
+                    if count >= total:
+                        return
+
+class BthreadListCmd(gdb.Command):
+    """list all bthreads, print format is 'id\ttid\tfunction\thas stack'"""
+    def __init__(self):
+        gdb.Command.__init__(self, "bthread_list", gdb.COMMAND_STACK, 
gdb.COMPLETE_NONE)
+
+    def invoke(self, arg, tty):
+        global status
+        global bthreads
+        if not status:
+            print("Not in bthread debug mode")
+            return
+        print("id\t\ttid\t\tfunction\t\thas 
stack\t\t\ttotal:{}".format(len(bthreads)))
+        for i, t in enumerate(bthreads):
+            print("#{}\t\t{}\t\t{}\t\t{}".format(i, t["tid"], t["fn"], "no" if 
str(t["stack"]) == "0x0" else "yes"))
+
+class BthreadNumCmd(gdb.Command):
+    """list active bthreads num"""
+    def __init__(self):
+        gdb.Command.__init__(self, "bthread_num", gdb.COMMAND_STACK, 
gdb.COMPLETE_NONE)
+
+    def invoke(self, arg, tty):
+        res = get_bthread_num()
+        print(res)
+
+class BthreadFrameCmd(gdb.Command):
+    """bthread_frame <id>, select bthread frame by id"""
+    def __init__(self):
+        gdb.Command.__init__(self, "bthread_frame", gdb.COMMAND_STACK, 
gdb.COMPLETE_NONE)
+
+    def invoke(self, arg, tty):
+        global status
+        global bthreads
+        if not status:
+            print("Not in bthread debug mode")
+            return
+        if not arg:
+            print("bthread_frame <id>, see 'bthread_list'")
+            return
+        bthread_id = int(arg)
+        if bthread_id >= len(bthreads):
+            print("id {} exceeds max bthread nums {}".format(bthread_id, 
len(bthreads)))
+            return
+        stack = bthreads[bthread_id]["stack"]
+        if str(stack) == "0x0":
+            print("this bthread has no stack")
+            return
+        context = gdb.parse_and_eval("(*(('bthread::ContextualStack' 
*){})).context".format(stack))
+        rip = gdb.parse_and_eval("*(uint64_t*)({}+7*8)".format(context))
+        rbp = gdb.parse_and_eval("*(uint64_t*)({}+6*8)".format(context))
+        rsp = gdb.parse_and_eval("{}+8*8".format(context))
+        gdb.parse_and_eval("$rip = {}".format(rip))
+        gdb.parse_and_eval("$rsp = {}".format(rsp))
+        gdb.parse_and_eval("$rbp = {}".format(rbp))
+
+class BthreadRegsCmd(gdb.Command):
+    """bthread_regs <id>, print bthread registers"""
+    def __init__(self):
+        gdb.Command.__init__(self, "bthread_regs", gdb.COMMAND_STACK, 
gdb.COMPLETE_NONE)
+
+    def invoke(self, arg, tty):
+        global status
+        global bthreads
+        if not status:
+            print("Not in bthread debug mode")
+            return
+        if not arg:
+            print("bthread_regs <id>, see 'bthread_list'")
+            return
+        bthread_id = int(arg)
+        if bthread_id >= len(bthreads):
+            print("id {} exceeds max bthread nums {}".format(bthread_id, 
len(bthreads)))
+            return
+        stack = bthreads[bthread_id]["stack"]
+        if str(stack) == "0x0":
+            print("this bthread has no stack")
+            return
+        context = gdb.parse_and_eval("(*(('bthread::ContextualStack' 
*){})).context".format(stack))
+        rip = int(gdb.parse_and_eval("*(uint64_t*)({}+7*8)".format(context)))
+        rbp = int(gdb.parse_and_eval("*(uint64_t*)({}+6*8)".format(context)))
+        rbx = int(gdb.parse_and_eval("*(uint64_t*)({}+5*8)".format(context)))
+        r15 = int(gdb.parse_and_eval("*(uint64_t*)({}+4*8)".format(context)))
+        r14 = int(gdb.parse_and_eval("*(uint64_t*)({}+3*8)".format(context)))
+        r13 = int(gdb.parse_and_eval("*(uint64_t*)({}+2*8)".format(context)))
+        r12 = int(gdb.parse_and_eval("*(uint64_t*)({}+1*8)".format(context)))
+        rsp = int(gdb.parse_and_eval("{}+8*8".format(context)))
+        print("rip: 0x{:x}\nrsp: 0x{:x}\nrbp: 0x{:x}\nrbx: 0x{:x}\nr15: 
0x{:x}\nr14: 0x{:x}\nr13: 0x{:x}\nr12: 0x{:x}".format(rip, rsp, rbp, rbx, r15, 
r14, r13, r12))
+
+class BthreadMetaCmd(gdb.Command):
+    """bthread_meta <id>, print task meta by id"""
+    def __init__(self):
+        gdb.Command.__init__(self, "bthread_meta", gdb.COMMAND_STACK, 
gdb.COMPLETE_NONE)
+
+    def invoke(self, arg, tty):
+        global status
+        global bthreads
+        if not status:
+            print("Not in bthread debug mode")
+            return
+        if not arg:
+            print("bthread_meta <id>, see 'bthread_list'")
+            return
+        bthread_id = int(arg)
+        if bthread_id >= len(bthreads):
+            print("id {} exceeds max bthread nums {}".format(bthread_id, 
len(bthreads)))
+            return
+        print(bthreads[bthread_id])
+
+class BthreadBeginCmd(gdb.Command):
+    """enter bthread debug mode"""
+    def __init__(self):
+        gdb.Command.__init__(self, "bthread_begin", gdb.COMMAND_STACK, 
gdb.COMPLETE_NONE)
+
+    def invoke(self, arg, tty):
+        global status
+        if status:
+            print("Already in bthread debug mode, do not switch thread before 
exec 'bthread_end' !!!")
+            return
+        active_bthreads = get_bthread_num()
+        scanned_bthreads = active_bthreads
+        if arg:
+            num_arg = int(arg)
+            if num_arg < active_bthreads:
+                scanned_bthreads = num_arg
+            else:
+                print("requested bthreads {} more than actived, will display 
{} bthreads".format(num_arg, scanned_bthreads))
+        print("Active bthreads: {}, will display {} 
bthreads".format(active_bthreads, scanned_bthreads))
+        get_all_bthreads(scanned_bthreads)
+        gdb.parse_and_eval("$saved_rip = $rip")
+        gdb.parse_and_eval("$saved_rsp = $rsp")
+        gdb.parse_and_eval("$saved_rbp = $rbp")
+        status = True
+        print("Enter bthread debug mode, do not switch thread before exec 
'bthread_end' !!!")
+
+class BthreadRegRestoreCmd(gdb.Command):
+    """restore registers"""
+    def __init__(self):
+        gdb.Command.__init__(self, "bthread_reg_restore", gdb.COMMAND_STACK, 
gdb.COMPLETE_NONE)
+
+    def invoke(self, arg, tty):
+        global status
+        if not status:
+            print("Not in bthread debug mode")
+            return
+        gdb.parse_and_eval("$rip = $saved_rip")
+        gdb.parse_and_eval("$rsp = $saved_rsp")
+        gdb.parse_and_eval("$rbp = $saved_rbp")
+        print("OK")
+
+class BthreadEndCmd(gdb.Command):
+    """exit bthread debug mode"""
+    def __init__(self):
+        gdb.Command.__init__(self, "bthread_end", gdb.COMMAND_STACK, 
gdb.COMPLETE_NONE)
+
+    def invoke(self, arg, tty):
+        global status
+        if not status:
+            print("Not in bthread debug mode")
+            return
+        gdb.parse_and_eval("$rip = $saved_rip")
+        gdb.parse_and_eval("$rsp = $saved_rsp")
+        gdb.parse_and_eval("$rbp = $saved_rbp")
+        status = False
+        print("Exit bthread debug mode")
+
+BthreadListCmd()
+BthreadNumCmd()
+BthreadBeginCmd()
+BthreadEndCmd()
+BthreadFrameCmd()
+BthreadMetaCmd()
+BthreadRegRestoreCmd()
+BthreadRegsCmd()


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to