gpt4 book ai didi

gcc - gcc 编译器标志和符号表之间的函数地址不兼容

转载 作者:行者123 更新时间:2023-12-02 10:39:05 29 4
gpt4 key购买 nike

我已经编译了一个项目(这里是openssh,但这并不重要)

CFLAGS="-ggdb3 -O0 -lm -finstrument-functions"

符号表是(小摘录):

nm -o somepath/sbin/sshd
/mypath/install/sbin/sshd:000f3548 d auth_method
/mypath/install/sbin/sshd:0001a90f t auth_openfile
/mypath/install/sbin/sshd:0001ab90 T auth_openkeyfile
/mypath/install/sbin/sshd:0001ac31 T auth_openprincipals
/mypath/install/sbin/sshd:0001d73a T auth_parse_options
/mypath/install/sbin/sshd:0000e362 T auth_password

当我打印__cyg_profile_func_enter|exit中的函数地址时,我得到的是:

0xb768f8ee
0xb768f66c
0xb768f66c
0xb76d9ae8

在查看所有数字后确认,显然范围不同。

据我了解,nm 提供偏移地址。当项目中有很多文件时,__cyg_profile_func_enter怎么办?是否需要执行额外的转换?

来自gcc documentation ,不应该有:

          void __cyg_profile_func_enter (void *this_fn,
void *call_site);
void __cyg_profile_func_exit (void *this_fn,
void *call_site);

The first argument is the address of the start of the current function, which may be looked up exactly in the symbol table.

那么,为了让它发挥作用,我错过了什么?

编辑:我在 ptrace.c 中添加了互斥体

#if (__GNUC__>2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ > 95))

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <sys/errno.h>
#include <pthread.h>

#define PTRACE_PIPENAME "TRACE"

#define REFERENCE_OFFSET "REFERENCE:"
#define FUNCTION_ENTRY "enter"
#define FUNCTION_EXIT "exit"
#define END_TRACE "EXIT"
#define __NON_INSTRUMENT_FUNCTION__ __attribute__((__no_instrument_function__))
#define PTRACE_OFF __NON_INSTRUMENT_FUNCTION__
#define STR(_x) #_x
#define DEF(_x) _x
#define GET(_x,_y) _x(_y)
#define TRACE __GNU_PTRACE_FILE__

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

/** Initial trace open */
static FILE *__GNU_PTRACE_FILE__;

/** Final trace close */
static void
__NON_INSTRUMENT_FUNCTION__
gnu_ptrace_close(void)
{
fprintf(TRACE, END_TRACE " %ld\n", (long)getpid());

int res = fflush(TRACE);
if (res < 0) {
printf("Erreur sur gnu_ptrace_close / fflush\n");
}

if (TRACE != NULL)
fclose(TRACE);

pthread_mutex_destroy(&lock);

return ;
}

/** Trace initialization */
static int
__NON_INSTRUMENT_FUNCTION__
gnu_ptrace_init(void)
{
struct stat sta;
__GNU_PTRACE_FILE__ = NULL;

/* See if a trace file exists */
if (stat(PTRACE_PIPENAME, &sta) != 0)
{
/* No trace file: do not trace at all */
return 0;
}
else
{
/* trace file: open up trace file */
if ((TRACE = fopen(PTRACE_PIPENAME, "a")) == NULL)
{
char *msg = strerror(errno);
perror(msg);
printf("[gnu_ptrace error]\n");
return 0;
}

#ifdef PTRACE_REFERENCE_FUNCTION
fprintf(TRACE,"%s %s %p\n",
REFERENCE_OFFSET,
GET(STR,PTRACE_REFERENCE_FUNCTION),
(void *)GET(DEF,PTRACE_REFERENCE_FUNCTION));
#endif

/* Tracing requested: a trace file was found */
atexit(gnu_ptrace_close);
return 1;
}
}

/** Function called by every function event */
void
__NON_INSTRUMENT_FUNCTION__
gnu_ptrace(char * what, void * p)
{
static int first=1;
static int active=1;
int res = 0;

if (active == 0)
return;

if (first)
{
active = gnu_ptrace_init();
first = 0;

if (active == 0)
return;
}

if (!what || !p) {
printf("Erreur, what ou p NULL\n");
return;
}

if (strcmp(what, FUNCTION_ENTRY) && strcmp(what, FUNCTION_EXIT)) {
printf("Erreur, what incorrect\n");
return;
}

printf("----------------------- what=%s p=%p\n", what, p);

res = fprintf(TRACE, "%s %p\n", what, p);
if (res < 0) {
printf("Erreur sur gnu_ptrace / fprintf\n");
/* active = 0;*/
}

if (res > 0) res = fflush(TRACE);
if (res < 0) {
printf("Erreur sur gnu_ptrace / fflush\n");
active = 0;
}

return;
}

/** According to gcc documentation: called upon function entry */
void
__NON_INSTRUMENT_FUNCTION__
__cyg_profile_func_enter(void *this_fn, void *call_site)
{
pthread_mutex_lock(&lock);
gnu_ptrace(FUNCTION_ENTRY, this_fn);
(void)call_site;
pthread_mutex_unlock(&lock);
}

/** According to gcc documentation: called upon function exit */
void
__NON_INSTRUMENT_FUNCTION__
__cyg_profile_func_exit(void *this_fn, void *call_site)
{
pthread_mutex_lock(&lock);
gnu_ptrace(FUNCTION_EXIT, this_fn);
(void)call_site;
pthread_mutex_unlock(&lock);
}

