-Wundef -Wno-unused -Werror -Wno-error=cast-align -Wno-error=strict-overflow -Wno-error=pedantic \
$(THUMBFLAGS) $(SIZE_OPTIMIZATION) $(INCPATHS) $(C9FLAGS) \
-fno-builtin -std=gnu11 -DREVISION=\"$(REVISION)\" \
- -DFW_NAME=\"corbenik\" $(PATHARGS)
+ -DFW_NAME=\"corbenik\" $(PATHARGS) -DMALLOC_DEBUG=1
AM_LDFLAGS=-Wl,--use-blx,--pic-veneer,-q -nostdlib -nodefaultlibs -Wl,-z,defs -lgcc \
*/
uint32_t wait_key(_UNUSED int sleep);
+/* Displays a prompt on the bottom screen if the relevant option is enabled and waits on input
+ * to continue.
+ */
+void wait();
+
#endif
*/
void *sbrk(size_t bytes);
+#ifdef MALLOC_DEBUG
+
+/* Prints stats for allocation to stderr.
+ */
+void print_alloc_stats();
+
+/* Allocate memory for use (debugging only, don't call)
+ *
+ * \param size Size in bytes to allocate.
+ * \param info Info to store about malloc
+ */
+void* malloc_chkd(size_t size, char* info);
+
+/* Free in-use memory allocated by malloc (debugging only, don't call)
+ *
+ * \param ptr Pointer to free.
+ * \param info Info to store about free
+ */
+void free_chkd(void* ptr, char* info);
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+#define malloc(x) malloc_chkd( x , __FILE__ ":" TOSTRING(__LINE__) )
+#define free(x) free_chkd( x , __FILE__ ":" TOSTRING(__LINE__) )
+
+#else
+
/* Allocate memory for use.
*
* \param size Size in bytes to allocate.
void free (void* ptr);
#endif
+
+#endif
return 0;
}
-extern void wait();
-
__attribute__ ((noreturn))
void
boot_firm()
fprintf(stderr, "Updated keyX keyslots.\n");
}
+#ifdef MALLOC_DEBUG
+ print_alloc_stats();
+ wait();
+#endif
+
+ // Beyond this point, using malloc() memory is unsafe, since we're trashing memory possibly.
+ // free() is also irrelevant from here on.
+
for (firm_section_h *section = firm_loc->section; section < firm_loc->section + 4 && section->address != 0; section++) {
memcpy((void *)section->address, (void *)((uint8_t*)firm_loc + section->offset), section->size);
}
return ret;
}
+extern int doing_autoboot;
+
+void
+wait()
+{
+ if (config->options[OPTION_TRACE] && !doing_autoboot) {
+ fprintf(stderr, "[Waiting...]");
+ wait_key(0); // No delay on traces.
+ }
+ fprintf(stderr, "\r \r");
+}
+
}
#else
#define log(a) fprintf(stderr, a)
- int wait();
#endif
struct mode
#include <common.h>
#include <ctr9/io.h>
-int wait();
-
uint8_t*
getProcess9(uint8_t *pos, uint32_t size, uint32_t *process9Size, uint32_t *process9MemAddr)
{
extern struct options_s* patches;
-void
-wait()
-{
- if (config->options[OPTION_TRACE] && !doing_autoboot) {
- fprintf(stderr, "[Waiting...]");
- wait_key(0); // No delay on traces.
- }
- fprintf(stderr, " \r");
-}
-
void list_patches_build(char *name, int desc_is_fname);
void
typedef struct free_block {
size_t size;
+#ifdef MALLOC_DEBUG
+ char* info;
+#endif
struct free_block* next;
} free_block;
-static free_block free_block_list_head = { 0, 0 };
+static free_block free_block_list_head = {
+ 0,
+#ifdef MALLOC_DEBUG
+ NULL,
+#endif
+ 0
+};
// static const size_t overhead = sizeof(size_t);
static const size_t align_to = 16;
+#ifdef MALLOC_DEBUG
+static size_t alloc_count = 0;
+static size_t free_count = 0;
+static size_t allocated_memory = 0;
+#endif
+
+#ifdef MALLOC_DEBUG
+void* malloc_chkd(size_t size, char* info) {
+#else
void* malloc(size_t size) {
- size = (size + sizeof(free_block) + (align_to - 1)) & ~ (align_to - 1);
+#endif
+ size_t bsize = (size + sizeof(free_block) + (align_to - 1)) & ~ (align_to - 1);
+
free_block* block = free_block_list_head.next;
free_block** head = &(free_block_list_head.next);
+
while (block != 0) {
- if (block->size >= size) {
+ if (block->size >= bsize) {
*head = block->next;
+
+#ifdef MALLOC_DEBUG
+ block->info = info;
+
+ ++alloc_count;
+ allocated_memory += block->size;
+#endif
+
return ((char*)block) + sizeof(free_block);
}
head = &(block->next);
block = block->next;
}
- block = (free_block*)sbrk(size);
- block->size = size;
+ block = (free_block*)sbrk(bsize);
+ block->size = bsize;
+
+#ifdef MALLOC_DEBUG
+ block->info = info;
+
+ ++alloc_count;
+ allocated_memory += bsize;
+#endif
return ((char*)block) + sizeof(free_block);
}
+void* malloc_zero(size_t size) {
+ void* ret = malloc(size);
+
+ if (ret)
+ memset(ret, 0, size);
+
+ return ret;
+}
+
+#ifdef MALLOC_DEBUG
+void free_chkd(void* ptr, char* info) {
+#else
void free(void* ptr) {
+#endif
if (ptr == NULL) return;
free_block* block = (free_block*)(((char*)ptr) - sizeof(free_block ));
+
+#ifdef MALLOC_DEBUG
+ ++free_count;
+ if (allocated_memory < block->size) {
+ fprintf(stderr, "%s: Invalid free detected.\n"
+ " Allocated at: %s\n",
+ info, block->info);
+ }
+ allocated_memory -= block->size;
+#endif
+
block->next = free_block_list_head.next;
free_block_list_head.next = block;
}
+
+#ifdef MALLOC_DEBUG
+void print_alloc_stats() {
+ fprintf(stderr, "[A] %u [F] %u [M] %u [B] %lu\n", alloc_count, free_count, allocated_memory, (uint32_t)heap_end - (uint32_t)&__end__);
+}
+#endif
if (f_open(&(fp->handle), filename, fp->mode)) {
free(fp);
return NULL;
- }
+ }
fp->is_open = 1;
void
fclose(FILE *fp)
{
- if (!fp->is_open)
+ if (fp == NULL || !fp->is_open)
return;
f_close(&(fp->handle));
void
fseek(FILE *fp, int64_t offset, int whence)
{
- if (!fp->is_open)
+ if (fp == NULL || !fp->is_open)
return;
uint32_t fixed_offset;
size_t
ftell(FILE *fp)
{
- if (!fp->is_open)
+ if (fp == NULL || !fp->is_open)
return 0;
return f_tell(&(fp->handle));
int
feof(FILE *fp)
{
- if (!fp->is_open)
+ if (fp == NULL || !fp->is_open)
return 0;
return f_eof(&(fp->handle));
size_t
fsize(FILE *fp)
{
- if (!fp->is_open)
+ if (fp == NULL || !fp->is_open)
return 0;
return f_size(&(fp->handle));
size_t
fwrite(const void *buffer, size_t elementSize, size_t elementCnt, FILE *fp)
{
- if (!fp->is_open)
+ if (fp == NULL || !fp->is_open)
return 0;
UINT br;
{
FILE *temp = fopen(path, "w");
- if (!temp || !temp->is_open)
+ if (!temp)
return 0;
+ if (!temp->is_open) {
+ fclose(temp);
+ return 0;
+ }
+
size_t wrote = fwrite(data, 1, size, temp);
fclose(temp);
{
FILE *temp = fopen(path, "r");
- if (!temp || !temp->is_open)
+ if (!temp)
return 0;
+ if (!temp->is_open) {
+ fclose(temp);
+ return 0;
+ }
+
size_t read = fread(data, 1, size, temp);
fclose(temp);