tools sonar sast many how for code available are gcc embedded code-analysis static-analysis

gcc - sast - sonarqube vs fortify



¿Cómo se determina el uso máximo de la pila en el sistema integrado con gcc? (5)

Bastante tarde, pero para cualquiera que mire esto, las respuestas dadas que combinan los resultados del uso de fstack y las herramientas de call graph como cflow pueden terminar siendo muy incorrectas para cualquier asignación dinámica, incluso limitada, porque no hay información sobre cuándo esa pila dinámica asignación ocurre. Por lo tanto, no es posible saber a qué funciones debe aplicar el valor. Como un ejemplo artificial, si el resultado (simplificado) de uso de fstack es:

main 1024 dynamic,bounded functionA 512 static functionB 16 static

y un árbol de llamadas muy simple es:

main functionA functionB

El enfoque ingenuo para combinar esto puede dar como resultado que main -> functionA se elija como la ruta de uso máximo de la pila, a 1536 bytes. Pero, si la mayor asignación dinámica de pila en main () es enviar un argumento grande como un registro a functionB () directamente en la pila en un bloque condicional que llama a functionB (ya dije que esto fue inventado), entonces realmente main -> functionB es la ruta del uso máximo de la pila, a 1040 bytes. Dependiendo del diseño de software existente, y también de otros objetivos más restringidos que pasan todo en la pila, los errores acumulativos pueden llevarlo rápidamente a buscar rutas completamente incorrectas, alegando un tamaño de pila máximo exagerado.

Además, dependiendo de su clasificación de "reentrada" cuando se habla de interrupciones, es posible omitir algunas asignaciones de pila por completo. Por ejemplo, muchos interruptores de nivel 7 de Coldfire son sensibles y, por lo tanto, ignoran la máscara de inhabilitación de interrupción, por lo que si se utiliza un semáforo para dejar la instrucción antes, no se puede considerar reentrada, pero la asignación de pila inicial aún ocurrirá antes el semáforo está marcado.

En resumen, debes tener mucho cuidado con el uso de este enfoque.

Estoy escribiendo el código de inicio para un sistema integrado: el código que carga el puntero inicial de la pila antes de saltar a la función main () y necesito decirle cuántos bytes de pila usará mi aplicación (o algunos más grandes) , estimación conservadora).

Me han dicho que el compilador de gcc ahora tiene una opción de uso de almacenamiento y una opción de información de gráficos que de alguna manera se puede usar para calcular estáticamente el "uso máximo de pila" exacto para mí. ( "Análisis de requisitos de pila en tiempo de compilación con GCC" por Botcazou, Comar y Hainque).

Nigel Jones dice que la recursividad es una muy mala idea en los sistemas integrados ("Calcular el tamaño de tu pila" 2009), así que he tenido cuidado de no hacer ninguna función mutuamente recursiva en este código.

Además, me aseguro de que ninguno de mis manejadores de interrupciones vuelvan a habilitar las interrupciones hasta su instrucción final de retorno de la interrupción, por lo que no tengo que preocuparme por los controladores de interrupción reentrantes.

Sin recursion o controladores de interrupción reentrantes, debería ser posible determinar estáticamente el uso máximo de la pila. (Y entonces, la mayoría de las respuestas a Cómo determinar el uso máximo de la pila no se aplican). Entiendo que yo (o preferiblemente, un poco de código en mi PC que se ejecuta automáticamente cada vez que reconstruyo el ejecutable) primero encuentre la profundidad máxima de pila para cada controlador de interrupción cuando no se interrumpe por una interrupción de prioridad más alta, y el máximo apilar la profundidad de la función main () cuando no se interrumpe. Luego los agrego a todos para encontrar la profundidad máxima total (peor de los casos) de la pila. Eso ocurre (en mi sistema integrado) cuando la tarea de fondo principal () está en su profundidad máxima cuando se interrumpe por la interrupción de prioridad más baja, y esa interrupción se encuentra en su profundidad máxima cuando es interrumpida por la siguiente prioridad más baja interrumpir, y así sucesivamente.

