你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

Tools / 获取 c 文件函数名的几种方法

[复制链接]
gaosmile 发布时间:2020-8-2 10:23
Tools / 获取 c 文件函数名的几种方法

目录:

1. 方法1: grep 配合正则表达式
0 d: C! a6 E4 @3 H& j" L" f" T2. 方法2: nm 类的调试工具! t. ]1 [# w# ^& [0 q
3. 方法3: 开源软件 ctags9 @0 }+ Z! T* s  D; P4 b% T
4. 使用 list function 的方法简单分析 Linux Input 子系统% T: E! G4 `$ a. {
5. 相关参考
8 s" y0 |/ z! c# X

1. 方法1: grep 配合正则表达式

1) private 函数:

$ grep -E '^(\w+ )?\w+ (\w+ )?\w+( )?\(.*)' SDL_events.c -o | sort | grep static | sort
8 W* Z+ O" A) x/ u) S- d' Zstatic int SDL_AddEvent(SDL_Event *event)
1 H" n( R" m* m( ?7 Sstatic int SDLCALL SDL_GobbleEvents(void *unused)8 ^" Q0 J) D# S' W4 H
static int SDL_CutEvent(int spot)
: V8 R8 s* [8 Q6 ]# Pstatic int SDL_StartEventThread(Uint32 flags)( ~5 g9 R) h2 O% S/ v
static void SDL_StopEventThread(void)9 \& N/ P8 R; K, \! v9 K

2) public 函数:

$ grep -E '^(\w+ )?\w+ (\w+ )?\w+( )?\(.*)' SDL_events.c -o | sort | grep -v static | sort9 l3 W/ H8 C9 x
int SDL_PollEvent (SDL_Event *event)) d- Z; x$ {/ r) Q- z8 j" ]( b
...
, o! Q7 s9 d% x# z: @" Fint SDL_WaitEvent (SDL_Event *event)1 e, q9 J- A. L  q- G, m
SDL_EventFilter SDL_GetEventFilter(void)
, w& m! y! Y  K' E. R" ]& n1 ?Uint32 SDL_EventThreadID(void)
' b1 c) B( Y- i, Q) i5 R/ _8 IUint8 SDL_EventState (Uint8 type, int state). n! Y- w$ r4 D$ m+ ]
void SDL_Lock_EventThread(void)
2 b. Q" L, x& I. D/ k9 q...
7 M! l9 b' C" B" Z! A" o: a3 dvoid SDL_Unlock_EventThread(void)
' Y9 l% H% F8 n$ Y4 ~0 F: f4 k

3) 优点:

  • 通用性强,基本所有的 Linux 系统都会有 grep 命令;

  • 可以看到函数的完整定义;

    3 l2 n0 J% o9 H8 F# q5 |& l5 o

4) 缺点:

  • 某些情景下无法完全匹配所有的函数定义,例如将函数定义分 2 行来写的情况。/ S/ R+ d6 J6 F) u9 b

2. 方法2: nm 类的调试工具

1) 什么是 nm?

nm 用于检查二进制文件 (包括库,编译后的目标模块,共享目标文件,和独立可执行文件),并显示这些文件的内容,或存储在其中的元信息,特别是符号表。

输出格式:

  • 默认按符号字母序排序;

  • 大写字母表示全局性,小写字母表示局部性;

  • U 表示此符号未定义,C 表示此符号是公共的,T/t 表示此符号在代码段中,D/d 的表示此符号在初始化数据段中,B/b 表示此符号在BSS数据段中;

    6 ~  D" d" a0 v: H

另外,objdump -t 和 readelf -s 也可以查看目标文件的符号表。

2) 例子:
; }2 V* J3 I& R( G5 P+ V下面的例子展示了变量和函数在全局、局部、外部、静态、自动和初始化的不同情况下的不同符号类型。

全局/静态 变量:

int global_var;
8 z- F5 e  p6 c  Qint global_var_init = 26;# i- z' j2 j: a
8 A( h( X4 U9 n
static int static_var;
& e1 V, @7 ?% Q" D( lstatic int static_var_init = 25;& }9 V6 Y0 Y7 T% ~" g9 U8 S" f

5 p9 f4 S0 n) Sextern int extern_var;/ Y* u4 B+ D$ l; S3 j
extern int extern_function(int);
/ k) S4 v( b4 A0 _

静态函数:

static int static_function(int x, int y)
: W) A- ~. J* a/ d  V$ w{& Q1 L. ]' A9 z6 A* C* f
int local_automatic_var;$ O4 A+ ]- H( E) ^( w
5 p2 G: v, T1 m5 a, j* f# f
local_automatic_var = x + y;: {7 a, i( k* r. M) _! R! H
return local_automatic_var;7 q7 e3 s# s& E
}

$ U( @5 G( j, a7 L

全局函数:

int global_function(int p)
- V, x  D. k: k, K: B, l{  m2 U7 O! m) g# B9 S% S- j
static int local_static_var;
& I% Y1 C- r5 d& G3 X2 v static int local_static_var_init=5;9 F2 N* M6 ^% ?2 Z  u$ l( w
- ~, S  y, c2 @: F9 m& _: q
local_static_var = static_function(local_static_var_init, p);
" m$ h: Z. p, {4 [3 d+ Y9 r1 L return local_static_var;" G) ]8 J1 G1 B( [% Q
}2 j' L* n5 ~9 G7 J# t. H4 b

' R7 @5 |( Q! h8 K' w* T# Eint main(int argc, char** argv)
, K7 {% _3 ~2 N{
0 ?; f. a- y' i$ }' {: N3 m static_var = 1;
0 |4 D+ Z( N  z
. I8 N' h! [% r5 o' W global_var = global_function(2);
2 S5 k% n( h) ?. S4 j# k extern_var = extern_function(3);  Z( D* n8 K0 f; {! o
return 0;& |# W1 I) }6 t5 Y- S2 p, D4 J$ l
}
3 M+ K  T* e8 L- u
$ Q; S3 f  c! ~#ifdef __cplusplus5 F2 F1 R9 O3 ~. C
extern "C"1 h; N7 J1 ?+ i
#endif
9 K0 `1 a& h0 G  H( L2 nvoid non_mangled_function(void)
, d2 a' I- D0 a4 X/ u3 _& A* I{8 B4 b2 m/ a% A$ l3 k: n% O2 a
// I do nothing
2 m. \+ z  E1 |8 e* Y}
% F; ~0 M- |/ E

