Forum: Mikrocontroller und Digitale Elektronik Keil Hardfault STM32 Jlink


von Peter Trace (Gast)


Angehängte Dateien:

Lesenswert?

Hallo, ich hab schon auf google viel Zeit verbracht, aber ich verstehe 
es noch nicht ganz.

Mein Code erzeugt einen Hardfault, diesen Fehler konnte ich mit 
"auskommentiern" finden.
1
void uart_get_time(void)
2
{
3
 char str[10]; //zu klein
4
 uint32_t rtc_time=rtc_get_day_time();
5
 uint8_t stu,min,sek;
6
  
7
 rtc_calc_time(&stu,&min,&sek,rtc_time);
8
  
9
 sprintf(str,"System-Uhrzeit %0.2d:%0.2d:%0.2dUhr \n", stu, min, sek);
10
 uart_send_s(str);
11
}

Aber wie findet man das ganze eleganter/schneller? Ich hab einen J-Link 
ohne ETM-Trace und die Keil EDU. Der Controller ist ein 
STM32F103C8/M3-Core.

IBUSERR heißt, dass der M3 den Fehler beim prefetch erkannt hat?
BFARVALID ist nicht gesetzt, also BFAR ignorieren oder?

von step one (Gast)


Lesenswert?

Peter Trace schrieb:
> Aber wie findet man das ganze eleganter/schneller?

In dem man immer selber eine Routine für den Hard Fault definiert und 
dort einen Breakpoint platziert. Den Grund für den Hard Fault kann man 
dann auslesen.

von Nop (Gast)


Lesenswert?

step one schrieb:

> In dem man immer selber eine Routine für den Hard Fault definiert und
> dort einen Breakpoint platziert. Den Grund für den Hard Fault kann man
> dann auslesen.

Und an SP+24 auch die Faultadresse, was einem zusammen mit dem Mapfile 
verrät, wo der Fehler passiert ist.

von Steffen R. (steffen_rose)


Lesenswert?

Hilft dir bei einem Stackfehler wie oben aber nur bedingt.
Der Hardfault tritt dann meist nicht dort auf wo der Stack kaputtgemacht 
wird.

Bei vielen anderen Zugriffs-Fehlern hilft es allerdings.

von ARMler (Gast)


Lesenswert?

Wenn deine Entwicklungsumgebung kein einfaches 'Backtrace' hat, dass 
auch aus einem Hardfault funktioniert, wechsle zu einer die das kann, 
oder baue dir ein Workaround das auf Kommando ein Backtrace liefert.

Alles andere ist doch sehr suboptimal..

von Bauform B. (bauformb)


Lesenswert?

Peter Trace schrieb:
> void uart_get_time(void)
> {
>  sprintf(str,"System-Uhrzeit %0.2d:%0.2d:%0.2dUhr \n", stu, min, sek);
> }
>
> Aber wie findet man das ganze eleganter/schneller?

Indem man snprintf() (mit der Betonung auf 'n') verwendet. Dass es 
sprintf() immer noch gibt ist eine Gemeinheit.

Manche Stack-Fehler kann man mit der MPU abfangen. Aber auch ohne MPU 
kann man den Stack auf der niedrigsten RAM-Adresse beginnen lassen. Dann 
gibt es einen Bus Error, wenn der Stack zu voll wird. Ich werde nie 
verstehen, was so toll daran ist, wenn der Stack den Heap überschreibt. 
Masochismus?

> Ich hab einen J-Link ohne ETM-Trace und die Keil EDU.

Mit dem GCC und den binutils bekommst du das Kommandozeilen Tools 
addr2line, das zeigt dir die Quelltextzeile passend zur Fault Adresse 
bei SP+24 an. Wenn allerdings der Stack überschrieben wurde... Aber das 
passiert dank snprintf() ja nicht :)

von Dr. Sommer (Gast)


Lesenswert?

Hmm, wenn man C++ nutzt kann man einen kleinen Trick machen um den 
sprintf-Fehler zu vermeiden:
1
template <std::size_t N, typename... Args>
2
inline int autosprintf (char (&str) [N], const char* fmt, Args&&... args) __attribute__ ((format (printf, 2, 3)));
3
4
template <std::size_t N, typename... Args>
5
inline int autosprintf (char (&str) [N], const char* fmt, Args&&... args) {
6
  return snprintf (str, N, fmt, std::forward<Args> (args)...);
7
}
8
9
int main () {
10
  char str[10]; //zu klein
11
  autosprintf(str,"System-Uhrzeit %0.2d:%0.2d:%0.2dUhr \n", stu, min, sek);
12
}

