Forum: Compiler & IDEs Adress-Analyse von Objekten in der bss-Sektion


von rw (Gast)


Lesenswert?

Hallo,

ich habe ein mit avr-g++ kompiliertes Programm, welches aus einem 
globalen Objekt besteht. Dieses Objekt enthält rekursiv verschaltet 
wiederum viele weitere Objekte. In der main-Funktion wird in eine 
Methode dieses globalen Objektes gesprungen und so das Programm 
gestartet.

Nun landet dieses globale Objekt mit all seinen Membern in der 
bss-Sektion hinter den statischen Variablen. Mit Hilfe von avr-objdump 
-D bekomme ich auch Startadresse heraus, bei der das globale Objekt in 
der bss-Sektion beginnt.

Nun möchte ich gern eine Layout-Übersicht über den gesamten Rest der 
bss-Sektion bekommen. Die einzige Variante, die mir dazu einfallen 
würde, wäre, das Gesamtheader-File herzunehmen, zu parsen und alle 
Offsets der Membervariablen auf deren Namen abzubilden. Dazu müsste ich 
natürlich auch die Größen aller Klassen bestimmen, also sizeof(). Daraus 
würden sich dann die Adressen zur Laufzeit berechnen lassen.

Hat jemand einen Tipp für mich, ob es für so etwas Werkzeuge gibt? Mein 
KnowHow ist für solch einen Parser nicht ausreichend. Welche 
Unterstützung kann mir gcc da bieten?

Vielen Dank und
Herzliche Grüße
Richard

von (prx) A. K. (prx)


Lesenswert?

Sollte alles im Mapfile drinstehen.

Aber ich habe noch nicht verstanden, wozu man das braucht - ausser für's 
Debugging.

von rw (Gast)


Lesenswert?

Danke, aber das Mapfile (wenn du die Memorymap des Linkers meinst), 
enthält leider nicht die Informationen, die ich benötige.

Ich benötige eine Übersicht über die Offsets der einzelnen Member in 
allen Klassen.

Das ganze ist tatsächlich für Debugging-Zwecke gedacht. Wenn ich die 
Adressen aller global angelegten Objekte kenne, kann ich von außen zum 
Beispiel zur Laufzeit einzelne Methoden anstoßen und schauen, was 
passiert.

Richard

von (prx) A. K. (prx)


Lesenswert?

Evtl. das Debugging-Format des erzeugten Binaries analysieren. Da steht 
sowas drin.

von Hc Z. (mizch)


Lesenswert?

Nicht ganz das, was Du suchst, aber das folgende Skript gibt alle 
Symbole, sortiert nach ihren Adressen, aus.  Mit einem Argument 
(Variablenname) gibt es die Umgebung dieser Variablen aus.

Du musst folgene Zeile ändern.  Angenommen, Dein Object-File heißt 
pgm.elf:
1
obj_file="$(sed -n 's/^ *file *\([^ ]\+\) *$/\1/p' gdb-macros)"
in
1
obj_file="pgm.elf"

Das Skript (es sollte (hoffentlich) auch auf der Konsole mit WinAVR 
laufen; evtl. das #!/bin/bash in #!/bin/sh am Beginn ändern) folgt:
1
#!/bin/bash
2
3
usage(){
4
    echo "\
5
usage: $pname [-s] regexp
6
Function: display addresses around regexp, sorted by address
7
          Matches on any symbol (not only variables).
8
opts:
9
  -s  display size too"
10
    exit
11
}
12
13
while getopts sSh-: argv; do
14
    case "$argv" in
15
        s|S) opt_s=S;;
16
        *) usage;;
17
    esac
18
done
19
shift $((OPTIND-1))
20
21
obj_file="$(sed -n 's/^ *file *\([^ ]\+\) *$/\1/p' gdb-macros)"
22
23
[[ $1 =~ [0-9a-fA-F] ]] && iopt="-i"
24
avr-nm -anl$opt_s "$obj_file" \
25
| while IFS= read line; do
26
    if [[ "$line" =~ ^(.*)\     .*/([^/]+:[0-9]+)$ ]] ; then
27
        line="${BASH_REMATCH[1]}        ${BASH_REMATCH[2]}"
28
    fi
29
    echo "$line"
30
  done \
31
| sort --key=1 \
32
| grep -C 4  --color=auto $iopt "$1"

EDIT: Es läuft nur mit der Bash -- also das, was ich oben zu #!/bin/bash 
geschrieben habe, gilt nicht.  Ist keine Bash vorhanden, kannst Du 
eventuell etwas aus dem Gerüst übernehmen.

