您的位置 首页 java

如何最快找出复杂代码运行时的函数调用流程

如何最快找出复杂代码运行时的函数调用流程

概述

最近在使用freeswitch测试发送DTMF码的时候,碰到一个函数调用流程的问题。

fs本身的模块较多,注册回调函数也比较多且复杂,有时候看到一条日志,却不知道流程的发起端在哪里。

通常我们在梳理代码调用流程的时候有几种方法。

1, 梳理源代码流程,代码太复杂的时候效果差。

2, 在调用函数中打印日志,代码太复杂的时候效果差。

3, 通过backtrace函数追踪当前堆栈,改动多,细节多。

4, gdb调试,命令复杂难记。

今天突然想到一个偷懒的办法,比上面几种方法都要快速简单。

环境

centos7

freeswitch 1.6.19

gcc version 4.8.5

起源

fs的日志如下,简单来看,在dialplan中调用了sleep之后,rtp流程开始发送DTMF。

 EXECUTE sofia/external/1001@10.55.55.138:5080 sleep(5000)
2022-06-17 14:42:54.890047 [DEBUG] switch_rtp.c:5237 Send start packet for [1] ts=160 dur=160/160/2000 seq=8238 lw=160  

但是rtp的调用过程隔的太远,源代码看了好久也没看出来所以然,主要是菜。

修改源代码

首先找到“switch_rtp.c:5237”的位置,修改源代码,增加一行断言判定。

 switch_assert(FALSE);  

重新对fs编译安装。

测试

启动fs,并执行测试命令,日志如下。

 freeswitch@localhost.localdomain> originate {originator_codec=PCMA,origination_caller_id_number=0755110}sofia/external/sip:1001@10.55.55.138:5080 1001 XML ext_test
…
EXECUTE sofia/external/1001@10.55.55.138:5080 sleep(5000)
freeswitch: src/switch_rtp.c:5236: do_2833: Assertion `0' failed.
Aborted  

哈,和设想的一样,fs程序coredump了

core堆栈

在bin目录下找到core文件

 -rw-------. 1 root root 71778304 Jun 17 15:24 core.14650  

使用gdb打开core文件,并显示堆栈。

 sudo gdb freeswitch core.14650
…
(gdb) bt
#0 0x00007f0b9e371387 in raise () from /lib64/libc.so.6
#1 0x00007f0b9e372a78 in abort () from /lib64/libc.so.6
#2 0x00007f0b9e36a1a6 in __assert_fail_base () from /lib64/libc.so.6
#3 0x00007f0b9e36a252 in __assert_fail () from /lib64/libc.so.6
#4 0x00007f0ba0e8be2a in do_2833 (rtp_session=rtp_session@entry=0x7f0b1c012d98) at src/switch_rtp.c:5236
#5 0x00007f0ba0e8d4fb in rtp_common_read (rtp_session=rtp_session@entry=0x7f0b1c012d98, payload_type=payload_type@entry=0x7f0b34040aa4 "", pmapP=pmapP@entry=0x7f0b34040ac8, flags=flags@entry=0x7f0b34040ab8, io_flags=io_flags@entry=0) at src/switch_rtp.c:7321
#6 0x00007f0ba0e8e59f in switch_rtp_zerocopy_read_frame (rtp_session=0x7f0b1c012d98, frame=frame@entry=0x7f0b34040a60, io_flags=io_flags@entry=0) at src/switch_rtp.c:7617
#7 0x00007f0ba0e41990 in switch_core_media_read_frame (session=session@entry=0x7f0b3402f3b8, frame=frame@entry=0x7f0b482795d8, flags=flags@entry=0, stream_id=stream_id@entry=0, type=type@entry=SWITCH_MEDIA_TYPE_AUDIO) at src/switch_core_media.c:2219
#8 0x00007f0b984f1298 in sofia_read_frame (session=0x7f0b3402f3b8, frame=0x7f0b482795d8, flags=0, stream_id=0) at mod_sofia.c:1044
#9 0x00007f0ba0e2a5d6 in switch_core_session_read_frame (session=session@entry=0x7f0b3402f3b8, frame=frame@entry=0x7f0b482795d8, flags=flags@entry=0, stream_id=stream_id@entry=0) at src/switch_core_io.c:188
#10 0x00007f0ba0ec426d in switch_ivr_sleep (session=session@entry=0x7f0b3402f3b8, ms=ms@entry=5000, sync=sync@entry=SWITCH_TRUE, args=args@entry=0x7f0b48279850) at src/switch_ivr.c:294
#11 0x00007f0b7273d5c4 in sleep_function (session=0x7f0b3402f3b8, data=<optimized out>) at mod_dptools.c:2288
#12 0x00007f0ba0e2472b in switch_core_session_exec (session=session@entry=0x7f0b3402f3b8, application_interface=application_interface@entry=0x1ccfcd8, arg=arg@entry=0x7f0b34053240 "5000") at src/switch_core_session.c:2802
#13 0x00007f0ba0e24cb9 in switch_core_session_execute_application_get_flags (session=session@entry=0x7f0b3402f3b8, app=0x7f0b34053238 "sleep", arg=0x7f0b34053240 "5000", flags=flags@entry=0x0) at src/switch_core_session.c:2672
#14 0x00007f0ba0e28ae4 in switch_core_standard_on_execute (session=0x7f0b3402f3b8) at src/switch_core_state_machine.c:353
#15 switch_core_session_run (session=0x7f0b3402f3b8) at src/switch_core_state_machine.c:650
#16 0x00007f0ba0e21f7e in switch_core_session_thread (thread=<optimized out>, obj=0x7f0b3402f3b8) at src/switch_core_session.c:1648
#17 0x00007f0ba0e1dc73 in switch_core_session_thread_pool_worker (thread=0x7f0b3404f340, obj=<optimized out>) at src/switch_core_session.c:1711
#18 0x00007f0ba10d8b10 in dummy_worker (opaque=0x7f0b3404f340) at threadproc/unix/thread.c:151
#19 0x00007f0b9ede5ea5 in start_thread () from /lib64/libpthread.so.0
#20 0x00007f0b9e439b0d in clone () from /lib64/libc.so.6
(gdb)  

啧啧,清晰的函数调用流程,一览无余。

总结

fs的模块比较多,代码调用链大都比较长,涉及到媒体方面流程更是复杂难以跟踪。

剑走偏锋,独辟蹊径。

空空如常

求真得真

文章来源:智云一二三科技

文章标题:如何最快找出复杂代码运行时的函数调用流程

文章地址:https://www.zhihuclub.com/178278.shtml

关于作者: 智云科技

热门文章

网站地图