aboutsummaryrefslogtreecommitdiff
path: root/malloc/mtrace-ctl.c
blob: 31adb46928f95b24381e052f86f3d27c6b6466b2 (plain)
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>

/* This module is a stand-alone control program for malloc's internal
   trace buffer.  It is intended to be preloaded like this:

   LD_PRELOAD=/usr/lib/libmtracectl.so ./myprog

   This module uses the following environment variables:

   MTRACE_CTL_COUNT - how many records to store (default: 1000).  Each
   record is 32 bytes, and the entire buffer is mmap'd at once.  If
   the buffer isn't big enough, it will overwrite early records with
   newer ones.  The total number of trace records is reported in the
   output file so that a larger buffer may be allocated on future runs.

   MTRACE_CTL_FILE - the output file name (default:
   /tmp/mtrace-$$.out).  Note that the default is per-pid but there is
   no way to specify a per-pid pattern via this environment variable.

   The output file will contain a header that says how many trace
   records were seen (which is usually more or less than the trace
   buffer size).  The trace buffer is then dumped one entry per line.

*/

#include "mtrace.h"

#define estr(str) write (2, str, strlen (str))

#if 0
static void
err(const char *str)
{
  estr (str);
  estr ("\n");
}
#endif

/*
 * mtrace_start - checks for buffer, allocates one if needed, starts trace.
 * mtrace_stop - stops tracing
 * mtrace_sync - syncs the buffer
 * mtrace_reset - resets buffer state to intial state
 */

struct _malloc_trace_buffer_s *mtrace_buffer = NULL;
size_t mtrace_buffer_bytesize = 0;

int
mtrace_start (void)
{
  const char *e;
  char *fname;
  int sequence = 0;

  e = getenv("MTRACE_CTL_COUNT");
  if (!e)
    e = "1000";

  e = getenv("MTRACE_CTL_FILE");
  if (!e)
    e = "/tmp/mtrace.out";

  fname = alloca (strlen(e) + 30);
  sprintf(fname, "%s.%d", e, getpid());
  while (access (fname, F_OK) == 0)
    {
      sequence ++;
      sprintf(fname, "%s.%d.%d", e, getpid(), sequence);
    }

  estr ("mtrace-ctl: writing to ");
  estr (fname);
  estr ("\n");

  __malloc_trace_init (fname);
  return 0;
}

void
mtrace_stop (void)
{
  size_t count;
  char line[100];

  count = __malloc_trace_stop ();
  sprintf (line, "mtrace-ctl: %lld entries recorded\n", (long long)count);
  estr (line);
}

void
mtrace_sync (void)
{
  __malloc_trace_sync ();
  //  __malloc_trace_buffer_ptr buf = __malloc_get_trace_buffer (&size, &head);
  //  msync (buf, size * sizeof(struct __malloc_trace_buffer_s), MS_SYNC | MS_INVALIDATE);
}

void
mtrace_reset (void)
{

  __malloc_trace_stop ();
  mtrace_start ();
}

void __attribute__((constructor))
mtrace_ctor(void)
{
  if (mtrace_start ())
    exit (1);
}

void __attribute__((destructor))
mtrace_dtor(void)
{
  mtrace_stop ();
  mtrace_sync ();
}

#if 0

const char * const typenames[] = {
  "unused  ",
  "malloc  ",
  "calloc  ",
  "free    ",
  "realloc ",
  "memalign",
  "valloc  ",
  "pvalloc  ",
};

void __attribute__((destructor))
djend(void)
{
  char *e;
  FILE *outf;
  size_t head, size, i;

  e = getenv("MTRACE_CTL_FILE");
  if (!e)
    {
      static char fname[100];
      sprintf(fname, "/tmp/mtrace-%d.out", getpid());
      e = fname;
    }

  outf = fopen(e, "w");
  if (!outf)
    err("cannot open output file");
  setbuf (outf, NULL);

  fprintf (outf, "%ld out of %ld events captured\n", (long)head, (long)size);

  fprintf (outf, "threadid type     path     ptr1             size             ptr2\n");
  for (i=0; i<size; i++)
    {
      __malloc_trace_buffer_ptr t = buf + (i+head) % size;

      switch (t->type)
	{
	case __MTB_TYPE_UNUSED:
	  break;
	default:
	  fprintf (outf, "%08x %s %c%c%c%c%c%c%c%c %016llx %016llx %016llx\n",
		   t->thread,
		   typenames[t->type],
		   t->path_thread_cache ? 'T' : '-',
		   t->path_cpu_cache ? 'c' : '-',
		   t->path_cpu_cache2 ? 'C' : '-',
		   t->path_sbrk ? 's' : '-',
		   t->path_mmap ? 'M' : '-',
		   t->path_munmap ? 'U' : '-',
		   t->path_m_f_realloc ? 'R' : '-',
		   t->path_hook ? 'H' : '-',
		   (long long unsigned int) (size_t) t->ptr1,
		   (long long unsigned int) t->size,
		   (long long unsigned int) (size_t) t->ptr2);
	  break;
	}
    }
  fclose (outf);

  munmap (buf, size * sizeof(struct __malloc_trace_buffer_s));
  return;
}
#endif