Estoy usando YAGARTO con gcc 4.6.0 para compilar el código para LM3S1968 ARM Cortex-M3.

Entonces, ¿cómo utilizo la opción -fstack-use y la opción -fcallgraph-info con gcc para calcular la profundidad máxima de la pila? ¿O hay algún método mejor para determinar el uso máximo de la pila?

(Consulte Cómo determinar el uso máximo de la pila en el sistema integrado? Para casi la misma pregunta dirigida al compilador de Keil).


Documentos de GCC:

-flash-uso

Hace que la información de uso de la pila de salida del compilador para el programa, por función. El nombre de archivo para el volcado se realiza al agregar .su al nombre auxiliar. auxname se genera a partir del nombre del archivo de salida, si se especifica explícitamente y no es un archivo ejecutable; de ​​lo contrario, es el nombre base del archivo fuente. Una entrada se compone de tres campos:

  • El nombre de la función.
  • Una cantidad de bytes.
  • Uno o más calificadores: estático, dinámico, limitado.

El calificador estático significa que la función manipula la pila estáticamente: se asigna un número fijo de bytes para el cuadro en la entrada de la función y se libera en la salida de la función; no se hacen ajustes de pila en la función. El segundo campo es este número fijo de bytes.

La dinámica de calificador significa que la función manipula la pila dinámicamente: además de la asignación estática descrita anteriormente, los ajustes de pila se realizan en el cuerpo de la función, por ejemplo, para empujar / explotar argumentos alrededor de las llamadas a funciones. Si el calificador limitado también está presente, la cantidad de estos ajustes está limitada en tiempo de compilación y el segundo campo es un límite superior de la cantidad total de pila utilizada por la función. Si no está presente, la cantidad de estos ajustes no está limitada en tiempo de compilación y el segundo campo solo representa la parte limitada.

No puedo encontrar ninguna referencia a -fcallgraph-info

Podrías crear la información que necesitas de -flash-use y -fdump-tree-optimized

Para cada hoja en -fdump-tree-optimized, obtenga sus padres y sume su número de tamaño de pila (teniendo en cuenta que este número corresponde a cualquier función con "dinámico" pero no "delimitado") de -flash-use, encuentre el máximo de estos valores y este debería ser su uso máximo de pila.


En caso de que a nadie se le ocurra una mejor respuesta, publicaré lo que tenía en el comentario de su otra pregunta, aunque no tengo experiencia en el uso de estas opciones y herramientas:

GCC 4.6 agrega la opción -fstack-usage que proporciona las estadísticas de uso de la pila función por función.

Si combina esta información con un gráfico de llamadas producido por cflow o una herramienta similar, puede obtener el tipo de análisis de profundidad de pila que está buscando (un script probablemente podría escribirse con bastante facilidad para hacer esto). Haga que el script lea la información de uso de la pila y cargue un mapa de nombres de funciones con la pila utilizada por la función. Luego cflow que el script recorra el gráfico de cflow (que puede ser un árbol de texto fácil de analizar), sumando el uso de la pila asociado con cada línea para cada rama en el gráfico de llamadas.

Por lo tanto, parece que esto se puede hacer con GCC, pero es posible que tenga que improvisar el conjunto correcto de herramientas.


No estoy familiarizado con las -fstack-usage y -fcallgraph-info . Sin embargo, siempre es posible descubrir el uso real de la pila al:

  1. Asigne un espacio de pila adecuado (para este experimento) e inicialícelo a algo fácilmente identificable. Me gusta 0xee .
  2. Ejecute la aplicación y pruebe todas sus rutas internas (por todas las combinaciones de entrada y parámetros). Déjalo funcionar por más de "lo suficiente".
  3. Examine el área de la pila y vea qué cantidad de la pila se utilizó.
  4. Haga que el tamaño de la pila, más 10% o 20% para tolerar actualizaciones de software y condiciones raras.

Terminé escribiendo un script de python para implementar la answer de τεκ. Es demasiado código para publicar aquí, pero se puede encontrar en github