Und noch was, was mir aufgefallen ist: zwischen ${BASH_REMATCH[1]} und 
${BASH_REMATCH[2]} ist genau 1 Space und 1 Tab.  Den Tab scheint die 
Forensoftware trotz pre../pre zu expandieren.

von Andreas F. (aferber)


Lesenswert?

A. K. schrieb:
> Evtl. das Debugging-Format des erzeugten Binaries analysieren. Da steht
> sowas drin.

Für C-Code gibt es pstruct, das ist bei Perl mit dabei (als Variante von 
c2ph, womit zu C-Headern automatisch Perl-Module generiert werden 
können), damit kann aus dem generierten Assemblercode das Layout einer 
struct extrahiert werden.
1
% avr-gcc -g -S -o struct_test_c.s struct_test_c.c
2
% pstruct struct_test_c.s
3
struct inner {
4
  int                inner.xyzzy                0       2
5
}
6
7
struct test_struct {
8
  char               test_struct.bar            0       1
9
  int                test_struct.baz            1       2
10
  struct inner       test_struct.sub            3       2
11
    int              test_struct.sub.xyzzy      3       2
12
}

Erste Zahlen-Spalte ist der Offset, zweite die Grösse des Feldes.

Leider kommt das Tool derzeit mit C++-Debuginformationen nicht klar 
(auch nicht für eine simple struct, wenn g++ verwendet wird), aber 
vielleicht kann der Code als Ausgangspunkt verwendet werden.

Andreas

von rw (Gast)


Lesenswert?

@mizch:
danke erst einmal. Dein Script läuft unter Cygwin, aber ich kann nicht 
erkennen, was es anderes ausgibt, als eine Auswahl der Symbole nebst 
ihrer Größe und Ladeadresse die ich auch mit "avr-objdump -t" oder über 
die Memory-Map des Linkers herausbekommen würde.

@aferber:
Ja, so etwas wie pstruct bräuchte ich, dass auch mit C++ umgehen kann. 
Ich habe gerade mal ddd ausprobiert. Damit kann ich mir immerhin schon 
einmal meine globale Systemvariable mit allen Elementen als grafischen 
Baum anschauen. Allerdings gibt es mir keine Informationen über die 
einzelnen Größen/Offsets der Variablen und überhaupt bekomme ich diesen 
Baum nur als Bild aus ddd exportiert.

Ich habe das ELF mal in den gdb geladen. Mit Aufrufen wie "print 
&globalesObjekt.member.tiefer.undnochTiefer" kann ich mir alle Adressen 
von beliebigen Membern anzeigen lassen. Jetzt möchte ich das ganze aber 
umgekehrt machen. Das heißt: Ich möchte eine Adresse eingeben und eine 
Variable zurück bekommen. Dafür konnte ich aber (noch) keinen Befehl 
finden.

von Andreas F. (aferber)


Lesenswert?

rw schrieb:
> Das heißt: Ich möchte eine Adresse eingeben und eine
> Variable zurück bekommen. Dafür konnte ich aber (noch) keinen Befehl
> finden.
1
(gdb) info symbol 0x0804957b
2
test_var + 11 in section .bss

Allerdings erhältst du so keine Informationen darüber, welchen Member du 
"getroffen" hast, nur den nackten Offset in die Variable. Um die 
komplette Struct anschliessend auszugeben reicht es aber natürlich.

Funktioniert natürlich nur mit statischen Variablen (static storage 
duration, nicht static linkage).

Andreas

von rw (Gast)


Lesenswert?

Japp. Das habe ich auch gesehen, aber das nützt mir nicht viel.

Um zum Ziel zu kommen, habe ich es jetzt folgendermaßen gemacht:
1
print meinGlobalesObjekt
gibt mir einen String zurück, welcher den gesamten rekursiven Aufbau von 
meinGlobalesObjekt mit allen Membern nebst ihren Typen enthält. Da diese 
Ausgabe wohlstrukturiert ist, kann mir ein kleines Script alle 
Variablennamen (eines bestimmten Typs) zusammenbauen.

Dieser Liste kann ich dann mit
1
print &variable
die jeweiligen Adressen zuordnen und sie so weiterverarbeiten.

Vielen Dank für's Mitdenken.
Richard

von Roberto (Gast)


Lesenswert?

Eine weitere Möglichkeit ist

avr-readelf -wi test.elf

damit wird die komplette Symboltabelle ausgegeben, aus der sich alle 
Informationen zusammenbauen lassen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.