Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | // SPDX-License-Identifier: GPL-2.0+ /* * malloc command - show malloc information * * Copyright 2025 Canonical Ltd * Written by Simon Glass <simon.glass@canonical.com> */ #include <command.h> #include <linux/string.h> #include <display_options.h> #include <malloc.h> static int do_malloc_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct malloc_info info; char buf[12]; int ret; ret = malloc_get_info(&info); if (ret) return CMD_RET_FAILURE; printf("total bytes = %s\n", format_size(buf, info.total_bytes)); printf("in use bytes = %s\n", format_size(buf, info.in_use_bytes)); printf("largest free = %s\n", format_size(buf, malloc_largest_free())); printf("malloc count = %lu\n", info.malloc_count); printf("free count = %lu\n", info.free_count); printf("realloc count = %lu\n", info.realloc_count); if (IS_ENABLED(CONFIG_MCHECK_HEAP_PROTECTION)) printf("mcheck count = %zu\n", malloc_mcheck_count()); return 0; } static int do_malloc_dump(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { malloc_dump(); 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_LEAK) static struct malloc_leak_snap leak_snap; static int do_malloc_leak(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { if (argc < 2) { int leaks; if (!leak_snap.addr) { printf("No snapshot taken, use 'malloc leak start'\n"); return CMD_RET_FAILURE; } leaks = malloc_leak_check_count(&leak_snap); if (leaks > 0) printf("%d new allocs\n", leaks); else printf("No leaks\n"); return 0; } if (!strcmp(argv[1], "start")) { int ret; if (leak_snap.addr) malloc_leak_check_free(&leak_snap); ret = malloc_leak_check_start(&leak_snap); if (ret) return CMD_RET_FAILURE; printf("Heap snapshot: %d allocs\n", leak_snap.count); } else if (!strcmp(argv[1], "end")) { int leaks; if (!leak_snap.addr) { printf("No snapshot taken, use 'malloc leak start'\n"); return CMD_RET_FAILURE; } leaks = malloc_leak_check_end(&leak_snap); if (leaks > 0) printf("%d leaked allocs\n", leaks); else printf("No leaks\n"); } else { return CMD_RET_USAGE; } return 0; } #define MALLOC_LEAK_HELP \ "malloc leak [start|end] - detect heap leaks\n" \ " start - snapshot current heap allocations\n" \ " end - show allocations not in the snapshot\n" \ " (none) - count new allocations without freeing snapshot\n" #define MALLOC_LEAK_SUBCMD , U_BOOT_SUBCMD_MKENT(leak, 3, 1, do_malloc_leak) #else #define MALLOC_LEAK_HELP #define MALLOC_LEAK_SUBCMD #endif #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_LEAK_HELP 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) MALLOC_LEAK_SUBCMD MALLOC_LOG_SUBCMD); |