Dann wird die Array-Größe automatisch übergeben; man kann sie nicht 
vergessen, und auch nicht falsch angeben. Ungetestet :)

von Felix F. (wiesel8)


Lesenswert?

Dr. Sommer schrieb:
> Hmm, wenn man C++ nutzt kann man einen kleinen Trick machen um den
> sprintf-Fehler zu vermeiden:
> ...
> Dann wird die Array-Größe automatisch übergeben; man kann sie nicht
> vergessen, und auch nicht falsch angeben. Ungetestet :)


Ja, oder man nimmt dann gleich die string-Klasse ala:
1
my_text << "Hallo";

Aber das wäre dann wohl zu einfach für dich oder?

mfg

von Dr. Sommer (Gast)


Lesenswert?

Felix F. schrieb:
> Ja, oder man nimmt dann gleich die string-Klasse ala:

Welche string-Klasse kann das, und kommt die ohne dynamischen Speicher 
aus, so wie s(n)printf?

von Felix F. (wiesel8)


Lesenswert?

Dr. Sommer schrieb:
> Felix F. schrieb:
>> Ja, oder man nimmt dann gleich die string-Klasse ala:
>
> Welche string-Klasse kann das, und kommt die ohne dynamischen Speicher
> aus, so wie s(n)printf?

So weit mir bekannt, gibt es nur 1 std::string Klasse und die kann 
natürlich alles, was auch im Standard definiert ist. Worauf willst du 
hinaus?

Wenn ich keine dyn. Speicherallokierung will, dann verwendet man halt 
Plain-C wie snprintf (wie bereits genannt) und keine auf irgendwelche 
Spezialfälle zusammengeschusterten Mixes die deine Speicherfehler 
verschleiern.

mfg

von Dr. Sommer (Gast)


Lesenswert?

Felix F. schrieb:
> So weit mir bekannt, gibt es nur 1 std::string Klasse und die kann
> natürlich alles, was auch im Standard definiert ist. Worauf willst du
> hinaus?

Darauf, dass sie nicht das kann, was du vorgeschlagen hast (Operator 
<<).

Felix F. schrieb:
> Wenn ich keine dyn. Speicherallokierung will, dann verwendet man halt
> Plain-C wie snprintf (wie bereits genannt) und keine auf irgendwelche
> Spezialfälle zusammengeschusterten Mixes die deine Speicherfehler
> verschleiern.
Begründung? Der Speicherfehler wird verhindert, nicht verschleiert.

von Simon D. (simon_d273)


Lesenswert?

Peter Trace schrieb:
> Hallo, ich hab schon auf google viel Zeit verbracht, aber ich verstehe
> es noch nicht ganz.
>
> Mein Code erzeugt einen Hardfault, diesen Fehler konnte ich mit
> "auskommentiern" finden.
>
> Aber wie findet man das ganze eleganter/schneller? Ich hab einen J-Link
> ohne ETM-Trace und die Keil EDU. Der Controller ist ein
> STM32F103C8/M3-Core.
>
> IBUSERR heißt, dass der M3 den Fehler beim prefetch erkannt hat?
> BFARVALID ist nicht gesetzt, also BFAR ignorieren oder?

Du landest ja im hard fault handler mit der Endlosschleife. Dann gehst 
du in callstack and locals und wählst den Händler aus und lässt dir im 
Kontextmenü den caller geben. Dann wird dir die Stelle in code und 
disassembly gezeigt.

von Felix F. (wiesel8)


Lesenswert?

Dr. Sommer schrieb:
> Felix F. schrieb:
>> So weit mir bekannt, gibt es nur 1 std::string Klasse und die kann
>> natürlich alles, was auch im Standard definiert ist. Worauf willst du
>> hinaus?
>
> Darauf, dass sie nicht das kann, was du vorgeschlagen hast (Operator
> <<).
>
> Felix F. schrieb:
>> Wenn ich keine dyn. Speicherallokierung will, dann verwendet man halt
>> Plain-C wie snprintf (wie bereits genannt) und keine auf irgendwelche
>> Spezialfälle zusammengeschusterten Mixes die deine Speicherfehler
>> verschleiern.
> Begründung? Der Speicherfehler wird verhindert, nicht verschleiert.

Oh, stimmt. Habe das mit stringstream verwechselt. Muss natürlich '=' 
lauten. Ändert aber jetzt vom Prinzip der automatischen Größenanpassung 
nichts.

