int check_for_free_memory_corruption(const char * const title) { SERIAL_ECHO(title); char *ptr = END_OF_HEAP(), *sp = top_of_stack(); int n = sp - ptr; SERIAL_ECHOPAIR("\nfmc() n=", n); SERIAL_ECHOPAIR("\n&__brkval: ", hex_address(&__brkval)); SERIAL_ECHOPAIR("=", hex_address(__brkval)); SERIAL_ECHOPAIR("\n__bss_end: ", hex_address(&__bss_end)); SERIAL_ECHOPAIR(" sp=", hex_address(sp)); if (sp < ptr) { SERIAL_ECHOPGM(" sp < Heap "); // SET_INPUT_PULLUP(63); // if the developer has a switch wired up to their controller board // safe_delay(5); // this code can be enabled to pause the display as soon as the // while ( READ(63)) // malfunction is detected. It is currently defaulting to a switch // idle(); // being on pin-63 which is unassigend and available on most controller // safe_delay(20); // boards. // while ( !READ(63)) // idle(); safe_delay(20); #ifdef M100_FREE_MEMORY_DUMPER M100_dump_routine(" Memory corruption detected with sp<Heap\n", (char*)0x1B80, (char*)0x21FF); #endif } // Scan through the range looking for the biggest block of 0xE5's we can find int block_cnt = 0; for (int i = 0; i < n; i++) { if (ptr[i] == TEST_BYTE) { int16_t j = count_test_bytes(ptr + i); if (j > 8) { // SERIAL_ECHOPAIR("Found ", j); // SERIAL_ECHOLNPAIR(" bytes free at ", hex_address(ptr + i)); i += j; block_cnt++; SERIAL_ECHOPAIR(" (", block_cnt); SERIAL_ECHOPAIR(") found=", j); SERIAL_ECHOPGM(" "); } } } SERIAL_ECHOPAIR(" block_found=", block_cnt); if (block_cnt != 1 || __brkval != 0x0000) SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area."); if (block_cnt == 0) // Make sure the special case of no free blocks shows up as an block_cnt = -1; // error to the calling code! SERIAL_ECHOPGM(" return="); if (block_cnt == 1) { SERIAL_CHAR('0'); // if the block_cnt is 1, nothing has broken up the free memory SERIAL_EOL(); // area and it is appropriate to say 'no corruption'. return 0; } SERIAL_ECHOLNPGM("true"); return block_cnt; }
/** * M100: Free Memory Check */ void gcode_M100() { SERIAL_ECHOPAIR("\n__brkval : ", hex_address(__brkval)); SERIAL_ECHOPAIR("\n__bss_end : ", hex_address(&__bss_end)); char *ptr = END_OF_HEAP(), *sp = top_of_stack(); SERIAL_ECHOPAIR("\nstart of free space : ", hex_address(ptr)); SERIAL_ECHOLNPAIR("\nStack Pointer : ", hex_address(sp)); // Always init on the first invocation of M100 static bool m100_not_initialized = true; if (m100_not_initialized || parser.seen('I')) { m100_not_initialized = false; init_free_memory(ptr, sp - ptr); } #if ENABLED(M100_FREE_MEMORY_DUMPER) if (parser.seen('D')) return dump_free_memory(ptr, sp); #endif if (parser.seen('F')) return free_memory_pool_report(ptr, sp - ptr); #if ENABLED(M100_FREE_MEMORY_CORRUPTOR) if (parser.seen('C')) return corrupt_free_memory(ptr, parser.value_int()); #endif }
/** * M100 C<num> * Corrupt <num> locations in the free memory pool and report the corrupt addresses. * This is useful to check the correctness of the M100 D and the M100 F commands. */ void corrupt_free_memory(char *ptr, const uint16_t size) { ptr += 8; const uint16_t near_top = top_of_stack() - ptr - 250, // -250 to avoid interrupt activity that's altered the stack. j = near_top / (size + 1); SERIAL_ECHOLNPGM("Corrupting free memory block.\n"); for (uint16_t i = 1; i <= size; i++) { char * const addr = ptr + i * j; *addr = i; SERIAL_ECHOPAIR("\nCorrupting address: ", hex_address(addr)); } SERIAL_EOL(); }
void gcode_M100() { static int m100_not_initialized = 1; unsigned char* sp, *ptr; int i, j, n; // // M100 D dumps the free memory block from __brkval to the stack pointer. // malloc() eats memory from the start of the block and the stack grows // up from the bottom of the block. Solid 0xE5's indicate nothing has // used that memory yet. There should not be anything but 0xE5's within // the block of 0xE5's. If there is, that would indicate memory corruption // probably caused by bad pointers. Any unexpected values will be flagged in // the right hand column to help spotting them. // #if ENABLED(M100_FREE_MEMORY_DUMPER) // Disable to remove Dump sub-command if (code_seen('D')) { ptr = (unsigned char*) __brkval; // // We want to start and end the dump on a nice 16 byte boundry even though // the values we are using are not 16 byte aligned. // SERIAL_ECHOPGM("\n__brkval : "); prt_hex_word((unsigned int) ptr); ptr = (unsigned char*)((unsigned long) ptr & 0xfff0); sp = top_of_stack(); SERIAL_ECHOPGM("\nStack Pointer : "); prt_hex_word((unsigned int) sp); SERIAL_ECHOPGM("\n"); sp = (unsigned char*)((unsigned long) sp | 0x000f); n = sp - ptr; // // This is the main loop of the Dump command. // while (ptr < sp) { prt_hex_word((unsigned int) ptr); // Print the address SERIAL_ECHOPGM(":"); for (i = 0; i < 16; i++) { // and 16 data bytes prt_hex_byte(*(ptr + i)); SERIAL_ECHOPGM(" "); delay(2); } SERIAL_ECHO("|"); // now show where non 0xE5's are for (i = 0; i < 16; i++) { delay(2); if (*(ptr + i) == 0xe5) SERIAL_ECHOPGM(" "); else SERIAL_ECHOPGM("?"); } SERIAL_ECHO("\n"); ptr += 16; delay(2); } SERIAL_ECHOLNPGM("Done.\n"); return; } #endif // // M100 F requests the code to return the number of free bytes in the memory pool along with // other vital statistics that define the memory pool. // if (code_seen('F')) { int max_addr = (int) __brkval; int max_cnt = 0; int block_cnt = 0; ptr = (unsigned char*) __brkval; sp = top_of_stack(); n = sp - ptr; // Scan through the range looking for the biggest block of 0xE5's we can find for (i = 0; i < n; i++) { if (*(ptr + i) == (unsigned char) 0xe5) { j = how_many_E5s_are_here((unsigned char*) ptr + i); if (j > 8) { SERIAL_ECHOPAIR("Found ", j); SERIAL_ECHOPGM(" bytes free at 0x"); prt_hex_word((int) ptr + i); SERIAL_ECHOPGM("\n"); i += j; block_cnt++; } if (j > max_cnt) { // We don't do anything with this information yet max_cnt = j; // but we do know where the biggest free memory block is. max_addr = (int) ptr + i; } } } if (block_cnt > 1) SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.\n"); SERIAL_ECHO("\nDone.\n"); return; } // // M100 C x Corrupts x locations in the free memory pool and reports the locations of the corruption. // This is useful to check the correctness of the M100 D and the M100 F commands. // #if ENABLED(M100_FREE_MEMORY_CORRUPTOR) if (code_seen('C')) { int x; // x gets the # of locations to corrupt within the memory pool x = code_value(); SERIAL_ECHOLNPGM("Corrupting free memory block.\n"); ptr = (unsigned char*) __brkval; SERIAL_ECHOPAIR("\n__brkval : ", (long) ptr); ptr += 8; sp = top_of_stack(); SERIAL_ECHOPAIR("\nStack Pointer : ", (long) sp); SERIAL_ECHOLNPGM("\n"); n = sp - ptr - 64; // -64 just to keep us from finding interrupt activity that // has altered the stack. j = n / (x + 1); for (i = 1; i <= x; i++) { *(ptr + (i * j)) = i; SERIAL_ECHO("\nCorrupting address: 0x"); prt_hex_word((unsigned int)(ptr + (i * j))); } SERIAL_ECHOLNPGM("\n"); return; } #endif // // M100 I Initializes the free memory pool so it can be watched and prints vital // statistics that define the free memory pool. // if (m100_not_initialized || code_seen('I')) { // If no sub-command is specified, the first time SERIAL_ECHOLNPGM("Initializing free memory block.\n"); // this happens, it will Initialize. ptr = (unsigned char*) __brkval; // Repeated M100 with no sub-command will not destroy the SERIAL_ECHOPAIR("\n__brkval : ", (long) ptr); // state of the initialized free memory pool. ptr += 8; sp = top_of_stack(); SERIAL_ECHOPAIR("\nStack Pointer : ", (long) sp); SERIAL_ECHOLNPGM("\n"); n = sp - ptr - 64; // -64 just to keep us from finding interrupt activity that // has altered the stack. SERIAL_ECHO(n); SERIAL_ECHOLNPGM(" bytes of memory initialized.\n"); for (i = 0; i < n; i++) *(ptr + i) = (unsigned char) 0xe5; for (i = 0; i < n; i++) { if (*(ptr + i) != (unsigned char) 0xe5) { SERIAL_ECHOPAIR("? address : ", (unsigned long) ptr + i); SERIAL_ECHOPAIR("=", *(ptr + i)); SERIAL_ECHOLNPGM("\n"); } } m100_not_initialized = 0; SERIAL_ECHOLNPGM("Done.\n"); return; } return; }
Assembler::Register register_for(int index) { GUARANTEE(0 < index && index <= top_of_stack(), "Index out of bounds"); return register_at(top_of_stack() - index); }
void assert_top_of_stack_is_expected_value(InputAndResultType const& expected) { InputAndResultType top_of_stack(0); OOLUA::pull(*m_lua, top_of_stack); CPPUNIT_ASSERT_EQUAL(expected, top_of_stack); }
void pop(Assembler::Register reg) { GUARANTEE(register_at(top_of_stack()) == reg, "Can only pop register at top of stack"); pop(); }
void pop() { GUARANTEE(top_of_stack() > 0, "FPU Register stack underflow"); set_register_at(top_of_stack(), Assembler::no_reg); set_top_of_stack(top_of_stack() - 1); }
void push(Assembler::Register reg) { GUARANTEE(top_of_stack() < Assembler::number_of_float_registers, "FPU Register stack overflow"); set_top_of_stack(top_of_stack() + 1); set_register_at(top_of_stack(), reg); }
Assembler::Register top_of_stack_register() { return register_at(top_of_stack()); }
bool is_empty() { return top_of_stack() == 0; }