2014-10-31 14 views
5

tôi đã biên soạn một dự án (OpenSSH đây nhưng đó không phải là quan trọng) vớiđịa chỉ chức năng không tương thích giữa cờ biên dịch gcc và bảng biểu tượng

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

Bảng biểu tượng là (chiết xuất nhỏ):

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 

những gì tôi có được khi tôi in các địa chỉ chức năng trong __cyg_profile_func_enter|exit là:

0xb768f8ee 
0xb768f66c 
0xb768f66c 
0xb76d9ae8 

Rõ ràng không cùng phạm vi, được xác nhận sau khi đã xem xét tất cả các số liệu.

Điều tôi hiểu là nm cung cấp địa chỉ offset. Điều gì về __cyg_profile_func_enter khi có nhiều tệp trong dự án? Có một chuyển đổi bổ sung để thực hiện không?

Từ gcc documentation, không nên:

  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. 

Vì vậy, những gì tôi bỏ lỡ để làm cho nó hoạt động?

EDIT: ptrace.c tôi, nơi tôi đã thêm một mutex

#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 

Đây là ptrace.c sửa đổi với những ý tưởng JHiant. Tôi đã liên kết với -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); 

Đây là dấu vết thu được (dòng đầu tiên):

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) 

dòng khác cho thấy null tất cả các thời gian thay vì tên hàm . Tôi đã kiểm tra bản đồ sshd, việc xây dựng libcrypto phù hợp với các biểu tượng được sử dụng. Điều đáng ngạc nhiên trong dấu vết ở trên là nó chỉ hiển thị một cuộc gọi tới libcrypto, trông giống như một thiết lập như tên hiển thị nó.

OpenSSH được biên soạn với (trích một dòng của làm cho thực hiện trong giao diện điều khiển - tất cả đều có tùy chọn tương tự - normaly mà không -fpic, nhưng dấu vết kết quả là như nhau):

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 được biên soạn với (trích xuất một dòng thực hiện lệnh trong bảng điều khiển - tất cả đều có cùng các tùy chọn):

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 

Tại sao không còn dấu vết nào từ OpenSSL/libcrypto?

Tại sao không có tên chức năng trong dấu vết ngoại trừ "chính"?

Trả lời

1

Một vài ý tưởng:

  1. Tạo helloworld.c và kiểm tra xem các nm cho rằng đồng bộ với những gì bạn đang nhìn thấy. trong mã tiểu sử của bạn. Nó có thể là một vấn đề với cách sshd được xây dựng, không phải mã của bạn.
  2. Thử thêm hình ảnh vào CFLAGS của bạn.
  3. Bắt buộc: Chỉ cần đảm bảo, bạn đang biên dịch sshd từ nguồn, không liên kết nó, vì công cụ chức năng được chèn vào trong bước biên dịch, không phải là bước liên kết. Nếu không, bạn chỉ cần in các địa chỉ không phải là địa chỉ từ thư viện sshd, chẳng hạn như địa chỉ của hàm main() hoặc một số hàm trợ giúp. Bạn có thể cân nhắc việc thêm tên functio để kết xuất debug qua:

 

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

Tôi đã (1) thành công, dấu vết và địa chỉ nm phù hợp trực tiếp. Tôi đã thử ví dụ được cung cấp bởi [dự án etrace] (https://github.com/elcritch/etrace) từ nơi tôi nhận được phương thức và tệp ptrace.c. Tôi sẽ thử (2) và (3) khi trở lại văn phòng. Cảm ơn. – lalebarde

+0

Tôi chưa thể thử nghiệm giải pháp của bạn, nhưng đó là giải pháp hứa hẹn nhất. Vì vậy, tôi trao cho bạn. Tại các điểm danh sách không bị mất. Chúc mừng. – lalebarde

+0

Chúc mừng. Giữ cho chúng tôi được đăng. Một điều tôi nhìn là đồng bằng giữa các con số trong nm và con số được đăng, nhưng không có sự tương quan. Sẽ tò mò muốn xem điều gì xảy ra. Hãy cho tôi biết cách cờ DL_info giúp. Bạn có thể đảo ngược kỹ sư nó liên quan đến chính trong nm. Bạn không chắc chắn nhưng nếu bạn có thể làm cho công việc đó, có thể tìm kiếm địa chỉ chính bằng cách nào đó như một móc thời gian chạy. – JHiant

1

Khi bạn tải và thực thi một file thực thi (hoặc một thư viện chia sẻ) nó sẽ được nạp vào một địa chỉ độc đoán và các mối liên kết di chuyển địa chỉ của tất cả các biểu tượng (như các hàm của bạn) liên quan đến địa chỉ tải của tệp thực thi. Các địa chỉ này có thể thay đổi từ một lần chạy tập tin thực thi sang một mã khác do Address space layout randomization Bạn có thể nghĩ về các địa chỉ được hiển thị bởi nm là các địa chỉ tương đối (đối với vị trí tải của tệp thực thi).

Để in các địa chỉ như nm, bạn cần phải biết địa chỉ tải và trừ địa chỉ đó khỏi địa chỉ được cung cấp trong chức năng lược tả của bạn. Vì tôi không quen thuộc với API lược tả mà bạn đang sử dụng, tôi không biết liệu có API để tìm bù đắp di dời hay không.

+0

/proc/$ PID/maps là bạn của chúng tôi. Hãy xem [giải pháp Mickael Pankov] (http://stackoverflow.com/questions/19655451/c-function-profiling-address-seem-to-be-offseted). – lalebarde

Các vấn đề liên quan