Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
B
brpc
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
brpc
Commits
95339cbd
Unverified
Commit
95339cbd
authored
Dec 20, 2019
by
Ge Jun
Committed by
GitHub
Dec 20, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #903 from lorinlee/bthread-tool
tools: add gdb_bthread_stack.py
parents
4cb13348
f3d46b7a
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
243 additions
and
0 deletions
+243
-0
gdb_bthread_stack.py
tools/gdb_bthread_stack.py
+243
-0
No files found.
tools/gdb_bthread_stack.py
0 → 100644
View file @
95339cbd
#!/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
\t
tid
\t
function
\t
has 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\t
tid
\t\t
function
\t\t
has stack
\t\t\t
total:{}"
.
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}
\n
rsp: 0x{:x}
\n
rbp: 0x{:x}
\n
rbx: 0x{:x}
\n
r15: 0x{:x}
\n
r14: 0x{:x}
\n
r13: 0x{:x}
\n
r12: 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
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment