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
|
/* -----------------------------------------------------------------------------
* Copyright (c) 2011 Ozmo Inc
* Released under the GNU General Public License Version 2 (GPLv2).
* This file contains debug allocation and free functions. These are turned on
* by the configuration switch WANT_DEBUG_KMALLOC. This flags should be turned
* off in the release version but facilitate memory leak and corruption during
* development.
* -----------------------------------------------------------------------------
*/
#include <linux/module.h>
#include "ozconfig.h"
#include "ozalloc.h"
#include "oztrace.h"
#ifdef WANT_DEBUG_KMALLOC
/*------------------------------------------------------------------------------
*/
#define MAGIC_1 0x12848796
#define MAGIC_2 0x87465920
#define MAGIC_3 0x80288264
/*------------------------------------------------------------------------------
*/
struct oz_alloc_hdr {
int size;
int line;
unsigned magic;
struct list_head link;
};
/*------------------------------------------------------------------------------
*/
static unsigned long g_total_alloc_size;
static int g_alloc_count;
static DEFINE_SPINLOCK(g_alloc_lock);
static LIST_HEAD(g_alloc_list);
/*------------------------------------------------------------------------------
* Context: any
*/
void *oz_alloc_debug(size_t size, gfp_t flags, int line)
{
struct oz_alloc_hdr *hdr = (struct oz_alloc_hdr *)
kmalloc(size + sizeof(struct oz_alloc_hdr) +
sizeof(unsigned), flags);
if (hdr) {
unsigned long irq_state;
hdr->size = size;
hdr->line = line;
hdr->magic = MAGIC_1;
*(unsigned *)(((u8 *)(hdr + 1)) + size) = MAGIC_2;
spin_lock_irqsave(&g_alloc_lock, irq_state);
g_total_alloc_size += size;
g_alloc_count++;
list_add_tail(&hdr->link, &g_alloc_list);
spin_unlock_irqrestore(&g_alloc_lock, irq_state);
return hdr + 1;
}
return 0;
}
/*------------------------------------------------------------------------------
* Context: any
*/
void oz_free_debug(void *p)
{
if (p) {
struct oz_alloc_hdr *hdr = (struct oz_alloc_hdr *)
(((unsigned char *)p) - sizeof(struct oz_alloc_hdr));
if (hdr->magic == MAGIC_1) {
unsigned long irq_state;
if (*(unsigned *)(((u8 *)(hdr + 1)) + hdr->size)
!= MAGIC_2) {
oz_trace("oz_free_debug: Corrupted beyond"
" %p size %d\n", hdr+1, hdr->size);
return;
}
spin_lock_irqsave(&g_alloc_lock, irq_state);
g_total_alloc_size -= hdr->size;
g_alloc_count--;
list_del(&hdr->link);
spin_unlock_irqrestore(&g_alloc_lock, irq_state);
hdr->magic = MAGIC_3;
kfree(hdr);
} else {
oz_trace("oz_free_debug: Invalid magic number %u\n",
hdr->magic);
}
}
}
/*------------------------------------------------------------------------------
* Context: process
*/
void oz_trace_leaks(void)
{
#ifdef WANT_TRACE
struct list_head *e;
oz_trace("Total alloc size:%ld Alloc count:%d\n",
g_total_alloc_size, g_alloc_count);
if (g_alloc_count)
oz_trace("Trace of leaks.\n");
else
oz_trace("No memory leaks.\n");
list_for_each(e, &g_alloc_list) {
struct oz_alloc_hdr *hdr =
container_of(e, struct oz_alloc_hdr, link);
oz_trace("LEAK size %d line %d\n", hdr->size, hdr->line);
}
#endif /* #ifdef WANT_TRACE */
}
#endif /* #ifdef WANT_DEBUG_KMALLOC */
|