Hallo zusammen, Ich versuche, mit GDB/openOCD ein Projekt zu debuggen. Grösstenteils funktioniert alles bestens, jedoch in einem File, task.c von FreeRTOS (oder zumindest in bestimmten Funktionen innerhalb dieses Files) findet GDB den Source nicht. Er meint dann z.B. beim steppen: "No line number information available for address" Wenn ich task.o mit Objdump anschaue, sehe ich den Sourcecode, auch die Funktionen, die GDB nicht findet. info sources sagt mir, dass task.c eingebunden ist. Hat jemand von Euch auch schon ein ähnliches Problem gehabt? BTW - Wo steht eigentlich die "line number information?" Sprich - wo steht, in welchem File und auf welcher Zeile der Source code für einen bestimmten Maschinencode steht? Das müsste nach meiner Logik ja auch im Object-File drin stehen, oder? Gruss & danke Simon
„No line number information available“ bedeutet normalerweise, dass ohne -g übersetzt wurde. Dazu passt allerdings nicht, dass mit objdump der Source da ist. Wurde task.o danach mit [avr-]strip behandelt? Das würde dann wieder passen. Simon Huwyler schrieb: > Sprich - wo > steht, in welchem File und auf welcher Zeile der Source code für einen > bestimmten Maschinencode steht? Das steht in einer eigenen Section im .o und .elf.
Hmmmm.... ich sehe gerade etwas sehr verdächtiges: Aus: /* Allocate the memory required by the TCB and stack for the new task, checking that the allocation was successful. */ pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer ); if( pxNewTCB != NULL ) { portSTACK_TYPE *pxTopOfStack; #if( portUSING_MPU_WRAPPERS == 1 ) /* Should the task be created in privileged mode? */ portBASE_TYPE xRunPrivileged; if( ( uxPriority & portPRIVILEGE_BIT ) != 0x00 ) { xRunPrivileged = pdTRUE; } else { xRunPrivileged = pdFALSE; } uxPriority &= ~portPRIVILEGE_BIT; #endif /* portUSING_MPU_WRAPPERS == 1 */ /* Calculate the top of stack address. This depends on whether the stack grows from high memory to low (as per the 80x86) or visa versa. portSTACK_GROWTH is used to make the result positive or negative as required by the port. */ #if( portSTACK_GROWTH < 0 ) { macht der: /* Allocate the memory required by the TCB and stack for the new task, checking that the allocation was successful. */ pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer ); 10: f8bd 300e ldrh.w r3, [sp, #14] 14: 4618 mov r0, r3 16: 990e ldr r1, [sp, #56] ; 0x38 18: f7ff fffe bl 0 <xTaskGenericCreate> 1c: 4603 mov r3, r0 1e: 9308 str r3, [sp, #32] if( pxNewTCB != NULL ) 20: 9b08 ldr r3, [sp, #32] 22: 2b00 cmp r3, #0 24: f000 80b1 beq.w 18a <xTaskGenericCreate+0x18a> stack grows from high memory to low (as per the 80x86) or visa versa. portSTACK_GROWTH is used to make the result positive or negative as required by the port. */ #if( portSTACK_GROWTH < 0 ) { pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 ); 28: 9b08 ldr r3, [sp, #32] 2a: 6b1a ldr r2, [r3, #48] ; 0x30 Der Stinker hat 'ne Zeile vergessen! (das #if statement ist false - aber unten, da fehlt eine Kommentarzeile) Wie kann denn das passieren? Nochmals meine Frage: Hat jemand von Euch schon mit so was gekämpft?
Ich würde sagen, da hat der Präprozessor das #if wegrationalisiert. EDIT: das hast Du gesehen. Dass Kommentarzeilen nicht vollständig sind, hat nichts zu sagen. Es ist ja der zusammengemischte Mix, den objdump -d hinterher erzeugt und nichts, was der Compiler sieht. Die Kommentarzeilen und der C-Source sind nur für Dich zur Information.
Vielen Dank schon mal für die Antwort! Nö Strip habe ich ich nicht verwendet. Habe auch gerade gesehen, dass er bei den "intakten" Files ebenfalls Teile der Kommentare weglässt. Wie kann ich die Source-Info aus dem elf-File rausholen?
Hc Zimmerer schrieb: > Es ist ja der zusammengemischte Mix, den > objdump -d hinterher erzeugt und nichts, was der Compiler sieht. Dazu noch 'ne Frage: Woher hat denn eigentlich objdump die Information? Steht der Sourcecode vollständig im objectfile, wenn ich mit -g compiliere? Oder holt sich objdump den aus den Sources? Und wenn ja, woher weiss es, aus welchen Sources? Oder anders: Findet Objdump und gcc den Sourcecode auf die selbe Weise? Oder werden da ganz andere Prinzipien angewandt?
avr-objdump -Sl *.elf sollte Dir u.a. die Zeilennummern zeigen, etwa so:
1 | incrementalCleanup(): |
2 | /U/minni-hcz/Projekte/108/tank-main.c:392 |
3 | ... |
Simon Huwyler schrieb: > Dazu noch 'ne Frage: Woher hat denn eigentlich objdump die Information? > Steht der Sourcecode vollständig im objectfile, wenn ich mit -g > compiliere? Oder holt sich objdump den aus den Sources? Und wenn ja, > woher weiss es, aus welchen Sources? Er holt sich's aus den Sourcen. Woher er die weiß: siehe einen Artikel drüber. (Damit er denselben auf verschiedenen Maschinen findet, ist der Pfad übrigens dort ein NFS-Automount (/U).)
Vielen Dank! Ich habe das mal probiert - und siehe da: void vTaskStartScheduler() { 8001c1c: b500 push {lr} 8001c1e: b087 sub sp, #28 /home/simon/PLH/PLH1/FreeRTOS/Source/task.c:1054 portBASE_TYPE xReturn; task.c existiert genau an dieser Stelle, und auf Zeile 1054 steht die erste Instruktion von vTaskStartScheduler(). Compiler und Linker scheinen also alles richtig gemacht zu haben. Warum zum Geier findet GDB diesen Code nicht, anderen Code, dessen Sources im selben Verzeichnis sind, jedoch schon?
Wenn der Pfad stimmt (also der Source nicht nur im gleichen Verzeichnis steht, sondern auch dort übersetzt wurde) und das der objdump des .elf war, bin ich leider auch mit meinem Latein am Ende.
Ich wollte nur kurz mitteilen, dass es inzwischen geklappt hat mit dem GDB. Einerseits bin ich sehr zufrieden, andererseits verwirrter denn je. Das von mir benutzte Makefile-Template (von Martin Thomas) aktiviert die GCC-Switches -ffunction-sections und -fdata-sections. Als ich die mal rausgenommen hatte, passierte etwas SEHR merkwürdiges: Beim Rebuild mooste der Linker, er fände ein Symbol nicht. Es war irgendwas in der Umgebung der Syscalls, weiss nicht mehr genau, welches. Aber - und das ist jetzt wirklich strange - ich sah, dass er es tatsächlich nicht finden KONNTE! Weil es schlicht nicht existierte (durch #ifdef ausgeblendet - ist ein Inline-Assembler Stub, und folglich compilerabhängig). Deswegen meine Verwirrung: - Wie zum Geier konnte der vorher linken??? Das Programm liess sich zwar teilweise (betraf eine gaaaaanz andere Funktion) nicht debuggen, aber es funktionierte bestens! - Was zum Geier hat das mit obigen Compiler-Switches zu tun??? Aber eben: Eigentlich bin ich nur froh, dass es läuft. Und ich dachte, das interessiert zumindest Hc Zimmerer - auch wenn mein Latein nie und nimmer ausreicht, zu erklären, wie obiges Phänomen zustande kam. :-)
-ffunction-section und -fdata-sections sorgt dafür, dass jeder Funktion und jeder Variable vom Compiler eine eigene Input-Section zugewiesen wird. Damit hat der Linker bei aktivierter Option --gc-sections die Möglichkeit, Input-Sections zu verwerfen (=nicht in output-sections aufzunehmen), die nicht genutzt werden. Es könnte sein, dass eine Funktion vom Compiler "geinlined" wurde. Wenn eine "extern" sichtbare Fassung der Funktion nicht benötigt wird, konnte diese wg. --gc-sections entsorgt wurden. Da nicht mehr vorhanden, gab es keine Linker-Fehler. Dann wäre es aber so, das die "geinlinete"-Variante aus irgend einem Grund eine Abhängigkeit nicht aufweisen würde, die bei der "sichtbaren" Variante vorhanden ist. Ist nur eine wenig fundierte Vermutung. Man bräuchte ein minimales aber funktionsfähiges Beispiel, um dieser Sache etwas nachgehen zu können. Was passiert, wenn -ffunction-sections aktiviert bleibt und Linker-Option --gc-sections entfernt wird?
Hey, da ist er ja, der Martin! :-) Gleich zu begin: Vielen Dank für Deine umfangreichen Templates und Projekte!! Hast (wohl nicht nur) mir viel Arbeit erspart! Builden tu ich nur noch mit Deinen Templates, und am Wochenende habe ich gerade "Dein" FAT (Deine Implementation für Cortex) in Betrieb genommen! Ja, irgendwie in diese Richtung stelle ich mir das auch vor. Habe gerade beim Mittagessen darüber nachgedacht und mit Kollegen darüber geredet (allerdings handelt es sich in diesem Fall um ein Hobby-Projekt). Ich könnte mal diesen Schritt wieder rückgängig machen und schauen, welche Funktionen denn von dem Fehler betroffen sind. Und dann mal schauen, wohin diese Funktionen gelinkt werden. Vielleicht entsteht irgendwie irgendwo ein Mismatch, ausgelöst durch eine nicht aufgelöste (und vielleicht wie von Dir gesagt auch nicht benötigte) Referenz, der sich dann auf nachfolgend eingelinkte Funktionen fortpflanzt. Wenn ich mal Zeit habe, werde ich das machen. Gruäss Simon
Hallo nochmals, ich habe zwar die Untersuchungen, die ich vorhatte, mangels Zeit nicht gemacht, jedoch habe ich im Buch The Definitive Guide to GCC von William Von Hagen gelesen, dass sich -fdata-sections und -g tatsächlich beissen. Die sollte man wohl nicht zusammen verwenden. Ich nehme das jetzt einfach so zur Kenntnis. Stört ja nicht. Solange ich debugge, ist jegliche Optimierung ja eh zweitrangig resp. unerwünscht. Gruäss Simon
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.