3) private 函数:

$ gcc -c c_obj.c  `. V6 D2 Y5 n. z6 Z* O& o9 a
$ nm c_obj.o | grep " t " | cut -d' ' -f33 ^9 |9 z9 F1 W8 l
static_function
+ p4 b( u: A- @2 Q# o

4) public 函数:

$ gcc -c c_obj.c/ B$ _7 G- m" O. ]/ c# K
$ nm c_obj.o | grep " T " | cut -d' ' -f32 @8 E0 M" t* m5 T, a
global_function$ H- x- k- i0 V. o/ l1 p7 |
main
* N+ I8 [* j( m. H& {. ^non_mangled_function
$ E/ D* q/ x/ e6 p9 d8 m" Z

5) 优点:

  • 可以看到整个文件的所有调试信息,不仅仅是函数列表;

  • 同时适用于C 和 C++;

  • 呈现的是编译后的结果,更加准确可靠,例如不用关心源码中宏定义是否打开。


    & k0 s) L2 v/ q% ~6 P* Q+ j

6) 缺点:

  • 只能对编译后的目标文件进行查看;

  • 目标文件如果被 strip 后,则无法使用该方法。

  • 无法看到完整的函数定义;


    # k1 i2 Y; e$ v9 B9 O. J

3. 方法3: 开源软件 Ctags

1) 什么是 ctags?
0 ~7 g: M. Q6 GCtags 是一个用于从程序源代码树产生索引文件(或tag文件),从而便于文本编辑器来实现快速定位的实用工具。在产生的 tag 文件中,每一个 tag 的入口指向了一个编程语言的对象。这个对象可以是变量定义、函数、类或其他的物件。

Ctags 支持下列的编程语言:
, V$ O& H" p3 X! B9 t) C5 {2 T汇编,AWK, ASP, BETA, Bourne/Korn/Zsh Shell, C, C++, COBOL, Eiffel, Fortran, Java, Lisp, Lua, Make, Pascal, Perl, PHP, Python, REXX, Ruby, S-Lang, Scheme, Tcl, Vim, and YACC。

2) private 函数:

$ ctags -x SDL_events.c | grep function | tr -s ' ' | cut -d' ' -f5- | grep static | sort' w8 y# N" S& u! t+ _# y! u; {

3 z# N3 p  y, K! Pstatic int SDL_AddEvent(SDL_Event *event)
  w! o' [% c# r+ ]# p8 w' qstatic int SDLCALL SDL_GobbleEvents(void *unused)
& S  L( q: i" G$ S8 }static int SDL_CutEvent(int spot)
4 Q0 k6 ~2 S  L8 M! i% x" dstatic int SDL_StartEventThread(Uint32 flags)4 i  F2 M9 f1 O" T
static void SDL_StopEventThread(void)
* Z; a; H! b2 T% x

3) public 函数:

$ ctags -x SDL_events.c | grep function | tr -s ' ' | cut -d' ' -f5- | grep -v static | sort
% G4 {+ o0 Q: ~) ^$ u7 w/ ~# c' @/ O8 b
) P+ Q' I' E0 @. rint SDL_PeepEvents(SDL_Event *events, int numevents, SDL_eventaction action,
) u4 _2 ]/ F+ Dint SDL_PollEvent (SDL_Event *event)
1 z3 y8 I2 w6 J9 G5 Y1 ?* W' r% J' x...
+ e& _4 H& q( Lint SDL_WaitEvent (SDL_Event *event)
# \4 ^3 a8 R. D, q! FSDL_EventFilter SDL_GetEventFilter(void)
8 k5 T% P- X/ L! U$ W- P/ |..." H8 d- x% M3 a# j7 I
void SDL_Lock_EventThread(void)* L/ e1 O5 S/ H7 R2 h7 Z
...) K9 h3 T# L& W6 h" O
void SDL_Unlock_EventThread(void)

' O$ `7 ?* F  K/ M, `

4) 优点:

  • 支持多语言;

  • 可以看到函数的完整定义;

  • Ctags 不是编译器也不是预处理器,它的解析能力是有限的;

      K! U  Z' i. A5 Z  h7 |1 @

5) 缺点:

  • 分2行定义的函数无法完整显示:$ ]2 _+ b2 L: @
    int SDL_PeepEvents(SDL_Event *events, int numevents, SDL_eventaction action,
% v. N. \  }0 d( c

6) 我有必要了解 ctags 的内部实现吗?

  • 并不十分清楚 Ctags 使用何种技术来解析内容,估计包括正则表达式、词法分析、语法分析。日后如果工作对上述知识点有需求的话,应该也是一个很不错的学习资料,暂时不深入学习,/ k3 h, c8 n1 R

4. 使用 list function 的方法简单分析 Linux Input 子系统

先是发散思维,Linux input 的整体框架大致如下:

微信图片_20200802102223.png
linux-input-overview

然后慢慢专注在自己关心的内容上,例如我想多了解一下input core的内容,我就去查看它提供了什么 API:

$ ctags -x input.c | grep function | tr -s ' ' | cut -d' ' -f5- | grep -v static5 k; A/ r  ^3 r  ]8 W$ ~
struct input_dev *devm_input_allocate_device(struct device *dev)
; K$ [6 h% ]. R( }# p5 Jvoid input_alloc_absinfo(struct input_dev *dev)) I. N; L4 w  o9 ^+ y, w. U
struct input_dev *input_allocate_device(void), R6 [9 X( U$ E8 I' Z+ i( r
...
5 C7 p8 O" x+ avoid input_free_device(struct input_dev *dev)) n  U+ F% ^6 }- F5 Y
void input_free_minor(unsigned int minor)' [+ q  j( H  \2 C8 @1 d, R
...
$ L3 A( c7 m# l0 s1 `6 l1 s/ mbool input_match_device_id(const struct input_dev *dev,
- S; ^9 Z! j$ d% Q% l5 m* Aint input_open_device(struct input_handle *handle)3 [+ H6 {6 `) l: @* b
int input_register_device(struct input_dev *dev)
7 p  f/ I7 D# K1 c3 F3 rint input_register_handle(struct input_handle *handle)& _+ o8 c( P2 Q7 ?: [: }
int input_register_handler(struct input_handler *handler)- `" O( X0 P& q9 a) _- }
void input_release_device(struct input_handle *handle)$ I0 A0 ]) e7 L' e3 E: r, v
...
% d: Y* a* g6 F) z4 G3 \void input_unregister_device(struct input_dev *dev)" ?! a7 t/ n1 F- d% F% M6 [
void input_unregister_handle(struct input_handle *handle)9 X) L5 y7 H3 w  ~, x: p' [
void input_unregister_handler(struct input_handler *handler)
) m% U+ E' F7 U% Z: Z

然后就可以重点去阅读上述函数了。


5. 相关参考
  • nm wiki

  • Ctags wiki


    * J$ b' Y- s  n
赞 收藏 评论0 发布时间:2020-8-2 10:23

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版