/**************************************************************************** * mm/mm_heap/mm_memdump.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include "mm_heap/mm.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #if UINTPTR_MAX <= UINT32_MAX # define MM_PTR_FMT_WIDTH 11 #elif UINTPTR_MAX <= UINT64_MAX # define MM_PTR_FMT_WIDTH 19 #endif /**************************************************************************** * Private Types ****************************************************************************/ /**************************************************************************** * Private Functions ****************************************************************************/ static void memdump_handler(FAR struct mm_allocnode_s *node, FAR void *arg) { FAR const struct mm_memdump_s *dump = arg; size_t nodesize = MM_SIZEOF_NODE(node); if (MM_NODE_IS_ALLOC(node)) { DEBUGASSERT(nodesize >= MM_SIZEOF_ALLOCNODE); #if CONFIG_MM_BACKTRACE < 0 if (dump->pid == PID_MM_ALLOC) { syslog(LOG_INFO, "%12zu%*p\n", nodesize, MM_PTR_FMT_WIDTH, ((FAR char *)node + MM_SIZEOF_ALLOCNODE)); } #elif CONFIG_MM_BACKTRACE == 0 if ((MM_DUMP_ASSIGN(dump->pid, node->pid) || MM_DUMP_ALLOC(dump->pid, node->pid) || MM_DUMP_LEAK(dump->pid, node->pid)) && node->seqno >= dump->seqmin && node->seqno <= dump->seqmax) { syslog(LOG_INFO, "%6d%12zu%12lu%*p\n", node->pid, nodesize, node->seqno, MM_PTR_FMT_WIDTH, ((FAR char *)node + MM_SIZEOF_ALLOCNODE)); } #else if ((MM_DUMP_ASSIGN(dump->pid, node->pid) || MM_DUMP_ALLOC(dump->pid, node->pid) || MM_DUMP_LEAK(dump->pid, node->pid)) && node->seqno >= dump->seqmin && node->seqno <= dump->seqmax) { char buf[CONFIG_MM_BACKTRACE * MM_PTR_FMT_WIDTH + 1] = ""; FAR const char *format = " %0*p"; int i; for (i = 0; i < CONFIG_MM_BACKTRACE && node->backtrace[i]; i++) { snprintf(buf + i * MM_PTR_FMT_WIDTH, sizeof(buf) - i * MM_PTR_FMT_WIDTH, format, MM_PTR_FMT_WIDTH - 1, node->backtrace[i]); } syslog(LOG_INFO, "%6d%12zu%12lu%*p%s\n", node->pid, nodesize, node->seqno, MM_PTR_FMT_WIDTH, ((FAR char *)node + MM_SIZEOF_ALLOCNODE), buf); } #endif } else if (dump->pid == PID_MM_FREE) { FAR struct mm_freenode_s *fnode = (FAR void *)node; DEBUGASSERT(nodesize >= MM_MIN_CHUNK); DEBUGASSERT(fnode->blink->flink == fnode); DEBUGASSERT(MM_SIZEOF_NODE(fnode->blink) <= nodesize); DEBUGASSERT(fnode->flink == NULL || fnode->flink->blink == fnode); DEBUGASSERT(fnode->flink == NULL || MM_SIZEOF_NODE(fnode->flink) == 0 || MM_SIZEOF_NODE(fnode->flink) >= nodesize); syslog(LOG_INFO, "%12zu%*p\n", nodesize, MM_PTR_FMT_WIDTH, ((FAR char *)node + MM_SIZEOF_ALLOCNODE)); } } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: mm_memdump * * Description: * mm_memdump returns a memory info about specified pid of task/thread. * if pid equals -1, this function will dump all allocated node and output * backtrace for every allocated node for this heap, if pid equals -2, this * function will dump all free node for this heap, and if pid is greater * than or equal to 0, will dump pid allocated node and output backtrace. ****************************************************************************/ void mm_memdump(FAR struct mm_heap_s *heap, FAR const struct mm_memdump_s *dump) { struct mallinfo_task info; if (dump->pid >= PID_MM_ALLOC) { syslog(LOG_INFO, "Dump all used memory node info:\n"); #if CONFIG_MM_BACKTRACE < 0 syslog(LOG_INFO, "%12s%*s\n", "Size", MM_PTR_FMT_WIDTH, "Address"); #else syslog(LOG_INFO, "%6s%12s%12s%*s %s\n", "PID", "Size", "Sequence", MM_PTR_FMT_WIDTH, "Address", "Backtrace"); #endif } else { syslog(LOG_INFO, "Dump all free memory node info:\n"); syslog(LOG_INFO, "%12s%*s\n", "Size", MM_PTR_FMT_WIDTH, "Address"); } #if CONFIG_MM_HEAP_MEMPOOL_THRESHOLD != 0 mempool_multiple_memdump(heap->mm_mpool, dump); #endif mm_foreach(heap, memdump_handler, (FAR void *)dump); info = mm_mallinfo_task(heap, dump); syslog(LOG_INFO, "%12s%12s\n", "Total Blks", "Total Size"); syslog(LOG_INFO, "%12d%12d\n", info.aordblks, info.uordblks); }