=== modified file 'config.h.in' --- config.h.in 2012-02-04 20:47:29 +0000 +++ config.h.in 2012-05-01 09:53:02 +0000 @@ -8,7 +8,11 @@ #if defined (GRUB_UTIL) || !defined (GRUB_MACHINE) #include #define NESTED_FUNC_ATTR +#define MM_DEBUG 0 #else + +/* Define to 1 if you enable memory manager debugging. */ +#define MM_DEBUG @MM_DEBUG@ /* Define if C symbols get an underscore after compilation. */ #define HAVE_ASM_USCORE @HAVE_ASM_USCORE@ /* Define it to \"addr32\" or \"addr32;\" to make GAS happy. */ === modified file 'configure.ac' --- configure.ac 2012-04-29 16:15:24 +0000 +++ configure.ac 2012-05-01 09:53:58 +0000 @@ -759,9 +759,14 @@ # Memory manager debugging. AC_ARG_ENABLE([mm-debug], AS_HELP_STRING([--enable-mm-debug], - [include memory manager debugging]), - [AC_DEFINE([MM_DEBUG], [1], - [Define to 1 if you enable memory manager debugging.])]) + [include memory manager debugging])) +if test x$enable_mm_debug = xyes; then + MM_DEBUG=1 +else + MM_DEBUG=0 +fi + +AC_SUBST([MM_DEBUG]) AC_ARG_ENABLE([cache-stats], AS_HELP_STRING([--enable-cache-stats], @@ -786,6 +791,10 @@ [AS_HELP_STRING([--enable-grub-emu-pci], [build and install the `grub-emu' debugging utility with PCI support (potentially dangerous) (default=no)])]) +if test "$platform" = emu && test "$MM_DEBUG" = 1; then + AC_MSG_ERROR([grub-emu doesn't support mm-debug]) +fi + if test "$platform" = emu; then missing_ncurses= [# Check for curses libraries.] @@ -1132,6 +1141,7 @@ AM_CONDITIONAL([COND_APPLE_CC], [test x$TARGET_APPLE_CC = x1]) AM_CONDITIONAL([COND_ENABLE_EFIEMU], [test x$enable_efiemu = xyes]) AM_CONDITIONAL([COND_ENABLE_CACHE_STATS], [test x$DISK_CACHE_STATS = x1]) +AM_CONDITIONAL([COND_ENABLE_MM_DEBUG], [test x$MM_DEBUG = x1]) AM_CONDITIONAL([COND_HAVE_ASM_USCORE], [test x$HAVE_ASM_USCORE = x1]) AM_CONDITIONAL([COND_CYGWIN], [test x$host_os = xcygwin]) === modified file 'grub-core/Makefile.core.def' --- grub-core/Makefile.core.def 2012-04-01 19:35:18 +0000 +++ grub-core/Makefile.core.def 2012-04-30 18:22:33 +0000 @@ -1816,6 +1816,13 @@ }; module = { + name = printmem; + common = commands/printmem.c; + condition = COND_ENABLE_MM_DEBUG; + enable = noemu; +}; + +module = { name = adler32; common = lib/adler32.c; }; === added file 'grub-core/commands/printmem.c' --- grub-core/commands/printmem.c 1970-01-01 00:00:00 +0000 +++ grub-core/commands/printmem.c 2012-05-01 10:20:29 +0000 @@ -0,0 +1,75 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2012 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_err_t +grub_cmd_print_mem (grub_command_t ctxt __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + grub_mm_header_t cur; + for (cur = grub_mm_allocated; cur; cur = cur->next) + { + struct grub_mm_alloc_info *info = (struct grub_mm_alloc_info *) (cur + 1); + if (grub_strcmp (info->file, "kern/dl.c") == 0 + || grub_strcmp (info->file, "kern/env.c") == 0 + || grub_strcmp (info->file, "kern/disk.c") == 0 + || grub_strcmp (info->file, "kern/command.c") == 0 + || grub_strcmp (info->file, "kern/parser.c") == 0 + || grub_strcmp (info->file, "normal/dyncmd.c") == 0 + || grub_strcmp (info->file, "normal/autofs.c") == 0 + || grub_strcmp (info->file, "normal/crypto.c") == 0 + || grub_strcmp (info->file, "normal/term.c") == 0 + || grub_strcmp (info->file, "normal/color.c") == 0 + || grub_strcmp (info->file, "script/script.c") == 0 + || grub_strcmp (info->file, "script/argv.c") == 0 + || grub_strcmp (info->file, "commands/extcmd.c") == 0) + continue; + /* TRANSLATORS: This line lists currently allocated memory. + First two fiels are filename and line number. + It's followed by the pointer and the size. */ + grub_printf_ (N_("%s:%d %p %lu B\n"), info->file, info->lineno, cur + 1, + (unsigned long) + ((cur->size << GRUB_MM_ALIGN_LOG2) - sizeof (*cur) + - sizeof (*info))); + } + return 0; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(printmem) +{ + cmd = grub_register_command ("printmem", grub_cmd_print_mem, 0, + N_("Print currently used memory.")); +} + +GRUB_MOD_FINI(printmem) +{ + grub_unregister_command (cmd); +} === modified file 'grub-core/kern/misc.c' --- grub-core/kern/misc.c 2012-02-29 18:35:19 +0000 +++ grub-core/kern/misc.c 2012-05-01 10:08:34 +0000 @@ -436,22 +436,37 @@ return num; } +#if MM_DEBUG +char * +grub_debug_strdup (const char *file, int line, const char *s) +#else char * grub_strdup (const char *s) +#endif { grub_size_t len; char *p; len = grub_strlen (s) + 1; - p = (char *) grub_malloc (len); +#if MM_DEBUG + p = (char *) grub_debug_malloc (file, line, len); +#else + p = (char *) grub_malloc (len); +#endif if (! p) return 0; return grub_memcpy (p, s, len); } + +#if MM_DEBUG +char * +grub_debug_strndup (const char *file, int line, const char *s, grub_size_t n) +#else char * grub_strndup (const char *s, grub_size_t n) +#endif { grub_size_t len; char *p; @@ -459,7 +474,11 @@ len = grub_strlen (s); if (len > n) len = n; +#if MM_DEBUG + p = (char *) grub_debug_malloc (file, line, len + 1); +#else p = (char *) grub_malloc (len + 1); +#endif if (! p) return 0; @@ -1051,8 +1070,13 @@ return ret; } +#if MM_DEBUG +char * +grub_debug_xvasprintf (const char *file, int line, const char *fmt, va_list ap) +#else char * grub_xvasprintf (const char *fmt, va_list ap) +#endif { grub_size_t s, as = PREALLOC_SIZE; char *ret; @@ -1060,7 +1084,11 @@ while (1) { va_list ap2; +#if MM_DEBUG + ret = grub_debug_malloc (file, line, as + 1); +#else ret = grub_malloc (as + 1); +#endif if (!ret) return NULL; @@ -1078,14 +1106,23 @@ } } +#if MM_DEBUG +char * +grub_debug_xasprintf (const char *file, int line, const char *fmt, ...) +#else char * grub_xasprintf (const char *fmt, ...) +#endif { va_list ap; char *ret; va_start (ap, fmt); +#if MM_DEBUG + ret = grub_debug_xvasprintf (file, line, fmt, ap); +#else ret = grub_xvasprintf (fmt, ap); +#endif va_end (ap); return ret; === modified file 'grub-core/kern/mm.c' --- grub-core/kern/mm.c 2012-02-03 13:20:31 +0000 +++ grub-core/kern/mm.c 2012-05-01 09:50:18 +0000 @@ -68,7 +68,7 @@ #include #include -#ifdef MM_DEBUG +#if MM_DEBUG # undef grub_malloc # undef grub_zalloc # undef grub_realloc @@ -84,10 +84,13 @@ to the header and a pointer to its region, respectively. PTR must be allocated. */ static void -get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r) +get_header_from_pointer (void *ptr_in, grub_mm_header_t *p, grub_mm_region_t *r) { - if ((grub_addr_t) ptr & (GRUB_MM_ALIGN - 1)) - grub_fatal ("unaligned pointer %p", ptr); + void *ptr; + if ((grub_addr_t) ptr_in & (GRUB_MM_ALIGN - 1)) + grub_fatal ("unaligned pointer %p", ptr_in); + + ptr = (grub_mm_header_t) ptr_in - (GRUB_MM_CELLS_METADATA - 1); for (*r = grub_mm_base; *r; *r = (*r)->next) if ((grub_addr_t) ptr > (grub_addr_t) ((*r) + 1) @@ -95,11 +98,11 @@ break; if (! *r) - grub_fatal ("out of range pointer %p", ptr); + grub_fatal ("out of range pointer %p", ptr_in); *p = (grub_mm_header_t) ptr - 1; if ((*p)->magic != GRUB_MM_ALLOC_MAGIC) - grub_fatal ("alloc magic is broken at %p", *p); + grub_fatal ("alloc magic is broken at %p: 0x%x", *p, (*p)->magic); } /* Initialize a region starting from ADDR and whose size is SIZE, @@ -150,6 +153,9 @@ { grub_mm_header_t p, q; + COMPILE_TIME_ASSERT (sizeof (struct grub_mm_header) == GRUB_MM_ALIGN); + COMPILE_TIME_ASSERT (sizeof (struct grub_mm_region) == GRUB_MM_ALIGN); + /* When everything is allocated side effect is that *first will have alloc magic marked, meaning that there is no room in this region. */ if ((*first)->magic == GRUB_MM_ALLOC_MAGIC) @@ -160,7 +166,8 @@ { grub_off_t extra; - extra = ((grub_addr_t) (p + 1) >> GRUB_MM_ALIGN_LOG2) % align; + extra = ((grub_addr_t) (p + GRUB_MM_CELLS_METADATA) + >> GRUB_MM_ALIGN_LOG2) & (align - 1); if (extra) extra = align - extra; @@ -266,7 +273,7 @@ pieces before this will be un-used. */ *first = q; - return p + 1; + return p + GRUB_MM_CELLS_METADATA; } /* Search was completed without result. */ @@ -282,7 +289,8 @@ grub_memalign (grub_size_t align, grub_size_t size) { grub_mm_region_t r; - grub_size_t n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1; + grub_size_t n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + + GRUB_MM_CELLS_METADATA; int count = 0; if (!grub_mm_base) @@ -435,7 +443,8 @@ } /* FIXME: Not optimal. */ - n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1; + n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + + GRUB_MM_CELLS_METADATA; get_header_from_pointer (ptr, &p, &r); if (p->size >= n) @@ -450,7 +459,7 @@ return q; } -#ifdef MM_DEBUG +#if MM_DEBUG int grub_mm_debug = 0; void @@ -510,6 +519,50 @@ grub_printf ("\n"); } +grub_mm_header_t grub_mm_allocated; + +static void +save_ref (void *ptr, int line, const char *file) +{ + grub_mm_header_t head; + struct grub_mm_alloc_info *info; + + COMPILE_TIME_ASSERT ((sizeof (struct grub_mm_alloc_info) + & (GRUB_MM_ALIGN - 1)) == 0); + + if (!ptr) + return; + + head = ptr; + head -= GRUB_MM_CELLS_METADATA; + info = (struct grub_mm_alloc_info *) (head + 1); + head->next = grub_mm_allocated; + if (head->next) + head->next->prev = head; + head->prev = 0; + info->lineno = line; + grub_strncpy (info->file, file, sizeof (info->file)); + grub_mm_allocated = head; +} + +static void +delete_ref (void *ptr) +{ + grub_mm_header_t head; + + if (!ptr) + return; + + head = ptr; + head -= GRUB_MM_CELLS_METADATA; + if (head->next) + head->next->prev = head->prev; + if (head->prev) + head->prev->next = head->next; + else if (grub_mm_allocated == head) + grub_mm_allocated = head->next; +} + void * grub_debug_malloc (const char *file, int line, grub_size_t size) { @@ -518,6 +571,7 @@ if (grub_mm_debug) grub_printf ("%s:%d: malloc (0x%" PRIxGRUB_SIZE ") = ", file, line, size); ptr = grub_malloc (size); + save_ref (ptr, line, file); if (grub_mm_debug) grub_printf ("%p\n", ptr); return ptr; @@ -531,6 +585,7 @@ if (grub_mm_debug) grub_printf ("%s:%d: zalloc (0x%" PRIxGRUB_SIZE ") = ", file, line, size); ptr = grub_zalloc (size); + save_ref (ptr, line, file); if (grub_mm_debug) grub_printf ("%p\n", ptr); return ptr; @@ -539,6 +594,7 @@ void grub_debug_free (const char *file, int line, void *ptr) { + delete_ref (ptr); if (grub_mm_debug) grub_printf ("%s:%d: free (%p)\n", file, line, ptr); grub_free (ptr); @@ -547,9 +603,11 @@ void * grub_debug_realloc (const char *file, int line, void *ptr, grub_size_t size) { + delete_ref (ptr); if (grub_mm_debug) grub_printf ("%s:%d: realloc (%p, 0x%" PRIxGRUB_SIZE ") = ", file, line, ptr, size); ptr = grub_realloc (ptr, size); + save_ref (ptr, line, file); if (grub_mm_debug) grub_printf ("%p\n", ptr); return ptr; === modified file 'grub-core/lib/relocator.c' --- grub-core/lib/relocator.c 2012-04-13 14:55:20 +0000 +++ grub-core/lib/relocator.c 2012-05-01 09:34:38 +0000 @@ -358,7 +358,9 @@ r2->first = r1->first; hl->next = r2->first; *rp = (*rp)->next; - grub_free (g + 1); + g->next = 0; + g->prev = 0; + grub_free (g + GRUB_MM_CELLS_METADATA); } break; } @@ -368,10 +370,11 @@ GRUB_MM_ALIGN); h->size = ((subchu->start + subchu->size + GRUB_MM_ALIGN - 1) / GRUB_MM_ALIGN) - - (subchu->start / GRUB_MM_ALIGN) - 1; - h->next = h; + - (subchu->start / GRUB_MM_ALIGN); + h->next = 0; + h->prev = 0; h->magic = GRUB_MM_ALLOC_MAGIC; - grub_free (h + 1); + grub_free (h + GRUB_MM_CELLS_METADATA); break; } #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS @@ -428,6 +431,9 @@ unsigned j, N = 0; grub_addr_t target = 0; + COMPILE_TIME_ASSERT (sizeof (struct grub_mm_header) == GRUB_MM_ALIGN); + COMPILE_TIME_ASSERT (sizeof (struct grub_mm_region) == GRUB_MM_ALIGN); + grub_dprintf ("relocator", "trying to allocate in 0x%lx-0x%lx aligned 0x%lx size 0x%lx\n", (unsigned long) start, (unsigned long) end, === modified file 'grub-core/normal/main.c' --- grub-core/normal/main.c 2012-03-11 13:43:18 +0000 +++ grub-core/normal/main.c 2012-05-01 10:16:23 +0000 @@ -41,8 +41,13 @@ int grub_normal_exit_level = 0; /* Read a line from the file FILE. */ +#if MM_DEBUG +char * +grub_file_debug_getline (const char *cfile, int line, grub_file_t file) +#else char * grub_file_getline (grub_file_t file) +#endif { char c; grub_size_t pos = 0; @@ -51,7 +56,11 @@ grub_size_t max_len = 64; /* Initially locate some space. */ - cmdline = grub_malloc (max_len); +#if MM_DEBUG + cmdline = grub_debug_malloc (cfile, line, max_len); +#else + cmdline = grub_debug_malloc (max_len); +#endif if (! cmdline) return 0; @@ -69,7 +78,11 @@ { char *old_cmdline = cmdline; max_len = max_len * 2; +#if MM_DEBUG + cmdline = grub_debug_realloc (cfile, line, cmdline, max_len); +#else cmdline = grub_realloc (cmdline, max_len); +#endif if (! cmdline) { grub_free (old_cmdline); === modified file 'include/grub/misc.h' --- include/grub/misc.h 2012-03-05 00:17:55 +0000 +++ include/grub/misc.h 2012-05-01 10:07:51 +0000 @@ -314,8 +314,16 @@ } } +#if MM_DEBUG +char *EXPORT_FUNC(grub_debug_strdup) (const char *file, int line, const char *s) __attribute__ ((warn_unused_result)); +char *EXPORT_FUNC(grub_debug_strndup) (const char *file, int line, const char *s, grub_size_t n) __attribute__ ((warn_unused_result)); + +#define grub_strdup(s) grub_debug_strdup (GRUB_FILE, __LINE__, s) +#define grub_strndup(s, n) grub_debug_strndup (GRUB_FILE, __LINE__, s, n) +#else char *EXPORT_FUNC(grub_strdup) (const char *s) __attribute__ ((warn_unused_result)); char *EXPORT_FUNC(grub_strndup) (const char *s, grub_size_t n) __attribute__ ((warn_unused_result)); +#endif void *EXPORT_FUNC(grub_memset) (void *s, int c, grub_size_t n); grub_size_t EXPORT_FUNC(grub_strlen) (const char *s) __attribute__ ((warn_unused_result)); int EXPORT_FUNC(grub_printf) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); @@ -363,9 +371,17 @@ __attribute__ ((format (printf, 3, 4))); int EXPORT_FUNC(grub_vsnprintf) (char *str, grub_size_t n, const char *fmt, va_list args); +#if MM_DEBUG +char *EXPORT_FUNC(grub_debug_xasprintf) (const char *file, int line, const char *fmt, ...) + __attribute__ ((format (printf, 3, 4))) __attribute__ ((warn_unused_result)); +char *EXPORT_FUNC(grub_debug_xvasprintf) (const char *file, int line, const char *fmt, va_list args) __attribute__ ((warn_unused_result)); +#define grub_xasprintf(fmt, args...) grub_debug_xasprintf (GRUB_FILE, __LINE__, fmt, ## args) +#define grub_xvasprintf(fmt, args) grub_debug_xvasprintf (GRUB_FILE, __LINE__, fmt, args) +#else char *EXPORT_FUNC(grub_xasprintf) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((warn_unused_result)); char *EXPORT_FUNC(grub_xvasprintf) (const char *fmt, va_list args) __attribute__ ((warn_unused_result)); +#endif void EXPORT_FUNC(grub_exit) (void) __attribute__ ((noreturn)); void EXPORT_FUNC(grub_abort) (void) __attribute__ ((noreturn)); grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, === modified file 'include/grub/mm.h' --- include/grub/mm.h 2011-11-13 11:48:39 +0000 +++ include/grub/mm.h 2012-05-01 09:53:09 +0000 @@ -39,7 +39,7 @@ #define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__); /* For debugging. */ -#if defined(MM_DEBUG) && !defined(GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) +#if MM_DEBUG /* Set this variable to 1 when you want to trace all memory function calls. */ extern int EXPORT_VAR(grub_mm_debug); === modified file 'include/grub/mm_private.h' --- include/grub/mm_private.h 2010-08-28 12:52:25 +0000 +++ include/grub/mm_private.h 2012-05-01 09:46:58 +0000 @@ -30,13 +30,7 @@ struct grub_mm_header *next; grub_size_t size; grub_size_t magic; -#if GRUB_CPU_SIZEOF_VOID_P == 4 - char padding[4]; -#elif GRUB_CPU_SIZEOF_VOID_P == 8 - char padding[8]; -#else -# error "unknown word size" -#endif + struct grub_mm_header *prev; } *grub_mm_header_t; @@ -48,6 +42,17 @@ #define GRUB_MM_ALIGN (1 << GRUB_MM_ALIGN_LOG2) +#if MM_DEBUG +struct grub_mm_alloc_info +{ + int lineno; + char file[128 - sizeof (int)]; +}; +static const grub_size_t GRUB_MM_CELLS_METADATA = ((sizeof (struct grub_mm_alloc_info) >> GRUB_MM_ALIGN_LOG2) + 1); +#else +#define GRUB_MM_CELLS_METADATA 1 +#endif + typedef struct grub_mm_region { struct grub_mm_header *first; @@ -61,4 +66,8 @@ extern grub_mm_region_t EXPORT_VAR (grub_mm_base); #endif +#if MM_DEBUG +extern grub_mm_header_t EXPORT_VAR(grub_mm_allocated); +#endif + #endif === modified file 'include/grub/normal.h' --- include/grub/normal.h 2012-03-10 22:25:34 +0000 +++ include/grub/normal.h 2012-05-01 10:15:01 +0000 @@ -51,7 +51,14 @@ void grub_menu_init_page (int nested, int edit, int *num_entries, struct grub_term_output *term); void grub_normal_init_page (struct grub_term_output *term); +#if MM_DEBUG +char *grub_file_debug_getline (const char *call_file, + int line, grub_file_t file); +#define grub_file_getline(file) \ + grub_file_debug_getline (GRUB_FILE, __LINE__, file) +#else char *grub_file_getline (grub_file_t file); +#endif void grub_cmdline_run (int nested); /* Defined in `cmdline.c'. */