Wenn ich in str[10] mehr als 10 Zeichen schreiben kann, wird der Fehler 
verschleiert. Wenn ich dahinter einfach reserved[10] schreibe, ist der 
Fehler auch behoben, weil ich jetzt in reserved schreibe. Schöner wirds 
dadurch aber auch nicht.

mfg

von Dr. Sommer (Gast)


Lesenswert?

Felix F. schrieb:
> Wenn ich in str[10] mehr als 10 Zeichen schreiben kann, wird der Fehler
> verschleiert.

Kannst du nicht. Die autosprintf-Funktion übergibt automatisch "10" an 
snprintf, und der String wird abgeschnitten, es wird nichts in 
"reserved" geschrieben, es tritt kein Buffer Overflow ein.

von P.Loetmichel (Gast)


Lesenswert?

> es tritt kein Buffer Overflow ein

Das macht Bascom schon immer so.

von Dr. Sommer (Gast)


Lesenswert?

P.Loetmichel schrieb:
> Das macht Bascom schon immer so.

D.h. man kann da nie aus Effizienzgründen bei sauberer Programmierung 
die Range-Checks abschalten? Schwach.

von Felix F. (wiesel8)


Lesenswert?

Dr. Sommer schrieb:
> Felix F. schrieb:
>> Wenn ich in str[10] mehr als 10 Zeichen schreiben kann, wird der Fehler
>> verschleiert.
>
> Kannst du nicht. Die autosprintf-Funktion übergibt automatisch "10" an
> snprintf, und der String wird abgeschnitten, es wird nichts in
> "reserved" geschrieben, es tritt kein Buffer Overflow ein.

Achso, dann habe ich da was falsch verstanden.

Dann würde ich aber gleich zum korrekten Ansatz raten:
1
char str[MAX];
2
snprintf(str, MAX, "bla bla");

mfg

von Dr. Sommer (Gast)


Lesenswert?

Felix F. schrieb:
> Dann würde ich aber gleich zum korrekten Ansatz raten:

Wenn man jetzt aber die Array-Größe auf "MAX-3" ändert muss man dran 
denken, das bei snprintf auch zu tun. Mit dem template entfällt das, 
weil automatisch immer die tatsächliche Array-Größe genutzt wird.

von W.S. (Gast)


Lesenswert?

Peter Trace schrieb:
> Hallo, ich hab schon auf google viel Zeit verbracht, aber ich verstehe
> es noch nicht ganz.

Tja. Das sind die Leiden der jungen Ignoranten, die partout sich auf 
einem µC genau so benehmen wollen wie auf dem PC, wo sie ein 
fürsorgliches Betriebssystem und schier unendlich viel RAM haben.

Aber der TO hat wohl sein Problem aus den Augen verloren, also was 
soll's.

W.S.

von Bauform B. (bauformb)


Lesenswert?

Dr. Sommer schrieb:
> Felix F. schrieb:
>> Dann würde ich aber gleich zum korrekten Ansatz raten:
>
> Wenn man jetzt aber die Array-Größe auf "MAX-3" ändert muss man dran
> denken, das bei snprintf auch zu tun. Mit dem template entfällt das,
> weil automatisch immer die tatsächliche Array-Größe genutzt wird.

das kann man in C auch haben, normalerweise schreibt man ja
1
char str[MAX];
2
3
   snprintf (str, sizeof str, "%s\n", blafasel);

von temp (Gast)


Lesenswert?

Dafür sieht man die Spatzen vor lauter Kanonenkugeln nicht.

von temp (Gast)


Lesenswert?

temp schrieb:
> Dafür sieht man die Spatzen vor lauter Kanonenkugeln nicht.

Damit kein Missverständnis aufkommt, das war allgemein auf einige der 
Vorschläge hier bezogen nicht auf den letzten von  Bauform B. Der ist 
zeitlich dazwischen gerutscht.

Beitrag #5514363 wurde von einem Moderator gelöscht.
von Peter Trace (Gast)


Lesenswert?

Vielen Dank für die zahlreichen Antworten.
Mir geht es bei dieser Frage nicht um die Vermeidung von Fehlern bei 
"printf", sondern nur um die Fehlerlokalisierung.
Witziger weise wurde under "Stack-Caller" keine Funktion angezeigt, das 
hat mich zum grübeln gebracht.

von gccler (Gast)


Lesenswert?

Hmm, hätte hier ein "-fstack-protector-all" geholfen?

von temp (Gast)


Lesenswert?

Peter Trace schrieb:
> Witziger weise wurde under "Stack-Caller" keine Funktion angezeigt, das
> hat mich zum grübeln gebracht.

Wenn du dir den Stack zerschießt ist das nun mal so.

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.