2012-06-29 16 views
9

Bir TCP soketine (belirli bir bağlantı noktasına bağlı) gönderilen isteği işleyen bir Linux C programım var. C programının iç durumunu bu bağlantı noktasına bir istek ile sorgulayabilmek istiyorum, ancak global değişkenlerin sorgulanabileceği sabit bir kod istemiyorum. Bu yüzden sorgunun, bir global ve C kodunun dize adını içermesini ve bu dizginin adres tablosunu bulmak için sembol tablosuna bakmasını ve ardından değerini TCP soketine geri göndermesini istiyorum. Tabii ki sembol tablosu soyulmamış olmalı. Bu yüzden C programı kendi sembol tablosunu bile bulabilir ve isimleri verilen sembollere bakmak için bir kütüphane arayüzü var mı? Bu, gcc ile oluşturulmuş bir ELF yürütülebilir C programıdır.Çalışan bir C programı kendi sembol tablosuna erişebilir mi?

+0

uzaktan hata ayıklama istiyorum için bir internet arama yapın "." uzaktan hata ayıklama linux linkleri Bol – selbie

+0

@selbie : Bu bir şeyleri yapmanın zor yolu. –

cevap

13

Bu aslında oldukça kolaydır. Sembollere erişmek için dlopen/dlsym kullanın. Bunun çalışması için sembollerin dinamik sembol tablosunda bulunması gerekir. Birden fazla sembol tablosu var! Dinamik sembol tablosuna bütün sembolleri eklemek için

#include <dlfcn.h> 
#include <stdio.h> 

__attribute__((visibility("default"))) 
const char A[] = "Value of A"; 

__attribute__((visibility("hidden"))) 
const char B[] = "Value of B"; 

const char C[] = "Value of C"; 

int main(int argc, char *argv[]) 
{ 
    void *hdl; 
    const char *ptr; 
    int i; 

    hdl = dlopen(NULL, 0); 
    for (i = 1; i < argc; ++i) { 
     ptr = dlsym(hdl, argv[i]); 
     printf("%s = %s\n", argv[i], ptr); 
    } 
    return 0; 
} 

, -Wl,--export-dynamic kullanın. Sembollerin çoğunu sembol tablosundan kaldırmak (önerilir) istiyorsanız, -fvisibility=hidden'u ayarlayın ve ardından __attribute__((visibility("default"))) ile istediğiniz sembolleri veya diğer yöntemlerden birini açıkça ekleyin.

 
~ $ gcc dlopentest.c -Wall -Wextra -ldl 
~ $ ./a.out A B C 
A = (null) 
B = (null) 
C = (null) 
~ $ gcc dlopentest.c -Wall -Wextra -ldl -Wl,--export-dynamic 
~ $ ./a.out A B C 
A = Value of A 
B = (null) 
C = Value of C 
~ $ gcc dlopentest.c -Wall -Wextra -ldl -Wl,--export-dynamic -fvisibility=hidden 
~ $ ./a.out A B C 
A = Value of A 
B = (null) 
C = (null) 

Emniyet kötü davranış için bir sürü oda olduğunu

dikkat edin.

 
$ ./a.out printf 
printf = ▯▯▯▯ (garbage) 

bu güvenli olmak istiyorsanız, izin verilen sembollerin bir beyaz liste oluşturmalısınız.

+0

Baskı dışı -string ibly sonlandırılmadı) veri veya dizge olarak işlevler tehlikelidir. Aksi takdirde, sembollerin beyaz listeye alınması gerekmiyor. –

+0

@R ..: Hm, soruyu daha ayrıntılı okuyana kadar değişkenin okuma/yazmada kullanıldığını düşündüm. Güncellenmiş. –

+0

Bu, istediğim şeyin yarısıdır ... sorun şu ki, sembolün türüne bakılmaksızın anlamlı bir şekilde yanıt verebilmek istiyorum. Yani Ya A “uzun” ve B “char” ve C a “char *” ise? Sembol türüne ve adresine erişmem gerekiyor. – JimKleck

1

özelliği bu tür için genel terim "reflection" olduğunu ve bu hata ayıklama amacıyla ise o C

parçası

değildir ve bir C eyaletinin tamamını incelemek isterler Program uzaktan, herhangi bir değişkeni incelemek başlatmak ve yürütme durdurma ve benzeri, aşağıdakileri düşünebilirsiniz GDBremote debugging:

