功能年代一丝C调用++使用etrace [英] Chronological trace of function calls in C++ using etrace

查看:170
本文介绍了功能年代一丝C调用++使用etrace的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景:

我有一个很大的仿真工具,我需要了解其逻辑的行为。为了做到这一点,最帮助我,让我是否有函数调用的时间顺序为一个最小的工作的例子。

我发现很多在线工具,如 CygProfiler 并的 etrace 。我成为了发现我开始跟着使用步入与调试器的最疯狂的溶液中而这么惨。这是一个很好的选择,如果你有一个小程序,但不是一个完整的仿真工具。


问题:

一个我所面临的问题是,上面提到的解决方案,本意为 C ,它们生成静态文件( *。Ø在编译时)。在另一方面仿真工具生成一个共享库(的.so )。我没有在较低层次的东西很多知识,我似乎当我尝试将它们连接失败。

我在 etrace特意看了文档,和它说:


  

要看看如何修改ptrace.c一个动态库工作,看
  例2的目录。上述人士也有创造一个独立的
  可执行文件,但PTRACE_REFERENCE_FUNCTION宏定义一样
  这将是一个动态库。


如果你看一下回购有在例如示例2 文件夹中的文件之间没有什么区别。只有出现在示例2 额外的 .H 文件。

在另一方面,如果你看看的src / ptrace.c 有这样说的:


  

在上一个动态库使用ptrace函数,必须设置
    PTRACE_REFERENCE_FUNCTION宏是在一个函数的名称
    图书馆。加载时该函数的地址将是第一
    线输出到跟踪文件,将允许的翻译
    其他出入境指针符号名。你可以设置
    宏观PTRACE_INCLUDE有需要对任何#include指令
    该功能是入店这个源文件。


略低于就有评论code:

  / *当一个动态库使用ptrace函数,必须进行以下定义:
