Browse Source

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
Varun Reddy Yeturu 7 years ago
parent
commit
52c506d034
3 changed files with 29 additions and 14 deletions
  1. 8 4
      qdf/inc/qdf_mem.h
  2. 3 1
      qdf/linux/src/i_qdf_mem.h
  3. 18 9
      qdf/linux/src/qdf_mem.c

+ 8 - 4
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

+ 3 - 1
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 <qdf_status.h>
 
@@ -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

+ 18 - 9
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);