2012-03-20 10 views
6

Pracujemy nad programem C skompilowanym z arm-eabi-gcc pod Linuksem.Jak uzyskać względny adres pola w zrzucie struktury. [C]

Używamy zrzutu dużej struktury i mamy problemy z określeniem, przy którym adresie powinniśmy czytać różne pola naszej struktury (np. 50 z nich), (wyrównanie pamięci i dopełnienie nie są tak przewidywalne mnie).

Czy istnieje sposób na mapowanie pamięci struktury produkowanej przez nasz kompilator. Opcja w gdb? Lub jakiekolwiek narzędzie pomagające nam znaleźć korespondencję między polami a adresem w zrzucie?

+0

Prawdopodobnie brakuje tu czegoś oczywistego, ale jeśli masz zmienną (powiedzmy 'x'), która jest zadeklarowana jako instancja struktury (lub wskaźnik do struktury), powinieneś być w stanie po prostu wpisać' wypisz x' (lub 'print * x' jeśli wskaźnik) w gdb, aby zrzucić wszystkie elementy. –

+0

Nie próbuję uzyskać adresu tego, co chcę zrzucić. Już mam dump i potrzebuję względnego adresu wszystkich członków. – Akhneyzar

Odpowiedz

23

Możesz to zrobić pod numerem gdb. Jako przykład, będę korzystać z tego źródła:

struct A { 
    int a; 
    char b; 
    short c; 
}; 

int main() { 
    struct A a; 
} 

załadunku binarny w gdb:

(gdb) print (int)&((struct A*)0)->a 
$1 = 0 
(gdb) print (int)&((struct A*)0)->b 
$2 = 4 
(gdb) print (int)&((struct A*)0)->c 
$3 = 6 

UPDATE:

Jeśli musisz to zrobić dla dużej liczby pól, wtedy może ci się przydać użycie nowego interfejsu Pythona GDB (będziesz potrzebować ostatniej wersji GDB, aby go użyć, używam 7.4). Utworzyłem offsets.py:

import gdb 

class Offsets(gdb.Command): 
    def __init__(self): 
     super (Offsets, self).__init__ ('offsets-of', gdb.COMMAND_DATA) 

    def invoke(self, arg, from_tty): 
     argv = gdb.string_to_argv(arg) 
     if len(argv) != 1: 
      raise gdb.GdbError('offsets-of takes exactly 1 argument.') 

     stype = gdb.lookup_type(argv[0]) 

     print argv[0], '{' 
     for field in stype.fields(): 
      print ' %s => %d' % (field.name, field.bitpos//8) 
     print '}' 

Offsets() 

Następnie można dodać do .gdbinit:

python 
sys.path.insert(0, '/path/to/script/dir') 
import offsets 
end 

następnie używając go w GDB, jak:

(gdb) offsets-of "struct A" 
struct A { 
    a => 0 
    b => 4 
    c => 6 
} 

Skrypt ten sprawia, że kilka upraszczających założeń, tak jak to, że nie używasz bitfieldów, i nie kopie w zagnieżdżone struktury, ale te zmiany są 3 dość proste, jeśli ich potrzebujesz.

+0

Podaję, ale chciałbym umieścić listę 50 potrzebnych pól. – Akhneyzar

+0

Zrobiłem bardziej kompletną wersję tego, dzięki za inspirację. [Clicky] (https://github.com/Craxic/PyGDBOffsets/blob/master/offsets.py) – AStupidNoob

+0

Twój '.gdbinit' wygląda dziwnie. Dlaczego nie 'source/path/to/script/dir/offsets.py' – zhangyoufu

-1

Wydaje mi się, można napisać kawałek kodu, tak dla wymaganych pól

struct MyStruct S; 
int Offset_of_X=((long)&(S.X))-((long)&S); 

obliczyć przesunięcie w bajtach w tej sytuacji kompilacji.

Powinno to uwzględniać wszelkie problemy z wyrównaniem występujące w kompilatorze.

+0

Ale nie ma wydajności na 50 pól lub więcej. – Akhneyzar

+0

To się nie kompiluje: arytmetyczne wskaźniki nie pozwalają odjąć wskaźnika na S od wskaźnika do X. –

2

Można to zrobić z poziomu programu C, używając standardowego makra offsetof(), zdefiniowanego w stddef.h. Jednak nie jestem pewien, czy właśnie tego chcesz, ponieważ możesz nie być w stanie go uruchomić (skompilowanie go na hoście prawdopodobnie zwróci nieprawidłowe przesunięcia).

#include <stdio.h> 
#include <stddef.h> 

struct A { 
    int a; 
    char b; 
    short c; 
}; 

int main() { 
    printf("Offset of b in A is %zu\n", offsetof(struct A, b)); 
    return 0; 
} 

Jednakże, być może będziesz w stanie zastosować kilka hacków, aby uzyskać offset skompilowanego pliku binarnego bez jego wykonywania. Może przypisać zmienną statyczną wartość przesunięcia i znaleźć jakiś sposób na uzyskanie jej wartości.