cro*_*oss 15 c c++ macros perl profiling
背景:
我有一个很大的模拟工具,我需要了解它的逻辑行为.为了做到这一点,如果我有函数调用的时间顺序,我将得到的大部分帮助,用于最小的工作示例.
我在网上找到了很多工具,比如CygProfiler和etrace.我找到了一个解决方案,我开始遵循使用调试器"步入"的最疯狂的解决方案,我变得非常痛苦.如果您有一个小程序但不是一个完整的模拟工具,这是一个很好的选择.
问题:
我面临的一个问题是上面提到的解决方案最初是用于编译时C生成静态文件(*.o).另一方面,模拟工具生成共享库(.so).我对较低级别的东西知之甚少,所以当我尝试链接它们时,我似乎失败了.
我特意看了一下etrace 文档,它说:
要了解如何修改ptrace.c以使用动态库,请查看example2目录.这里的源代码也创建了一个独立的可执行文件,但PTRACE_REFERENCE_FUNCTION宏的定义与动态库一样.
如果你看看repo,文件example和example2文件夹之间没有区别.只有一个额外的.h文件example2.
另一方面,如果你看src/ptrace.c那里它说:
在动态库上使用ptrace时,必须将PTRACE_REFERENCE_FUNCTION宏设置为库中函数的名称.此功能的加载时,地址将线路输出第一跟踪文件,并且允许其他出入境指针的翻译符号名.您可以将宏PTRACE_INCLUDE设置为该函数可访问此源文件所需的任何#include指令.
稍微低于评论代码:
/* When using ptrace on a dynamic library, the following must be defined:
#include "any files needed for PTRACE_REFERENCE_FUNCTION"
#define PTRACE_REFERENCE_FUNCTION functionName
`*/
Run Code Online (Sandbox Code Playgroud)
题:
本质上问题如下:如何使用etrace动态库?
我需要#include任何文件吗?
要跟踪独立程序,不需要#include任何其他文件.只需将代码链接到ptrace.c,并使用-finstrument-functions选项作为gcc的编译选项.这应该做到这一点.
如何链接通过makefile构建的C++代码 ptrace.c
最后的注意事项:如果有人承担我的无知并为我的问题提供逐步解决方案,我将不胜感激.
更新1:
我设法将与etrace相关的库添加到模拟工具中,并且执行正常.
但是,(可能是因为脚本太旧,或者不适合与C++一起使用)在使用默认情况下提供的perl脚本时出现以下错误:etrace
Run Code Online (Sandbox Code Playgroud)Hexadecimal number > 0xffffffff non-portable"
可能这会改变这个问题的性质,在这一点上更多地转向与perl相关的问题.
如果这个问题得到解决,我希望etrace能够处理一个复杂的项目,我会提供详细信息
更新2:
我接受了@Harry的建议,我相信这对大多数项目都有效.但是在我的情况下,我从perl脚本中获得以下内容:
Use of uninitialized value within %SYMBOLTABLE in list assignment at etrace2.pl line 99, <CALL_DATA> line 1.
\-- ???
| \-- ???
\-- ???
| \-- ???
| | \-- ???
\-- ???
| \-- ???
\-- ???
| \-- ???
\-- ???
| \-- ???
\-- ???
| \-- ???
\-- ???
| \-- ???
Run Code Online (Sandbox Code Playgroud)
由于autegenerated makefile我使用LD_PRELOAD加载etrace.so的共享库,我得到如下:
gcc -g -finstrument-functions -shared -fPIC ptrace.c -o etrace.so -I <path-to-etrace>
Run Code Online (Sandbox Code Playgroud)
我在工具中创建了虚拟etrace.h:
#ifndef __ETRACE_H_
#define __ETRACE_H_
#include <stdio.h>
void Crumble_buy(char * what, int quantity, char * unit);
void Crumble_buy(char * what, int quantity, char * unit)
{
printf("buy %d %s of %s\n", quantity, unit, what);
}
#endif
Run Code Online (Sandbox Code Playgroud)
并且使用Crumble_buy了#define与etrace.h对#include.
十六进制数 > 0xffffffff 不可移植”
这是一个警告,hex因为它检测到可能不可移植的值(大于 32 位的值)。
在脚本的最顶部添加以下内容:
use bigint qw/hex oct/;
Run Code Online (Sandbox Code Playgroud)
当这个工具被编写时,我怀疑人们使用的是 32 位机器。您可以使用带有 flag 的 32 位编译程序-m32,但如果您按照上面提到的方式更改 perl 脚本,则不需要这样做。
请注意,如果您使用的是 Mac,则无法使用mknod脚本中使用的方式来创建管道;你需要使用mkfifo不带参数的方法。
在 Linux 上,添加bigint上述修复即可工作。然后,您需要从同一目录运行这两个命令,我使用以下命令执行此操作example2:
../src/etrace.pl crumble
# Switch to a different terminal
./crumble
Run Code Online (Sandbox Code Playgroud)
我在 Mac 和 Linux 上得到了这个
\-- main
| \-- Crumble_make_apple_crumble
| | \-- Crumble_buy_stuff
| | | \-- Crumble_buy
| | | \-- Crumble_buy
| | | \-- Crumble_buy
| | | \-- Crumble_buy
| | | \-- Crumble_buy
| | \-- Crumble_prepare_apples
| | | \-- Crumble_skin_and_dice
| | \-- Crumble_mix
| | \-- Crumble_finalize
| | | \-- Crumble_put
| | | \-- Crumble_put
| | \-- Crumble_cook
| | | \-- Crumble_put
| | | \-- Crumble_bake
Run Code Online (Sandbox Code Playgroud)
当加载动态库时,目标文件中的地址并不是运行时将使用的地址。etrace 的作用是从您指定的标头中获取函数名称。例如,在 的情况下example2,将如下所示:
#include "crumble.h"
#define PTRACE_REFERENCE_FUNCTION Crumble_buy
Run Code Online (Sandbox Code Playgroud)
然后,您将编辑 makefile 以确保可以找到头文件:
CFLAGS = -g -finstrument-functions -I.
Run Code Online (Sandbox Code Playgroud)
请注意添加了 include -I.。标头中的符号地址(在我们的例子中为Crumble_buy)用于计算目标文件和实际地址之间的偏移量;这允许程序计算正确的地址来查找符号。
如果查看 的输出nm,您会得到类似以下内容的内容:
0000000100000960 T _Crumble_bake
00000001000005b0 T _Crumble_buy
0000000100000640 T _Crumble_buy_stuff
00000001000009f0 T _Crumble_cook
Run Code Online (Sandbox Code Playgroud)
左边的地址是相对的,也就是说,在运行时,这些地址实际上会发生变化。etrace.pl 程序将这些存储在哈希中,如下所示:
$VAR1 = {
'4294969696' => '_Crumble_bake',
'4294969424' => '_Crumble_put',
'4294970096' => '_main',
'4294969264' => '_Crumble_mix',
'4294970704' => '_gnu_ptrace_close',
'4294967296' => '__mh_execute_header',
'4294968752' => '_Crumble_buy',
'4294968896' => '_Crumble_buy_stuff',
'4294969952' => '_Crumble_make_apple_crumble',
'4294969184' => '_Crumble_prepare_apples',
'4294971512' => '___GNU_PTRACE_FILE__',
'4294971504' => '_gnu_ptrace.first',
'4294970208' => '_gnu_ptrace',
'4294970656' => '___cyg_profile_func_exit',
'4294970608' => '___cyg_profile_func_enter',
'4294969552' => '_Crumble_finalize',
'4294971508' => '_gnu_ptrace.active',
'4294969840' => '_Crumble_cook',
'4294969088' => '_Crumble_skin_and_dice',
'4294970352' => '_gnu_ptrace_init'
};
Run Code Online (Sandbox Code Playgroud)
请注意前导下划线,因为这是在使用 clang 的 Mac 上。在运行时,这些地址不正确,但它们的相对偏移量是正确的。如果您可以计算出偏移量是多少,则可以调整运行时获得的地址以找到实际的符号。执行此操作的代码如下:
if ($offsetLine =~ m/^$REFERENCE_OFFSET\s+($SYMBOL_NAME)\s+($HEX_NUMBER)$/) {
# This is a dynamic library; need to calculate the load offset
my $offsetSymbol = "_$1";
my $offsetAddress = hex $2;
my %offsetTable = reverse %SYMBOLTABLE;
print Dumper(\%offsetTable);
$baseAddress = $offsetTable{$offsetSymbol} - $offsetAddress;
#print("offsetSymbol == $offsetSymbol\n");
#print("offsetAddress == $offsetAddress\n");
#print("baseoffsetAddress == $offsetAddress\n");
$offsetLine = <CALL_DATA>;
} else {
# This is static
$baseAddress = 0;
}
Run Code Online (Sandbox Code Playgroud)
这就是这条线#define PTRACE_REFERENCE_FUNCTION Crumble_buy的用途。ptrace 中的代码C正在使用该宏,如果定义了,则首先输出该函数的地址。然后,它计算偏移量,并针对所有后续地址,按此量调整它们,在散列中查找正确的符号。