Vorab: Ich habe es mit einem embbeded system zu tun, dass wir in C++ programmieren wollen. Damit haben wir beschränkten Speicher, keine Festplatte und im echten Betrieb auch kein Dumpterminal oder Dergleichen. Angeschlossen an die Cpu ist nur ein Flashspeicher, auf dem seriell Datenrecords gespeichert werden. Nun - Leider ist es ja bislang kaum jemanden gelungen, Programme absolut absturzsicher zu schreiben. Ich habe mir aber überlegt im Falle eines Abstruzes (Watchdog reset, etc) zumindest eine kurze Nachricht zurückzulassen. Dafür habe ich einen kleinen nicht initialisierten RAM - Bereich vorgesehen. In diesem sollen pointer auf Instanz und die lezte ausgeführte Methode und optional ein darin enthaltener Watchpoint sowie gegebenenfalls relevante 8, 16,32 bit Daten gespeichert werden. und nun mein Problem: Wie kann ich auf möglich einfache Weise die addresse einer gerade ausgeführten Methode ermitteln? für konstruktive Beiträge schonmal vorab danke
Dafür gibt es keine allgemeine Lösung in C++. Wenn du uns mitteilst um welche spezielle Hardware es geht, kann man vielleicht dafür eine Lösung finden. Einige Mikrocontroller sichern den PC im Fehlerfall und springen einen entsprechenden Interrupt an. Dort könnte man den PC und andere Infos in den RAM schreiben um diese später auszuwerten.
Alex2.2 schrieb: > Wie kann ich auf möglich einfache Weise die addresse einer gerade > ausgeführten Methode ermitteln? Willst du die denn wirklich wissen? Nicht vielmehr welche Methode? Eine mühsame Möglichkeit besteht darin, zu Anfang jeder Funktion bzw. Methode eine Debug-Variable auf einen bestimmten Wert zu setzen (und dafür zu sorgen, dass das nicht wegoptimiert wird). Georg
am einfachsten wäre wohl: - eine globale, statische variable - ein Header file, wobei du dir folgende Makros definierst: - #MAIN_FUNC 0 #IWAS_FUNC MAIN_FUNC + 1 ... in jedem Funktionsaufruf schreibst dann in die statische Variable einen zugehörigen Wert. Allerdings haut dir dein Watchdog-Reset auch die statische Variable weg, weswegen du entweder irgendwie externen RAM brauchst oder ein EEPROM...
Speichere doch einfach den aktuellen Program Counter. Mit dem Disassembly kommt man so leicht an die Funktion und sogar die genaue Stelle.
Wenns der GCC ist, oder mindestens C99, dann schau dich hier um: https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
Wenn du weisst, in welcher methode du bist (z.B. getInfo()), dann kannst du natürlich auch mit dem Adressoperator die Adresse holen (also &getInfo beispielsweise). PS: für die aktuelle Funktion hat der gcc wiederum ein Makro, wahrscheinlich siehe Link oben von A.K. oder in der Nähe davon.
:
Bearbeitet durch User
Falls GCC:
1 | __builtin_return_address (0) |
https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html Das liefert nicht die Adresse der Funktion, sondern die Stelle, von der aus die (effektive) Funktion aufgerufen wurde. (bzw. die Adresse nach dem CALL). Es liefert also sogar mehr Info als gewünscht, da der Callee einfach aus der Call-Site ermittelt werden kann. "effektiv" bedeutet nach Inlining und Function Cloning und nur modulo Tail-Calling. Generell ist die Anschaffung von Debug-Hardware engezeigt, z.B. mit OCDS o.ä. https://de.wikipedia.org/wiki/OCDS Nur so kann nicht-invasiv debuggt werden. printf, cout und Konsorten zu verwenden ist einerseits invasiv und andererseits kein Debugging, sondern Logging.
Klaus W. schrieb: > PS: für die aktuelle Funktion hat der gcc wiederum ein Makro, > wahrscheinlich siehe Link oben von A.K. oder in der Nähe davon. Wollte ich auch erst vorschlagen. Es gibt ein _FUNCTION_ (wie krieg ich das Unterstrichene hier weg?) Macro das den Namen der aktuellen Funktion enthält. Blöderweise sind da Anführungszeichen drumherum, wenn man also &__FUNCTION__ schreibt kriegt man die Adresse des Strings wo der Name der Funktion drin steht. Wobei das auch ganz praktisch sein könnte.
:
Bearbeitet durch User
Sebastian V. schrieb: > Es gibt ein FUNCTION (wie krieg > ich das Unterstrichene hier weg?) In Code-Tags einschließen:
1 | __FUNCTION__ |
oder kursiv machen, da wohl mehrere Formatierungen gleichzeitig nicht unterstützt werden: __FUNCTION__ Sebastian V. schrieb: > Blöderweise sind da Anführungszeichen drumherum, wenn > man also &__FUNCTION__ schreibt kriegt man die Adresse des Strings wo > der Name der Funktion drin steht. Naja, was heißt Anführungszeichen? __FUNCTION__ ist eine Stringvariable. In C++ mit gcc würde sich übrigens __PRETTY_FUNCTION__ anbieten. Das enthält dann nicht nur den reinen Namen, sondern die ganze Signatur der Funktion.
:
Bearbeitet durch User
Beim gcc wäre evtl. auch -finstrument-functions und Verwandtschaft eine Überlegung wert. https://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/Code-Gen-Options.html Aber sowas verwende ich eigentlich nur auf ausgewachsenen Rechnern und zu sehr speziellen Zwecken während der Entwicklung, nie für Software, die in den produktiven Einsatz geht.
Zunächst einmal danke. Ich hatte das bereits befürchtet. Ich würde wirklich gerne die Addresse wissen und nicht marker of den _FUNCTION_ string. Es handelt sich um einen Renesas RX, der durchaus informationen über Resetursachen und vieles mehr anbietet. Geschrieben wird mit IAR C/C++ für RX Prozessoren. Eure genannten Möglichkeiten hatte ich auch bereits in Erwägung gezogen, bin aber nicht wirklich glücklich damit. Diese Firmware wird doch bereits sehr komplex aber soll mit Sicherheit nicht auf einem OS laufen. nochmals danke
Rolf M. schrieb: > Naja, was heißt Anführungszeichen? _FUNCTION_ ist eine > Stringvariable. Zu einer Variable wird es aber erst wenn der Compiler drüber läuft. Der Präprozessor macht ja erstmal nur eine Textersetzung. Alex2.2 schrieb: > Ich würde wirklich gerne die Addresse wissen Dazu fällt mir noch mindestens ein Problem ein. Du sagtest, dass du C++ benutzt und dann willst du sicher auch die Adressen von Memberfunktionen. Allerdings sind Pointer auf Memberfunktionen (PMF) echt komische Tiere. Ich habe gerade mal in VS ausprobiert einen PMF zu einem void* zu konvertieren. Lässt mich der Compiler nicht machen, weder mit C-style cast noch reinterpret_cast.
Liefert backtrace() nicht letztlich alles, was du brauchst? http://www.linuxjournal.com/article/6391
Klaus W. schrieb: > Liefert backtrace() nicht letztlich alles, was du brauchst? gibt's bei IAR nicht. Zu dumm aber das wär's natürlich. Nun gut ich habe mir da etwas zusammengebaut in Richtung "hole dir den Inhalt des PC und sichere den erstmal. Da geht bei IAR dann so:
1 | #define __getCurrentAddress(aPtr)\ |
2 | register u32 aPtr;\ |
3 | asm("mvfc pc, %[ptr] \n"\ |
4 | : [ptr]"=r"(aPtr)); |
und innhalb jeder Methode dann
1 | void aClass::aMethode(void) |
2 | { |
3 | __getCurrentAddress(aPtr); |
4 | Euroscan::system::watchdog.enterMethod(this, aPtr); |
5 | //do somthing |
6 | Euroscan::system::watchdog.leaveMethod(this, aPtr); |
7 | } |
diese Verfahren ist nicht exakt, da normalerweise noch ein bischen Compileroverhead in Form von push operationen, ...etc entsteht aber es ist sicher erstmal hilfreich um Firmwarefehler zu analysieren.
Wolltest du nicht C++ machen? Und dann so ein Makro? :-) Eine inline-Funktion mit demselben Inhalt würde doch netter aussehn...
Klaus W. schrieb: > Wolltest du nicht C++ machen? Und dann so ein Makro? :-) > Eine inline-Funktion mit demselben Inhalt würde doch netter aussehn... stimmt du hast recht. Hab zuviel C gemacht. Daher wird das noch ein inline. ;-)
Sebastian V. schrieb: > Rolf M. schrieb: >> Naja, was heißt Anführungszeichen? FUNCTION ist eine >> Stringvariable. > > Zu einer Variable wird es aber erst wenn der Compiler drüber läuft. Der > Präprozessor macht ja erstmal nur eine Textersetzung. Der Präprozessor hat da gar nichts damit zu tun. Nochmal: __FUNCTION__ ist eine Variable, kein Präprozessor-Makro. Siehe https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html > Allerdings sind Pointer auf Memberfunktionen (PMF) echt komische Tiere. Ich > habe gerade mal in VS ausprobiert einen PMF zu einem void* zu konvertieren. > Lässt mich der Compiler nicht machen, weder mit C-style cast noch > reinterpret_cast. Streng genommmen dürfte er das schon mit normalen Funktionszeigern nicht.
Rolf M. schrieb: >> Allerdings sind Pointer auf Memberfunktionen (PMF) echt komische Tiere. Ich >> habe gerade mal in VS ausprobiert einen PMF zu einem void* zu konvertieren. >> Lässt mich der Compiler nicht machen, weder mit C-style cast noch >> reinterpret_cast. > > Streng genommmen dürfte er das schon mit normalen Funktionszeigern > nicht. Darf man auch nicht und mit vielen Compilern, z. B. meinem geht das auch nicht, jedenfalls nicht ohne riskante tricks. Da ich eine stabile Firmware möchte (die lässt sich nähmlich nicht mal so eben upgraden) mache ich das auch nicht.
Alex2.2 schrieb: >> Ich habe mir aber überlegt im Falle eines Abstruzes (Watchdog reset, >> etc) zumindest eine kurze Nachricht zurückzulassen. Sämtliche nützliche Informationen müssen VOR dem Absturz/WD-Reset gesichert worden sein.
StinkyWinky schrieb: > Sämtliche nützliche Informationen müssen VOR dem Absturz/WD-Reset > gesichert worden sein. Ach - wirklich? Nun deswegen möchte ich ja auch VOR dem Absturz sicherstellen, dass ich an einer nicht initialisierten Stelle im Speicher zumindest ungefähr die Position speichere, an der sich die Programverarbeitung befand als es knallte. Da ich nicht in der kompfotablen Lage bin, einen kompletten Stack auf einem nicht befindlichem Monitor anzuzeigen oder in einen auf einer nicht vorhanden Festplatte in einen Logfile abzulegen, muß ich es mit möglichst kleinen Notizen machen, die dann als Record zwischen den normalen Daten auf einen kleinen Datenflash geschrieben werden. Diese kann man im Fehlerfalle oder bei Reclamationen auswerten. Deutlich?
Hallo Alex2.2, Sebastian V. schrieb: > Dafür gibt es keine allgemeine Lösung in C++. Wenn du uns mitteilst um > welche spezielle Hardware es geht, kann man vielleicht dafür eine Lösung > finden. Einige Mikrocontroller sichern den PC im Fehlerfall und springen > einen entsprechenden Interrupt an. Dort könnte man den PC und andere > Infos in den RAM schreiben um diese später auszuwerten. Das ist die einzige "vernünftige" Antwort die Du bekommen wirst. Zuerst solltest Du mal gucken, was ein Absturz den wirklich ist. In der Regel läuft es immer auf eine hardware trap hinaus. Dort wird ein Interrupt Handler aufgerufen und in dem Moment liegt die Adresse, die Du suchst auf dem Stack. Dort musst Du sie nur noch abholen! Wo sie genau steht, solltest Du im Reference Manual Deiner CPU finden. mfg Torsten
So machen es die Arduinos. https://github.com/Megunolink/ArduinoCrashMonitor/blob/master/CrashTracking/ApplicationMonitor.cpp
Alex2.2 schrieb: >> Streng genommmen dürfte er das schon mit normalen Funktionszeigern >> nicht. > > Darf man auch nicht Schön, daß du das nochmal wiederholst, falls jemand es bei mir nicht gelesen haben sollte... > und mit vielen Compilern, z. B. meinem geht das auch nicht, jedenfalls > nicht ohne riskante tricks. Auf vielen anderen Compilern, vor allem auf dem PC, ist es aber Gang und Gäbe, weil recht grundlegende Funktionen das voraussetzen.
Rolf M. schrieb: >> und mit vielen Compilern, z. B. meinem geht das auch nicht, jedenfalls >> nicht ohne riskante tricks. > > Auf vielen anderen Compilern, vor allem auf dem PC, ist es aber Gang und > Gäbe, weil recht grundlegende Funktionen das voraussetzen. Wird z.B. für Signal-Handler-Bindung (Delegates) in boost::bind() oder auch QT genutzt. Und da ist das schon 'ne feine Sache für solche Objekt-Request-Broker-Geschichten. Aber es ist schon wahr, das Handling von Member-Funktionspointern ist aufgrund der Typbindung an die Klasse sicher kein triviales Einsteigerthema und erfordert schon etwas Verständnis, wie das C++-Objektmodell und das Typensystem funktioniert. Ich erwisch mich da auch öfters mal damit, das wenn ich das für 'ne Objektbindung für eine bestimmte Lösung mal brauche, wieder nachzuschlagen.
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.