#endif

这里是用 JHiant 思想修改后的 ptrace.c。我已与 -ldl 链接

#include <dlfcn.h>

_

Dl_info finfo;
if (!dladdr(p, &finfo))
printf("Erreur, dladdr\n");

/* res = fprintf(TRACE, "%s %p\n", what, p); */
res = fprintf(TRACE, "%s %p %s (%s)\t\n", what, p, finfo.dli_sname, finfo.dli_fname);

这是获得的跟踪(第一行):

enter 0xb7494974 OPENSSL_cpuid_setup (/home/laurent/Documents/projet/install/lib/libcrypto.so.1.0.0)    
exit 0xb7494974 OPENSSL_cpuid_setup (/home/laurent/Documents/projet/install/lib/libcrypto.so.1.0.0)
enter 0xb76ac470 main (/home/laurent/Documents/projet/install/sbin/sshd)
enter 0xb76b34fe (null) (/home/laurent/Documents/projet/install/sbin/sshd)
exit 0xb76b34fe (null) (/home/laurent/Documents/projet/install/sbin/sshd)
enter 0xb7749384 (null) (/home/laurent/Documents/projet/install/sbin/sshd)
enter 0xb770496e (null) (/home/laurent/Documents/projet/install/sbin/sshd)
enter 0xb77046ec (null) (/home/laurent/Documents/projet/install/sbin/sshd)
exit 0xb77046ec (null) (/home/laurent/Documents/projet/install/sbin/sshd)
enter 0xb774eb68 (null) (/home/laurent/Documents/projet/install/sbin/sshd)
exit 0xb774eb68 (null) (/home/laurent/Documents/projet/install/sbin/sshd)
exit 0xb770496e (null) (/home/laurent/Documents/projet/install/sbin/sshd)
exit 0xb7749384 (null) (/home/laurent/Documents/projet/install/sbin/sshd)

其他行始终显示 null 而不是函数名称。我检查了 sshd 映射,使用了带有符号的正确 libcrypto 构建。上面的跟踪中令人惊讶的是,它只显示了对 libcrypto 的一次调用,正如名称所示,这看起来只是一个设置。

OpenSSH 的编译方式为(控制台中 make 执行的一行摘录 - 全部具有相同的选项 - 通常没有 -fpic,但生成的跟踪是相同的):

gcc -ggdb3 -O0 -lm -finstrument-functions -ldl -fpic -Wall -Wpointer-arith -Wuninitialized -Wsign-compare -Wformat-security -Wno-pointer-sign -Wno-unused-result -fno-strict-aliasing -D_FORTIFY_SOURCE=2 -ftrapv -fno-builtin-memset -fstack-protector-all -fPIE  -I. -I. -I/home/laurent/Documents/projet/install/include  -DSSHDIR=\"/home/laurent/Documents/projet/install/etc\" -D_PATH_SSH_PROGRAM=\"/home/laurent/Documents/projet/install/bin/ssh\" -D_PATH_SSH_ASKPASS_DEFAULT=\"/home/laurent/Documents/projet/install/libexec/ssh-askpass\" -D_PATH_SFTP_SERVER=\"/home/laurent/Documents/projet/install/libexec/sftp-server\" -D_PATH_SSH_KEY_SIGN=\"/home/laurent/Documents/projet/install/libexec/ssh-keysign\" -D_PATH_SSH_PKCS11_HELPER=\"/home/laurent/Documents/projet/install/libexec/ssh-pkcs11-helper\" -D_PATH_SSH_PIDDIR=\"/var/run\" -D_PATH_PRIVSEP_CHROOT_DIR=\"/var/empty\" -DHAVE_CONFIG_H -c ssh-keyscan.c

OpenSSL 的编译方式为(控制台中 make 执行的一行摘录 - 全部具有相同的选项):

gcc -I.. -I../.. -I../modes -I../asn1 -I../evp -I../../include  -ggdb3 -O0 -lm -finstrument-functions -ldl  -fPIC -DOPENSSL_PIC -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -Wa,--noexecstack -DL_ENDIAN -DTERMIO -fomit-frame-pointer -Wall -DOPENSSL_BN_ASM_PART_WORDS -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DRMD160_ASM -DAES_ASM -DVPAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM   -c -o cms_lib.o cms_lib.c

为什么没有来自 OpenSSL/libcrypto 的更多痕迹?

为什么跟踪中除了“main”之外没有函数名称?

最佳答案

一些想法:

  1. 创建 helloworld.c 并检查 nm 是否与您所看到的同步。在您的个人资料代码中。这可能是 sshd 构建方式的问题,而不是您的代码的问题。
  2. 尝试将 -fpic 添加到您的 CFLAGS。
  3. 强制:只是为了确保您是从源代码编译 sshd,而不是链接它,因为函数检测是在编译步骤而不是链接步骤中插入的。否则,它只会打印不是来自 sshd 库的地址,例如 main() 或一些辅助函数的地址。您可以考虑通过以下方式将函数名称添加到调试输出:

 

#include <dlfcn.h>
__cyg_profile_func_enter(void *func, void *site)
{
DL_info finfo;
dladdr(fun, &finfo);
fprintf(log, "Entered &s", finfo.dli_sname);
}

关于gcc - gcc 编译器标志和符号表之间的函数地址不兼容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26675818/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com