From 52c506d034fb978538fc2b9624d4920c7e246464 Mon Sep 17 00:00:00 2001 From: Varun Reddy Yeturu Date: Fri, 9 Feb 2018 16:44:57 -0800 Subject: [PATCH] qcacmn: Add caller info to memory debug infrastructure Currently, the detected memory leaks would not dump the caller of the function which is leaking the memory. Add an extra parameter to the table to store the caller address and print the function during an assert. Change-Id: I6dc31b55fd4e78dc69df9eb6166ebb63086891c1 CRs-Fixed: 2177486 --- qdf/inc/qdf_mem.h | 12 ++++++++---- qdf/linux/src/i_qdf_mem.h | 4 +++- qdf/linux/src/qdf_mem.c | 27 ++++++++++++++++++--------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/qdf/inc/qdf_mem.h b/qdf/inc/qdf_mem.h index c0cbfeb60c..d0545cc178 100644 --- a/qdf/inc/qdf_mem.h +++ b/qdf/inc/qdf_mem.h @@ -101,6 +101,7 @@ void qdf_mem_exit(void); * @size: Number of bytes of memory to allocate. * @file: File name of the call site * @line: Line number of the call site + * @caller: Address of the caller function * * This function will dynamicallly allocate the specified number of bytes of * memory and add it to the qdf tracking list to check for memory leaks and @@ -108,10 +109,11 @@ void qdf_mem_exit(void); * * Return: A valid memory location on success, or NULL on failure */ -void *qdf_mem_malloc_debug(size_t size, const char *file, uint32_t line); +void *qdf_mem_malloc_debug(size_t size, const char *file, uint32_t line, + void *caller); #define qdf_mem_malloc(size) \ - qdf_mem_malloc_debug(size, __FILE__, __LINE__) + qdf_mem_malloc_debug(size, __FILE__, __LINE__, QDF_RET_IP) /** * qdf_mem_free_debug() - debug version of qdf_mem_free @@ -167,16 +169,18 @@ void qdf_mem_check_for_leaks(void); * @paddr: Physical address * @file: file name of the call site * @line: line numbe rof the call site + * @caller: Address of the caller function * * Return: pointer of allocated memory or null if memory alloc fails */ void *qdf_mem_alloc_consistent_debug(qdf_device_t osdev, void *dev, qdf_size_t size, qdf_dma_addr_t *paddr, - const char *file, uint32_t line); + const char *file, uint32_t line, + void *caller); #define qdf_mem_alloc_consistent(osdev, dev, size, paddr) \ qdf_mem_alloc_consistent_debug(osdev, dev, size, paddr, \ - __FILE__, __LINE__) + __FILE__, __LINE__, QDF_RET_IP) /** * qdf_mem_free_consistent_debug() - free consistent qdf memory diff --git a/qdf/linux/src/i_qdf_mem.h b/qdf/linux/src/i_qdf_mem.h index 63b066b7a9..f664e08b5a 100644 --- a/qdf/linux/src/i_qdf_mem.h +++ b/qdf/linux/src/i_qdf_mem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -66,6 +66,7 @@ #define vfree(buf) #define pci_alloc_consistent(dev, size, paddr) NULL #define __qdf_mempool_t void* +#define QDF_RET_IP NULL #endif /* __KERNEL__ */ #include @@ -205,6 +206,7 @@ int __qdf_mempool_init(qdf_device_t osdev, __qdf_mempool_t *pool, int pool_cnt, void __qdf_mempool_destroy(qdf_device_t osdev, __qdf_mempool_t pool); void *__qdf_mempool_alloc(qdf_device_t osdev, __qdf_mempool_t pool); void __qdf_mempool_free(qdf_device_t osdev, __qdf_mempool_t pool, void *buf); +#define QDF_RET_IP ((void *)_RET_IP_) #define __qdf_mempool_elem_size(_pool) ((_pool)->elem_size) #endif diff --git a/qdf/linux/src/qdf_mem.c b/qdf/linux/src/qdf_mem.c index ac5b1f5679..7938380093 100644 --- a/qdf/linux/src/qdf_mem.c +++ b/qdf/linux/src/qdf_mem.c @@ -89,6 +89,7 @@ static inline qdf_list_t *qdf_mem_dma_list(enum qdf_debug_domain domain) * @file: name of the file the allocation was made from * @line: line number of the file the allocation was made from * @size: size of the allocation in bytes + * @caller: Caller of the function for which memory is allocated * @header: a known value, used to detect out-of-bounds access */ struct qdf_mem_header { @@ -98,6 +99,7 @@ struct qdf_mem_header { const char *file; uint32_t line; uint32_t size; + void *caller; uint64_t header; }; @@ -142,7 +144,7 @@ static void qdf_mem_trailer_init(struct qdf_mem_header *header) } static void qdf_mem_header_init(struct qdf_mem_header *header, qdf_size_t size, - const char *file, uint32_t line) + const char *file, uint32_t line, void *caller) { QDF_BUG(header); if (!header) @@ -153,6 +155,7 @@ static void qdf_mem_header_init(struct qdf_mem_header *header, qdf_size_t size, header->file = file; header->line = line; header->size = size; + header->caller = caller; header->header = WLAN_MEM_HEADER; } @@ -357,6 +360,7 @@ static int seq_printf_printer(void *priv, const char *fmt, ...) * @file: the file which allocated memory * @line: the line at which allocation happened * @size: the size of allocation + * @caller: Address of the caller function * @count: how many allocations of same type * */ @@ -364,6 +368,7 @@ struct __qdf_mem_info { const char *file; uint32_t line; uint32_t size; + void *caller; uint32_t count; }; @@ -385,7 +390,7 @@ static void qdf_mem_domain_print_header(qdf_abstract_print print, { print(print_priv, "--------------------------------------------------------------"); - print(print_priv, " count size total filename"); + print(print_priv, " count size total filename caller"); print(print_priv, "--------------------------------------------------------------"); } @@ -409,12 +414,12 @@ static void qdf_mem_meta_table_print(struct __qdf_mem_info *table, break; print(print_priv, - "%6u x %5u = %7uB @ %s:%u", + "%6u x %5u = %7uB @ %s:%u %pS", table[i].count, table[i].size, table[i].count * table[i].size, kbasename(table[i].file), - table[i].line); + table[i].line, table[i].caller); } } @@ -436,12 +441,14 @@ static bool qdf_mem_meta_table_insert(struct __qdf_mem_info *table, table[i].line = meta->line; table[i].size = meta->size; table[i].count = 1; + table[i].caller = meta->caller; break; } if (table[i].file == meta->file && table[i].line == meta->line && - table[i].size == meta->size) { + table[i].size == meta->size && + table[i].caller == meta->caller) { table[i].count++; break; } @@ -1035,7 +1042,8 @@ static void qdf_mem_debug_exit(void) qdf_spinlock_destroy(&qdf_mem_dma_list_lock); } -void *qdf_mem_malloc_debug(size_t size, const char *file, uint32_t line) +void *qdf_mem_malloc_debug(size_t size, const char *file, uint32_t line, + void *caller) { QDF_STATUS status; enum qdf_debug_domain current_domain = qdf_debug_domain_get(); @@ -1066,7 +1074,7 @@ void *qdf_mem_malloc_debug(size_t size, const char *file, uint32_t line) return NULL; } - qdf_mem_header_init(header, size, file, line); + qdf_mem_header_init(header, size, file, line, caller); qdf_mem_trailer_init(header); ptr = qdf_mem_get_ptr(header); @@ -1586,7 +1594,8 @@ qdf_mem_dma_free(void *dev, qdf_size_t size, void *vaddr, qdf_dma_addr_t paddr) #ifdef MEMORY_DEBUG void *qdf_mem_alloc_consistent_debug(qdf_device_t osdev, void *dev, qdf_size_t size, qdf_dma_addr_t *paddr, - const char *file, uint32_t line) + const char *file, uint32_t line, + void *caller) { QDF_STATUS status; enum qdf_debug_domain current_domain = qdf_debug_domain_get(); @@ -1613,7 +1622,7 @@ void *qdf_mem_alloc_consistent_debug(qdf_device_t osdev, void *dev, * Prefix the header into DMA buffer causes SMMU faults, so * do not prefix header into the DMA buffers */ - qdf_mem_header_init(header, size, file, line); + qdf_mem_header_init(header, size, file, line, caller); qdf_spin_lock_irqsave(&qdf_mem_dma_list_lock); status = qdf_list_insert_front(mem_list, &header->node);