My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

unwarm.cpp 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /***************************************************************************
  2. * ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
  3. * Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
  4. *
  5. * This program is PUBLIC DOMAIN.
  6. * This means that there is no copyright and anyone is able to take a copy
  7. * for free and use it as they wish, with or without modifications, and in
  8. * any context, commercially or otherwise. The only limitation is that I
  9. * don't guarantee that the software is fit for any purpose or accept any
  10. * liability for its use or misuse - this software is without warranty.
  11. ***************************************************************************
  12. * File Description: Utility functions and glue for ARM unwinding sub-modules.
  13. **************************************************************************/
  14. #if defined(__arm__) || defined(__thumb__)
  15. #define MODULE_NAME "UNWARM"
  16. #include <stdint.h>
  17. #include <stdio.h>
  18. #include <stdarg.h>
  19. #include <string.h>
  20. #include "unwarm.h"
  21. #include "unwarmmem.h"
  22. #ifdef UNW_DEBUG
  23. /**
  24. * Printf wrapper.
  25. * This is used such that alternative outputs for any output can be selected
  26. * by modification of this wrapper function.
  27. */
  28. void UnwPrintf(const char *format, ...) {
  29. va_list args;
  30. va_start( args, format );
  31. vprintf(format, args );
  32. }
  33. #endif
  34. /**
  35. * Invalidate all general purpose registers.
  36. */
  37. void UnwInvalidateRegisterFile(RegData *regFile) {
  38. uint8_t t = 0;
  39. do {
  40. regFile[t].o = REG_VAL_INVALID;
  41. t++;
  42. } while (t < 13);
  43. }
  44. /**
  45. * Initialize the data used for unwinding.
  46. */
  47. void UnwInitState(UnwState * const state, /**< Pointer to structure to fill. */
  48. const UnwindCallbacks *cb, /**< Callbacks. */
  49. void *rptData, /**< Data to pass to report function. */
  50. uint32_t pcValue, /**< PC at which to start unwinding. */
  51. uint32_t spValue) { /**< SP at which to start unwinding. */
  52. UnwInvalidateRegisterFile(state->regData);
  53. /* Store the pointer to the callbacks */
  54. state->cb = cb;
  55. state->reportData = rptData;
  56. /* Setup the SP and PC */
  57. state->regData[13].v = spValue;
  58. state->regData[13].o = REG_VAL_FROM_CONST;
  59. state->regData[15].v = pcValue;
  60. state->regData[15].o = REG_VAL_FROM_CONST;
  61. UnwPrintd3("\nInitial: PC=0x%08x SP=0x%08x\n", pcValue, spValue);
  62. /* Invalidate all memory addresses */
  63. memset(state->memData.used, 0, sizeof(state->memData.used));
  64. }
  65. // Detect if function names are available
  66. static int __attribute__ ((noinline)) has_function_names() {
  67. uint32_t flag_word = ((uint32_t*)(((uint32_t)(&has_function_names)) & (-4))) [-1];
  68. return ((flag_word & 0xFF000000) == 0xFF000000) ? 1 : 0;
  69. }
  70. /**
  71. * Call the report function to indicate some return address.
  72. * This returns the value of the report function, which if true
  73. * indicates that unwinding may continue.
  74. */
  75. bool UnwReportRetAddr(UnwState * const state, uint32_t addr) {
  76. UnwReport entry;
  77. // We found two acceptable values.
  78. entry.name = nullptr;
  79. entry.address = addr & 0xFFFFFFFE; // Remove Thumb bit
  80. entry.function = 0;
  81. // If there are function names, try to solve name
  82. if (has_function_names()) {
  83. // Lets find the function name, if possible
  84. // Align address to 4 bytes
  85. uint32_t pf = addr & (-4);
  86. // Scan backwards until we find the function name
  87. uint32_t v;
  88. while (state->cb->readW(pf-4,&v)) {
  89. // Check if name descriptor is valid
  90. if ((v & 0xFFFFFF00) == 0xFF000000 && (v & 0xFF) > 1) {
  91. // Assume the name was found!
  92. entry.name = ((const char*)pf) - 4 - (v & 0xFF);
  93. entry.function = pf;
  94. break;
  95. }
  96. // Go backwards to the previous word
  97. pf -= 4;
  98. }
  99. }
  100. /* Cast away const from reportData.
  101. * The const is only to prevent the unw module modifying the data.
  102. */
  103. return state->cb->report((void *)state->reportData, &entry);
  104. }
  105. /**
  106. * Write some register to memory.
  107. * This will store some register and meta data onto the virtual stack.
  108. * The address for the write
  109. * \param state [in/out] The unwinding state.
  110. * \param wAddr [in] The address at which to write the data.
  111. * \param reg [in] The register to store.
  112. * \return true if the write was successful, false otherwise.
  113. */
  114. bool UnwMemWriteRegister(UnwState * const state, const uint32_t addr, const RegData * const reg) {
  115. return UnwMemHashWrite(&state->memData, addr, reg->v, M_IsOriginValid(reg->o));
  116. }
  117. /**
  118. * Read a register from memory.
  119. * This will read a register from memory, and setup the meta data.
  120. * If the register has been previously written to memory using
  121. * UnwMemWriteRegister, the local hash will be used to return the
  122. * value while respecting whether the data was valid or not. If the
  123. * register was previously written and was invalid at that point,
  124. * REG_VAL_INVALID will be returned in *reg.
  125. * \param state [in] The unwinding state.
  126. * \param addr [in] The address to read.
  127. * \param reg [out] The result, containing the data value and the origin
  128. * which will be REG_VAL_FROM_MEMORY, or REG_VAL_INVALID.
  129. * \return true if the address could be read and *reg has been filled in.
  130. * false is the data could not be read.
  131. */
  132. bool UnwMemReadRegister(UnwState * const state, const uint32_t addr, RegData * const reg) {
  133. bool tracked;
  134. // Check if the value can be found in the hash
  135. if (UnwMemHashRead(&state->memData, addr, &reg->v, &tracked)) {
  136. reg->o = tracked ? REG_VAL_FROM_MEMORY : REG_VAL_INVALID;
  137. return true;
  138. }
  139. else if (state->cb->readW(addr, &reg->v)) { // Not in the hash, so read from real memory
  140. reg->o = REG_VAL_FROM_MEMORY;
  141. return true;
  142. }
  143. else return false; // Not in the hash, and failed to read from memory
  144. }
  145. #endif // __arm__ || __thumb__