Falla misteriosa cuando paso por encima

6

Esta pregunta fue reescrita para eliminar varias actualizaciones y mejorar la claridad.

Tengo un MCU basado en Cortex M3 (y bastante oscuro). Tengo un proyecto bastante grande, escrito en C ++, en Keil MDK5 con compilador armcc.

Tengo esta función:

bool CanHandle::sendMsg(CanMsg & msg)
{
    bool result = false; // <--------- problematic line

    CAN_TxMsgTypeDef txMsg;

    if (format == FrameFormat::EXTENDED)
    {
        txMsg.IDE = CAN_ID_EXT;
    }
    else
    {
        txMsg.IDE = CAN_ID_STD;
    }

    ENTER_CRITICAL_SECTION(); 

        uint32_t bufN = CAN_GetEmptyTransferBuffer(set.mdrCan);
        if (bufN != CAN_BUFFER_NUMBER)
        {
            CAN_Transmit(set.mdrCan, bufN, &txMsg);
            isTxQueueFull = false;
        }
        else
        {
            isTxQueueFull = true;
            result = false;
        }

    LEAVE_CRITICAL_SECTION();

    return result;
}

Cuando compilo con -O1, el compilador produce esta lista de ensamblados para él:

0x0800068C E92D41FF  PUSH     {r0-r8,lr}
0x08000690 4604      MOV      r4,r0
0x08000692 2700      MOVS     r7,#0x00
0x08000694 7A20      LDRB     r0,[r4,#0x08]
0x08000696 2600      MOVS     r6,#0x00
0x08000698 F04F0801  MOV      r8,#0x01
0x0800069C 2801      CMP      r0,#0x01
0x0800069E D013      BEQ      0x080006C8
0x080006A0 F88D6005  STRB     r6,[sp,#0x05]
0x080006A4 4860      LDR      r0,[pc,#384]  ; @0x08000828
0x080006A6 6800      LDR      r0,[r0,#0x00]
0x080006A8 F3C00508  UBFX     r5,r0,#0,#9
0x080006AC F8D401FC  LDR      r0,[r4,#0x1FC]
0x080006B0 F000FBCA  BL.W     CAN_GetEmptyTransferBuffer (0x08000E48)
0x080006B4 4601      MOV      r1,r0
0x080006B6 2920      CMP      r1,#0x20
0x080006B8 D009      BEQ      0x080006CE
0x080006BA 466A      MOV      r2,sp
0x080006BC F8D401FC  LDR      r0,[r4,#0x1FC]
0x080006C0 F000FBC4  BL.W     CAN_Transmit (0x08000E4C)
0x080006C4 7266      STRB     r6,[r4,#0x09]
0x080006C6 E004      B        0x080006D2
0x080006C8 F88D8005  STRB     r8,[sp,#0x05]
0x080006CC E7EA      B        0x080006A4
0x080006CE F8848009  STRB     r8,[r4,#0x09]
0x080006D2 B004      ADD      sp,sp,#0x10
0x080006D4 4638      MOV      r0,r7
0x080006D6 E8BD81F0  POP      {r4-r8,pc}

Y aquí está lo gracioso: cuando trato de pasar por encima de la línea bool result = false; , tengo una falla fuerte con el conjunto de indicadores UNDEFINSTR. La PC recuperada de la pila muestra alguna dirección inexistente.

Pero , y aquí está la cosa realmente misteriosa: si paso por encima del ensamblaje, o si paso por el código C o si establece un punto de interrupción en la línea 2 y presiona Ejecutar, ¡todo está bien! No hay falla dura, el programa se ejecuta desde allí. Si compilo con -O0 o hago un resultado volátil, el compilador produce un ensamblaje diferente y no se produce una falla. Intenté usar diferentes versiones de compilador o IDE: el problema persiste.

La ejecución de este programa sin depurador no produce fallas.

La depuración en el simulador no produce fallas, pero pasar sobre esa línea en particular no pasa, hace que el programa se ejecute indefinidamente.

Esta función se llama desde main, por lo que, después de su finalización, hay solo while (1). Creo que no hay ningún problema en el código externo.

El código de la función ahora está al mínimo, si elimino cualquier línea, literalmente cualquier línea, el problema desaparece. Anteriormente publiqué varias suposiciones erróneas, las eliminé por ahora. No puedo precisar ninguna instrucción o dirección particular que produzca fallas. Todas las llamadas de función allí son maniquíes, vuelven inmediatamente. Las macros de CRITICAL_SECTION no producen secciones críticas en absoluto, pero algo tiene que estar en esas líneas o no ocurre ninguna falla.

Literalmente no tengo idea de cómo puede suceder eso. No sé cómo funciona exactamente el depurador, ¿cuál es la diferencia entre detenerse y establecer un punto de interrupción y pulsar "ejecutar"?

    
pregunta Amomum

2 respuestas

1

Algunas ideas que pueden ayudar cuando se depura una falla dura en una corteza m4, quizás algunas de ellas son útiles: - la línea que causa la falla dura se pone en la pila en la dirección + 0x18, si la interrupción es síncrona, bit BFARVALID establezca, si no, puede forzarse configurando el bit DISDEBUF desde el registro del sistema ACTLR.

Otra cosa, al ejecutar código desde flash, cosas como la configuración del estado de espera, las memorias caché, los búferes de captación previa pueden causar errores como este.

Actualmente tengo un problema similar, que parece estar influenciado por una opción de vinculador (ignore_debug_references), no estoy seguro de cómo ...

    
respondido por el Marius E.
1
  

MCU es lo suficientemente oscuro como para tener errores de hardware muy agradables (y los tiene, en realidad) pero hasta ahora no había errores en el núcleo mismo (porque se compró a ARM, supongo). Pero hay una posibilidad.

Es raro que encuentre un error en el núcleo o compilador. Menos raro encontrar errores en los periféricos, y muy común encontrar errores en el código.

  

Literalmente no tengo idea de cómo puede suceder eso. No sé cómo funciona exactamente el depurador, ¿cuál es la diferencia entre detenerse y establecer un punto de interrupción y pulsar "ejecutar"?

El paso no interrumpe, el paso a paso sí

Además, habilite captura de vectores . Puede hacer esto con un script de depuración .

    
respondido por el Jeroen3

Lea otras preguntas en las etiquetas