#包括需要PTRACE_REFERENCE_FUNCTION任何文件
#定义PTRACE_REFERENCE_FUNCTION functionName
`* /


问:

在本质上的问题如下:?如何使用 etrace 与动态库

我是否需要#包括任何文件?


  

要跟踪一个独立的程序,也没有必要对#包括任何
  额外的文件。只是链接你的code反对ptrace.c和使用
  -finstrument-功能选项,作为一个GCC编译选项。这应该做到这一点。


如何链接它是通过内置的makefile对 ptrace.c

一个C ++ code

最后请注意:我想如果有人用我的无知承担,并提供了一​​步一步的解决我的问题AP preciate


更新1:

我设法增加etrace的仿真工具相关的库,并执行罚款。

然而,(可能是因为脚本是太旧了,或者并不适用于C ++使用)我得到使用的 perl脚本通过默认提供由 etrace


 十六进制数> 0xffffffff的非便携


这大概修改了一下这个问题的性质,在这一点上把它更多的一个perl相关的问题。

如果这个问题解决了,我希望 etrace 将一个复杂的项目工作,我将提供详细信息。


更新2:

我把建议从@Harry,我相信这将在大多数项目。然而,在我的情况下,我从Perl脚本如下:

 使用%SYMBOLTABLE内列表赋值在etrace2.pl线99 LT初始化值,和的; CALL_DATA> 1号线。\\  - ?
| \\ - ?
\\ - ?
| \\ - ?
| | \\ - ?
\\ - ?
| \\ - ?
\\ - ?
| \\ - ?
\\ - ?
| \\ - ?
\\ - ?
| \\ - ?
\\ - ?
| \\ - ?

由于autegenerated的makefile我用 LD_ preLOAD 加载共享库etrace.so我得到如下:

 的gcc -g -finstrument函数-fPIC -shared -o ptrace.c -I etrace.so LT&;路径到etrace>

我的工具创建的内部虚拟etrace.h:

 的#ifndef __ETRACE_H_
#定义__ETRACE_H_#包括LT&;&stdio.h中GT;无效Crumble_buy(字符*的东西,INT数量,字符*单位);
无效Crumble_buy(字符*的东西,INT数量,字符*单位)
{
    的printf(买%d个%S的\\ n%S,数量,单位,什么);
}#万一

和使用 Crumble_buy 的#define etrace.h 的#include


解决方案

修复Perl脚本


  

十六进制数> 0xffffffff的非便携


这是从十六进制一个警告,因为它检测到可能的非便携值(东西> 32位)。

在脚本的最顶端,补充一点:

 使用BIGINT QW /六角十月/;

当这个工具是书面的,我怀疑的人都在32位机器。您可以编译使用32位的标志 -m32 该计划,但如果你改变了Perl脚本为上面提到你不会需要。

请注意,如果你是一个Mac上,你不能使用 mknod的它在脚本用于创建管道的方式;你需要使用 mkfifo子不带任何参数来代替。

在Linux中,添加 BIGINT 解决上述作品。然后,您需要从同一目录中运行两个命令,我这样做是使用示例2

  ../的src / etrace.pl崩溃
#切换到不同的终端
。/崩溃

和我得到这个在Mac和Linux上

  \\  - 主
| \\ - 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

关于动态库...

当你加载一个动态库,对象文件中的地址是不运行时将使用的地址。什么etrace确实是从您指定的头拍摄功能名称。例如,在示例2 的情况下,这将是以下内容:

 的#includecrumble.h
#定义PTRACE_REFERENCE_FUNCTION Crumble_buy

您会然后编辑生成文件,以确保头文件可以发现:

  CFLAGS = -g -finstrument函数-I。

请注意增加的包括 -I 。从标题中的符号的地址(在我们的情况下, Crumble_buy )被用来计算在目标文件和实际地址之间的偏移;这使得程序计算出正确的地址找到符号。

如果你看看纳米的输出,你得到的东西像下面这样:

  0000000100000960牛逼_Crumble_bake
00000001000005b0ŧ_Crumble_buy
0000000100000640ŧ_Crumble_buy_stuff
00000001000009f0ŧ_Crumble_cook

左边的地址是相对的,即,在运行时,这些地址实际改变。该etrace.pl程序在哈希存储这些是这样的:

  $ VAR1 = {
          '4294969696'=> _Crumble_bake',
          '4294969424'=> _Crumble_put',
          '4294970096'=> '_主要',
          '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
        };

请注意前导下划线,因为这是在Mac上使用铿锵。在运行时,这些地址是不正确的,但它们的相对偏移。如果你能制定出有什么偏差,你可以调整你在运行时的地址找到实际的符号。在code,这是否如下:

 如果($ offsetLine =〜M / ^ $ REFERENCE_OFFSET \\ S +($ SYMBOL_NAME)\\ S +($ HEX_NUMBER)$ /){
    #这是一个动态库;需要计算负载偏移
    我的$ offsetSymbol =_ $ 1;
    我的$ offsetAddress = HEX $ 2;    我的%=偏移表反向%SYMBOLTABLE;    打印自卸车(\\%偏移表);
    $ baseAddress = $ {偏移表$ offsetSymbol} - $ offsetAddress;
    #PRINT(offsetSymbol == $ offsetSymbol \\ n);
    #PRINT(offsetAddress == $ offsetAddress \\ n);
    #PRINT(baseoffsetAddress == $ offsetAddress \\ n);
    $ offsetLine =&所述; CALL_DATA取代;
  }其他{
    #这是静态的
    $ baseAddress = 0;
  }

这是什么行的#define PTRACE_REFERENCE_FUNCTION Crumble_buy 是。在ptrace的的 C code是使用宏,如果定义,即输出功能的第一件事的地址。然后计算的偏移量,以及所有后续地址,此数量进行调整,在哈希查找正确的符号。

Background:

I have one big simulation tool, and I need to understand its logical behavior. In order to do that, the most of help I would get if I have the chronological order of function calls, for a minimal working example.

I found many tools online, like CygProfiler and etrace. I became so miserable on finding a solution that I started to follow the craziest solution of using "step into" with the debugger. Which is a good option if you have a small program but not a complete simulation tool.


Problem:

One of the problems I face is that the above-mentioned solutions are originally meant for C and they generate a static file (*.o) when compiled. On the other hand the simulation tool generates a shared library (.so). I don't have much knowledge on lower level stuff so I seem to fail when I try linking them.

I looked specifically at the etrace documentation, and it says:

To see how to modify ptrace.c to work with a dynamic library, look at the example2 directory. The sources there also create a stand-alone executable, but the PTRACE_REFERENCE_FUNCTION macro is defined just as it would be for a dynamic library.

If you look at the repo there is no difference between the files in example and example2 folders. Only there is an extra .h file in example2.

On the other hand, if you look at src/ptrace.c there it says:

When using ptrace on a dynamic library, you must set the PTRACE_REFERENCE_FUNCTION macro to be the name of a function in the library. The address of this function when loaded will be the first line output to the trace file and will permit the translation of the other entry and exit pointers to their symbolic names. You may set the macro PTRACE_INCLUDE with any #include directives needed for that function to be accesible to this source file.

a little below there is the commented code:

/* 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
`*/


