cmd: malloc: Add a command to show the malloc log
Add a command interface for the malloc-traffic log:
- malloc log start: Start recording allocations
- malloc log stop: Stop recording
- malloc log: Dump the recorded entries
Example output:
=> malloc log
Malloc log: 29 entries (max 524288, total 29)
Seq Type Ptr Size Caller
---- -------- ---------------- -------- ------
0 free 16a016e0 0 free_pipe_list:2001
<-parse_stream_outer:3208 <-parse_file_outer:3300
1 alloc 16a01b90 20 hush_file_init:3277
<-parse_file_outer:3295 <-run_pipe_real:1986
Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
This commit is contained in:
10
cmd/Kconfig
10
cmd/Kconfig
@@ -3049,6 +3049,16 @@ config CMD_MALLOC
|
||||
about memory allocation, such as total memory allocated and
|
||||
currently in use.
|
||||
|
||||
config CMD_MALLOC_LOG
|
||||
bool "malloc log - Log malloc traffic"
|
||||
depends on CMD_MALLOC && MCHECK_LOG
|
||||
default y
|
||||
help
|
||||
This adds the 'malloc log' subcommand which records all
|
||||
malloc/free/realloc calls with their addresses, sizes, and caller
|
||||
information. Use 'malloc log start' to begin recording and
|
||||
'malloc log' to display the recorded entries.
|
||||
|
||||
config CMD_MOUSE
|
||||
bool "mouse - Show mouse input"
|
||||
default y if MOUSE
|
||||
|
||||
41
cmd/malloc.c
41
cmd/malloc.c
@@ -38,10 +38,47 @@ static int do_malloc_dump(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused do_malloc_log(struct cmd_tbl *cmdtp, int flag,
|
||||
int argc, char *const argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
malloc_log_dump();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "start")) {
|
||||
malloc_log_start();
|
||||
printf("Malloc logging started\n");
|
||||
} else if (!strcmp(argv[1], "stop")) {
|
||||
malloc_log_stop();
|
||||
printf("Malloc logging stopped\n");
|
||||
} else if (!strcmp(argv[1], "dump")) {
|
||||
malloc_log_dump();
|
||||
} else {
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(CMD_MALLOC_LOG)
|
||||
#define MALLOC_LOG_HELP \
|
||||
"malloc log [start|stop|dump] - log malloc traffic\n" \
|
||||
" start - start recording malloc/free calls\n" \
|
||||
" stop - stop recording\n" \
|
||||
" dump - print the log (or just 'malloc log')\n"
|
||||
#define MALLOC_LOG_SUBCMD , U_BOOT_SUBCMD_MKENT(log, 3, 1, do_malloc_log)
|
||||
#else
|
||||
#define MALLOC_LOG_HELP
|
||||
#define MALLOC_LOG_SUBCMD
|
||||
#endif
|
||||
|
||||
U_BOOT_LONGHELP(malloc,
|
||||
"info - display malloc statistics\n"
|
||||
"malloc dump - dump heap chunks (address, size, status)\n");
|
||||
"malloc dump - dump heap chunks (address, size, status)\n"
|
||||
MALLOC_LOG_HELP);
|
||||
|
||||
U_BOOT_CMD_WITH_SUBCMDS(malloc, "malloc information", malloc_help_text,
|
||||
U_BOOT_SUBCMD_MKENT(info, 1, 1, do_malloc_info),
|
||||
U_BOOT_SUBCMD_MKENT(dump, 1, 1, do_malloc_dump));
|
||||
U_BOOT_SUBCMD_MKENT(dump, 1, 1, do_malloc_dump)
|
||||
MALLOC_LOG_SUBCMD);
|
||||
|
||||
@@ -390,7 +390,8 @@ Malloc-Traffic Log
|
||||
|
||||
On sandbox, when mcheck is enabled, a malloc-traffic log can record all
|
||||
malloc/free/realloc calls. This is useful for debugging allocation patterns
|
||||
and finding where allocations without caller info originate.
|
||||
and finding where allocations without caller info originate. See
|
||||
:doc:`../usage/cmd/malloc` for usage.
|
||||
|
||||
The log buffer is allocated from host memory using ``os_malloc()``, so it
|
||||
does not affect U-Boot's heap. The size is controlled by
|
||||
|
||||
@@ -13,6 +13,7 @@ Synopsis
|
||||
|
||||
malloc info
|
||||
malloc dump
|
||||
malloc log [start|stop]
|
||||
|
||||
Description
|
||||
-----------
|
||||
@@ -31,6 +32,13 @@ dump
|
||||
for debugging memory allocation issues. When CONFIG_MCHECK_HEAP_PROTECTION
|
||||
is enabled, the caller string is also shown if available.
|
||||
|
||||
log
|
||||
Controls the malloc traffic log. With no argument, dumps the recorded log
|
||||
entries. Use ``start`` to begin recording malloc/free/realloc calls, and
|
||||
``stop`` to stop recording. Each entry shows the operation type, pointer
|
||||
address, size, and caller backtrace. This is useful for tracking down
|
||||
memory leaks or understanding allocation patterns.
|
||||
|
||||
The total heap size is set by ``CONFIG_SYS_MALLOC_LEN``.
|
||||
|
||||
Example
|
||||
@@ -71,11 +79,31 @@ With CONFIG_MCHECK_HEAP_PROTECTION enabled, the caller backtrace is shown::
|
||||
18a3b840 90 used of_alias_scan:911 <-board_init_
|
||||
...
|
||||
|
||||
With CONFIG_CMD_MALLOC_LOG enabled, the log subcommand is available::
|
||||
|
||||
=> malloc log start
|
||||
Malloc logging started
|
||||
=> ... do some operations ...
|
||||
=> malloc log stop
|
||||
Malloc logging stopped
|
||||
=> malloc log
|
||||
Malloc log: 5 entries (max 524288, total 5)
|
||||
Seq Type Ptr Size Caller
|
||||
---- -------- ---------------- -------- ------
|
||||
0 alloc 16a01b90 20 hush_file_init:3277
|
||||
<-parse_file_outer:3295 <-run_pipe_real:1986
|
||||
1 alloc 16a01bc0 100 xmalloc:107 <-xzalloc:117
|
||||
<-new_pipe:1498 <-run_list_real:1702
|
||||
2 free 16a01bc0 0 free_pipe_list:2001
|
||||
<-parse_stream_outer:3208 <-parse_file_outer:3300
|
||||
...
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
The malloc command is enabled by CONFIG_CMD_MALLOC which depends on
|
||||
CONFIG_MALLOC_DEBUG.
|
||||
CONFIG_MALLOC_DEBUG. The log subcommand is enabled by CONFIG_CMD_MALLOC_LOG
|
||||
which additionally requires CONFIG_MCHECK_LOG.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
#include <dm/test.h>
|
||||
#include <test/cmd.h>
|
||||
#include <test/ut.h>
|
||||
@@ -52,3 +53,50 @@ static int cmd_test_malloc_dump(struct unit_test_state *uts)
|
||||
return 0;
|
||||
}
|
||||
CMD_TEST(cmd_test_malloc_dump, UTF_CONSOLE);
|
||||
|
||||
#if CONFIG_IS_ENABLED(MCHECK_LOG)
|
||||
/* Test 'malloc log' command */
|
||||
static int cmd_test_malloc_log(struct unit_test_state *uts)
|
||||
{
|
||||
struct mlog_info info;
|
||||
void *ptr, *ptr2;
|
||||
int seq;
|
||||
|
||||
ut_assertok(run_command("malloc log start", 0));
|
||||
ut_assert_nextline("Malloc logging started");
|
||||
ut_assert_console_end();
|
||||
|
||||
/* Get current log position so we know our sequence numbers */
|
||||
ut_assertok(malloc_log_info(&info));
|
||||
seq = info.total_count;
|
||||
|
||||
/* Do allocations with distinctive sizes we can search for */
|
||||
ptr = malloc(12345);
|
||||
ut_assertnonnull(ptr);
|
||||
ptr2 = realloc(ptr, 23456);
|
||||
ut_assertnonnull(ptr2);
|
||||
free(ptr2);
|
||||
|
||||
ut_assertok(run_command("malloc log stop", 0));
|
||||
ut_assert_nextline("Malloc logging stopped");
|
||||
ut_assert_console_end();
|
||||
|
||||
/* Dump the log and find our allocations by sequence number and size */
|
||||
ut_assertok(run_command("malloc log", 0));
|
||||
ut_assert_nextlinen("Malloc log: ");
|
||||
ut_assert_nextline("%4s %-8s %10s %8s %s",
|
||||
"Seq", "Type", "Address", "Size", "Caller");
|
||||
ut_assert_nextline("---- -------- ---------- -------- ------");
|
||||
/* 12345 = 0x3039, 23456 = 0x5ba0 */
|
||||
ut_assert_skip_to_linen("%4d alloc %10lx 3039", seq,
|
||||
(ulong)map_to_sysmem(ptr));
|
||||
ut_assert_skip_to_linen("%4d realloc %10lx 5ba0", seq + 1,
|
||||
(ulong)map_to_sysmem(ptr2));
|
||||
ut_assert_skip_to_linen("%4d free %10lx 0", seq + 2,
|
||||
(ulong)map_to_sysmem(ptr2));
|
||||
console_record_reset_enable(); /* discard remaining output */
|
||||
|
||||
return 0;
|
||||
}
|
||||
CMD_TEST(cmd_test_malloc_log, UTF_CONSOLE);
|
||||
#endif /* MCHECK_LOG */
|
||||
|
||||
Reference in New Issue
Block a user