GDB gömülü sistemler ayıklarken sıklıkla kullanılan bir 'uzak' modunu sunar. GDB tek bir makinede çalıştığında ve hata ayıklanmış programında başka bir işlem yürütüldüğünde uzaktan işlem gerçekleştirilir. GDB, Seri veya TCP/IP üzerinden GDB protokolünü anlayan uzak 'saplama' ile iletişim kurabilir. bir saplama programı, GDB ile sağlanan uygun saplama dosyalarına bağlantı kurarak iletişim protokolünün hedef tarafını uygulayarak oluşturulabilir. Alternatif olarak, gdbserver herhangi bir şekilde değiştirmeye gerek kalmadan programı hata ayıklamak için kullanılabilir.

+1

Bu üretim içindir ve bir arama tablosunu sürdürmek zorunda kalmadan herhangi bir simgeye göz atmak istiyorum ... sonuçta bu bilgi zaten sembol tablosundadır. – JimKleck

6

dosyası: reflect.c

#include <stdio.h> 
#include "reflect.h" 

struct sym_table_t gbl_sym_table[1] __attribute__((weak)) = {{NULL, NULL}}; 

void * reflect_query_symbol(const char *name) 
{ 
    struct sym_table_t *p = &gbl_sym_table[0]; 

    for(; p->name; p++) { 
     if(strcmp(p->name, name) == 0) { 
      return p->addr; 
     } 
    } 
    return NULL; 
} 

dosyası: reflect.h

#include <stdio.h> 

struct sym_table_t { 
    char *name; 
    void *addr; 
}; 

void * reflect_query_symbol(const char *name); 

dosyası:

sadece #include main.c "yansıtmaktadır.h" ve çağrı reflect_query_symbol

örnek:

#include <stdio.h> 
#include "reflect.h" 

void foo(void) 
{ 
    printf("bar test\n"); 
} 

int uninited_data; 

int inited_data = 3; 

int main(int argc, char *argv[]) 
{ 
    int i; 
    void *addr; 

    for(i=1; i<argc; i++) { 
     addr = reflect_query_symbol(argv[i]); 
     if(addr) { 
      printf("%s lay at: %p\n", argv[i], addr); 
     } else { 
      printf("%s NOT found\n", argv[i], addr); 
     } 
    } 

    return 0; 
} 

dosyası:. Makefile

objs = main.o reflect.o 

main: $(objs) 
     gcc -o [email protected] $^ 
     nm [email protected] | awk 'BEGIN{ print "#include <stdio.h>"; print "#include \"reflect.h\""; print "struct sym_table_t gbl_sym_table[]={" } { if(NF==3){print "{\"" $$3 "\", (void*)0x" $$1 "},"}} END{print "{NULL,NULL} };"}' > .reflect.real.c 
     gcc -c .reflect.real.c -o .reflect.real.o 
     gcc -o [email protected] $^ .reflect.real.o 
     nm [email protected] | awk 'BEGIN{ print "#include <stdio.h>"; print "#include \"reflect.h\""; print "struct sym_table_t gbl_sym_table[]={" } { if(NF==3){print "{\"" $$3 "\", (void*)0x" $$1 "},"}} END{print "{NULL,NULL} };"}' > .reflect.real.c 
     gcc -c .reflect.real.c -o .reflect.real.o 
     gcc -o [email protected] $^ .reflect.real.o 
+0

Sadece "reflect.c" ve "reflect.h" gibi iki dosya yazmanız ve "Makefile" nizi değiştirmeniz yeterlidir, sembol ismini ve sembolün ilgili adresini alacaktır. –

+0

Sembolün veya adresin yanı sıra en az boyuta sahip bir simge istiyorum. Nm için "-S" bayrağı bunu yapacak gibi görünüyor. Nbl_sym_table için doğru boyutu almak için son çalıştırılabilirde nm'yi çalıştırmam gerekmiyor (birden fazla .o'dan beri), sonra tekrar adreslerle doldurmak için nm'yi tekrar çalıştır mı? Sonra sonunda reflect.o'yu yeniden oluşturun ve hepsini çalıştırılabilir duruma getirin mi? – JimKleck

+0

Aslında, neden nm ve makefile sihirbazlık ile uğraşmak? Nm programı sembol tablosuna erişmek için bir miktar API kullanmalıdır, bu API'nin doğrudan programımda kullanılmasını istiyorum. – JimKleck

İlgili konular