Question:

In essence the question is the following: How to use etrace with a dynamic library?

Do I need to #include any files?

To trace a stand-alone program, there is no need to #include any additional file. Just link your code against ptrace.c and use the -finstrument-functions option as a compile option for gcc. This should do it.

How do I link a C++ code which is built via makefiles against ptrace.c

Final Note: I would appreciate if someone bears with my ignorance and provides a step-by-step solution to my question.


Update 1:

I managed to add the libraries related to etrace to the simulation tool, and it executes fine.

However, (probably because the scripts are too old, or are not meant for use with C++) I get the following error when using the perl script provided by default by etrace

Hexadecimal number > 0xffffffff non-portable"

Probably this changes a bit the nature of this question, turning it more to a perl related issue at this point.

If this problem is solved, I hope etrace will work with a complicated project and I will provide the details


Update 2:

I took the suggestions from @Harry, and I believe that would work in most projects. However in my case I get the following from the perl script:

Use of uninitialized value within %SYMBOLTABLE in list assignment at etrace2.pl line 99, <CALL_DATA> line 1.

\-- ???
|   \-- ???
\-- ???
|   \-- ???
|   |   \-- ???
\-- ???
|   \-- ???
\-- ???
|   \-- ???
\-- ???
|   \-- ???
\-- ???
|   \-- ???
\-- ???
|   \-- ???

Due to autegenerated makefiles I used the LD_PRELOAD to load the shared library for etrace.so which I got as follows:

gcc -g -finstrument-functions -shared -fPIC ptrace.c -o etrace.so -I <path-to-etrace>

I created the dummy etrace.h inside the tool:

#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

and used Crumble_buy for the #define and the etrace.h for the #include.

解决方案

Fixing the Perl Script

Hexadecimal number > 0xffffffff non-portable"

This is a warning from hex because it's detecting a possibly non-portable value (something > 32bits).

At the very top of the script, add this:

use bigint qw/hex oct/;

When this tool was written, I suspect the people were on 32-bit machines. You can compile the program using 32-bit with the flag -m32, but if you change the perl script as mentioned above you won't need to.

Note, if you're on a Mac, you can't use mknod the way it's used in the script to create a pipe; you need to use mkfifo with no arguments instead.

On Linux, adding the bigint fix above works. You then need to run both commands from the same directory, I did this using example2:

../src/etrace.pl crumble
# Switch to a different terminal
./crumble

and I get this on the Mac and 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

About the Dynamic Library...

When you load a dynamic library, the address in the object file is not the address that will be used when running. What etrace does is take a function name from a header you specify. For example, in the case of example2, this would be the following:

#include "crumble.h"
#define PTRACE_REFERENCE_FUNCTION Crumble_buy

You would then edit the makefile to make sure that the header file can be found:

CFLAGS = -g -finstrument-functions -I.

Note the addition of the include -I.. The address of the symbol from the header (in our case, Crumble_buy) is used to calculate the offset between the object file and the actual address; this allows the program to calculate the correct address to find the symbol.

If you look at the output of nm, you get something like the following:

0000000100000960 T _Crumble_bake
00000001000005b0 T _Crumble_buy
0000000100000640 T _Crumble_buy_stuff
00000001000009f0 T _Crumble_cook

The addresses on the left are relative, that is, at runtime, these addresses actually change. The etrace.pl program is storing these in a hash like this:

$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'
        };

Note the leading underscore because this is on a Mac using clang. At runtime, these addresses are not correct, but their relative offsets are. If you can work out what the offset is, you can adjust the addresses you get at runtime to find the actual symbol. The code that does this follows:

 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;
  }

This is what the line #define PTRACE_REFERENCE_FUNCTION Crumble_buy is for. The C code in ptrace is using that MACRO, and if defined, outputting the address of that function as the first thing. It then calculates the offset, and for all subsequent addresses, adjusts them by this amount, looking up the correct symbol in the hash.

这篇关于功能年代一丝C调用++使用etrace的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