mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-20 02:27:51 +01:00
70d01b22e1
This is not a child of cmd, since they have independent lifetimes, but we don't want to noleak them all, since it's only the one currently in progress (and its children) that we want to exclude. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
162 lines
4.0 KiB
C
162 lines
4.0 KiB
C
/* Only possible if we're in developer mode. */
|
|
#ifdef DEVELOPER
|
|
#include <backtrace.h>
|
|
#include <ccan/tal/str/str.h>
|
|
#include <common/memleak.h>
|
|
#include <lightningd/chaintopology.h>
|
|
#include <lightningd/jsonrpc.h>
|
|
#include <lightningd/lightningd.h>
|
|
#include <lightningd/log.h>
|
|
#include <stdio.h>
|
|
|
|
static void json_add_ptr(struct json_result *response, const char *name,
|
|
const void *ptr)
|
|
{
|
|
char ptrstr[STR_MAX_CHARS(void *)];
|
|
sprintf(ptrstr, "%p", ptr);
|
|
json_add_string(response, name, ptrstr);
|
|
}
|
|
|
|
static void add_memdump(struct json_result *response,
|
|
const char *name, const tal_t *root,
|
|
struct command *cmd)
|
|
{
|
|
const tal_t *i;
|
|
|
|
json_array_start(response, name);
|
|
for (i = tal_first(root); i; i = tal_next(i)) {
|
|
const char *name = tal_name(i);
|
|
|
|
/* Don't try to dump this command! */
|
|
if (i == cmd || i == cmd->jcon)
|
|
continue;
|
|
|
|
/* Don't dump logs, we know they grow. */
|
|
if (name && streq(name, "struct log_book"))
|
|
continue;
|
|
|
|
json_object_start(response, NULL);
|
|
json_add_ptr(response, "parent", tal_parent(i));
|
|
json_add_ptr(response, "value", i);
|
|
if (name)
|
|
json_add_string(response, "label", name);
|
|
|
|
if (tal_first(i))
|
|
add_memdump(response, "children", i, cmd);
|
|
json_object_end(response);
|
|
}
|
|
json_array_end(response);
|
|
}
|
|
|
|
static void json_memdump(struct command *cmd,
|
|
const char *buffer UNNEEDED,
|
|
const jsmntok_t *params UNNEEDED)
|
|
{
|
|
struct json_result *response = new_json_result(cmd);
|
|
|
|
add_memdump(response, NULL, NULL, cmd);
|
|
|
|
command_success(cmd, response);
|
|
}
|
|
|
|
static const struct json_command dev_memdump_command = {
|
|
"dev-memdump",
|
|
json_memdump,
|
|
"Dump the memory objects currently used",
|
|
"Debugging tool for memory leaks"
|
|
};
|
|
AUTODATA(json_command, &dev_memdump_command);
|
|
|
|
static int json_add_syminfo(void *data, uintptr_t pc,
|
|
const char *filename, int lineno,
|
|
const char *function)
|
|
{
|
|
struct json_result *response = data;
|
|
char *str;
|
|
|
|
str = tal_fmt(response, "%s:%u (%s)", filename, lineno, function);
|
|
json_add_string(response, NULL, str);
|
|
tal_free(str);
|
|
return 0;
|
|
}
|
|
|
|
static void json_add_backtrace(struct json_result *response,
|
|
const uintptr_t *bt)
|
|
{
|
|
size_t i;
|
|
|
|
if (!bt)
|
|
return;
|
|
|
|
json_array_start(response, "backtrace");
|
|
/* First one serves as counter. */
|
|
for (i = 1; i < bt[0]; i++) {
|
|
backtrace_pcinfo(backtrace_state,
|
|
bt[i], json_add_syminfo,
|
|
NULL, response);
|
|
}
|
|
json_array_end(response);
|
|
}
|
|
|
|
static void scan_mem(struct command *cmd,
|
|
struct json_result *response,
|
|
struct lightningd *ld)
|
|
{
|
|
struct htable *memtable;
|
|
const tal_t *i;
|
|
const uintptr_t *backtrace;
|
|
|
|
/* Enter everything, except this cmd and its jcon */
|
|
memtable = memleak_enter_allocations(cmd, cmd, cmd->jcon);
|
|
|
|
/* First delete known false positives. */
|
|
chaintopology_mark_pointers_used(memtable, ld->topology);
|
|
htlc_inmap_mark_pointers_used(memtable, &ld->htlcs_in);
|
|
htlc_outmap_mark_pointers_used(memtable, &ld->htlcs_out);
|
|
|
|
/* Now delete ld and those which it has pointers to. */
|
|
memleak_remove_referenced(memtable, ld);
|
|
|
|
json_array_start(response, "leaks");
|
|
while ((i = memleak_get(memtable, &backtrace)) != NULL) {
|
|
const tal_t *p;
|
|
|
|
json_object_start(response, NULL);
|
|
json_add_ptr(response, "value", i);
|
|
if (tal_name(i))
|
|
json_add_string(response, "label", tal_name(i));
|
|
|
|
json_add_backtrace(response, backtrace);
|
|
json_array_start(response, "parents");
|
|
for (p = tal_parent(i); p; p = tal_parent(p)) {
|
|
json_add_string(response, NULL, tal_name(p));
|
|
p = tal_parent(p);
|
|
}
|
|
json_array_end(response);
|
|
json_object_end(response);
|
|
}
|
|
json_array_end(response);
|
|
}
|
|
|
|
static void json_memleak(struct command *cmd,
|
|
const char *buffer UNNEEDED,
|
|
const jsmntok_t *params UNNEEDED)
|
|
{
|
|
struct json_result *response = new_json_result(cmd);
|
|
|
|
json_object_start(response, NULL);
|
|
scan_mem(cmd, response, cmd->ld);
|
|
json_object_end(response);
|
|
|
|
command_success(cmd, response);
|
|
}
|
|
|
|
static const struct json_command dev_memleak_command = {
|
|
"dev-memleak",
|
|
json_memleak,
|
|
"Dump the memory objects unreferenced",
|
|
"Debugging tool for memory leaks"
|
|
};
|
|
AUTODATA(json_command, &dev_memleak_command);
|
|
#endif /* DEVELOPER */
|