gcc/java:
[official-gcc.git] / libjava / gnu / gcj / util / natGCInfo.cc
blob7e5c6fbb8454984934fe96d9bd4d6a532ccd6f67
1 /* natGCInfo.cc -- Native portion of support for creating heap dumps.
2 Copyright (C) 2007 Free Software Foundation
4 This file is part of libgcj.
6 This software is copyrighted work licensed under the terms of the
7 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
8 details. */
11 #include <config.h>
13 #include <gcj/cni.h>
15 #include <gnu/gcj/util/GCInfo.h>
17 #ifdef HAVE_PROC_SELF_MAPS
19 // If /proc/self/maps does not exist we assume we are doomed and do nothing.
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <errno.h>
29 // Boehm GC includes.
31 #ifdef PACKAGE_NAME
32 #undef PACKAGE_NAME
33 #endif
35 #ifdef PACKAGE_STRING
36 #undef PACKAGE_STRING
37 #endif
39 #ifdef PACKAGE_TARNAME
40 #undef PACKAGE_TARNAME
41 #endif
43 #ifdef PACKAGE_VERSION
44 #undef PACKAGE_VERSION
45 #endif
47 #ifdef TRUE
48 #undef TRUE
49 #endif
51 #ifdef FALSE
52 #undef FALSE
53 #endif
55 extern "C" {
56 #include "private/dbg_mlc.h"
57 int GC_n_set_marks(hdr* hhdr);
58 ptr_t GC_clear_stack(ptr_t p);
59 extern int GC_gcj_kind;
60 extern int GC_gcj_debug_kind;
63 #endif
65 #ifdef HAVE_PROC_SELF_MAPS
67 static int gc_ok = 1;
69 typedef struct gc_debug_info
71 int used;
72 int free;
73 int wasted;
74 int blocks;
75 FILE* fp;
78 static void
79 GC_print_debug_callback(hblk *h, word user_data)
81 hdr *hhdr = HDR(h);
82 size_t bytes = WORDS_TO_BYTES(hhdr -> hb_sz);
84 gc_debug_info *pinfo = (gc_debug_info *)user_data;
86 fprintf(pinfo->fp, "ptr = %#lx, kind = %d, size = %zd, marks = %d\n",
87 (unsigned long)h, hhdr->hb_obj_kind, bytes, GC_n_set_marks(hhdr));
91 this next section of definitions shouldn't really be here.
92 copied from boehmgc/allchblk.c
95 # define UNIQUE_THRESHOLD 32
96 # define HUGE_THRESHOLD 256
97 # define FL_COMPRESSION 8
98 # define N_HBLK_FLS (HUGE_THRESHOLD - UNIQUE_THRESHOLD)/FL_COMPRESSION \
99 + UNIQUE_THRESHOLD
100 #ifndef USE_MUNMAP
101 extern "C" {
102 extern word GC_free_bytes[N_HBLK_FLS+1];
104 #endif
106 # ifdef USE_MUNMAP
107 # define IS_MAPPED(hhdr) (((hhdr) -> hb_flags & WAS_UNMAPPED) == 0)
108 # else /* !USE_MMAP */
109 # define IS_MAPPED(hhdr) 1
110 # endif /* USE_MUNMAP */
112 static void
113 GC_print_hblkfreelist_file(FILE *fp)
115 struct hblk * h;
116 word total_free = 0;
117 hdr * hhdr;
118 word sz;
119 int i;
121 fprintf(fp, "---------- Begin free map ----------\n");
122 for (i = 0; i <= N_HBLK_FLS; ++i)
124 h = GC_hblkfreelist[i];
125 #ifdef USE_MUNMAP
126 if (0 != h)
127 fprintf (fp, "Free list %ld:\n", (unsigned long)i);
128 #else
129 if (0 != h)
130 fprintf (fp, "Free list %ld (Total size %ld):\n",
131 (unsigned long)i,
132 (unsigned long)GC_free_bytes[i]);
133 #endif
134 while (h != 0)
136 hhdr = HDR(h);
137 sz = hhdr -> hb_sz;
138 fprintf (fp, "\t0x%lx size %lu ", (unsigned long)h,
139 (unsigned long)sz);
140 total_free += sz;
142 if (GC_is_black_listed (h, HBLKSIZE) != 0)
143 fprintf (fp, "start black listed\n");
144 else if (GC_is_black_listed(h, hhdr -> hb_sz) != 0)
145 fprintf (fp, "partially black listed\n");
146 else
147 fprintf (fp, "not black listed\n");
149 h = hhdr -> hb_next;
152 #ifndef USE_MUNMAP
153 if (total_free != GC_large_free_bytes)
155 fprintf (fp, "GC_large_free_bytes = %lu (INCONSISTENT!!)\n",
156 (unsigned long) GC_large_free_bytes);
158 #endif
159 fprintf (fp, "Total of %lu bytes on free list\n", (unsigned long)total_free);
160 fprintf (fp, "---------- End free map ----------\n");
163 static int GC_dump_count = 1;
165 static void
166 GC_print_debug_info_file(FILE* fp)
168 gc_debug_info info;
170 memset(&info, 0, sizeof info);
171 info.fp = fp;
173 if (gc_ok)
174 GC_gcollect();
175 fprintf(info.fp, "---------- Begin block map ----------\n");
176 GC_apply_to_all_blocks(GC_print_debug_callback, (word)(void*)(&info));
177 //fprintf(fp, "#Total used %d free %d wasted %d\n", info.used, info.free, info.wasted);
178 //fprintf(fp, "#Total blocks %d; %dK bytes\n", info.blocks, info.blocks*4);
179 fprintf(info.fp, "---------- End block map ----------\n");
181 //fprintf(fp, "\n***Free blocks:\n");
182 //GC_print_hblkfreelist();
185 namespace
187 class __attribute__ ((visibility ("hidden"))) GC_enumerator
189 public:
190 GC_enumerator(const char *name);
191 void enumerate();
192 private:
193 FILE* fp;
194 int bytes_fd;
196 void print_address_map();
197 void enumerate_callback(struct hblk *h);
198 static void enumerate_callback_adaptor(struct hblk *h, word dummy);
202 GC_enumerator::GC_enumerator(const char *name)
204 bytes_fd = -1;
205 fp = fopen (name, "w");
206 if (!fp)
208 printf ("GC_enumerator failed to open [%s]\n", name);
209 return;
211 printf ("GC_enumerator saving summary to [%s]\n", name);
213 // open heap file
214 char bytes_name[strlen(name) + 10];
215 sprintf (bytes_name, "%s.bytes", name);
216 bytes_fd = open (bytes_name, O_CREAT|O_TRUNC|O_WRONLY, 0666);
217 if (bytes_fd <= 0)
219 printf ("GC_enumerator failed to open [%s]\n", bytes_name);
220 return;
222 printf ("GC_enumerator saving heap contents to [%s]\n", bytes_name);
226 sample format of /proc/self/maps
228 0063b000-00686000 rw-p 001fb000 03:01 81993 /avtrex/bin/dumppropapp
229 00686000-0072e000 rwxp 00000000 00:00 0
231 These are parsed below as:
232 start -end xxxx xxxxxxxx a:b xxxxxxxxxxxxxxx
237 void
238 GC_enumerator::print_address_map()
240 FILE* fm;
241 char buffer[128];
243 fprintf(fp, "---------- Begin address map ----------\n");
245 fm = fopen("/proc/self/maps", "r");
246 if (fm == NULL)
248 if (0 == strerror_r (errno, buffer, sizeof buffer))
249 fputs (buffer, fp);
251 else
253 while (fgets (buffer, sizeof buffer, fm) != NULL)
255 fputs (buffer, fp);
256 char *dash = strchr(buffer, '-');
257 char *colon = strchr(buffer, ':');
258 if (dash && colon && ((ptrdiff_t)strlen(buffer) > (colon - buffer) + 2))
260 char *endp;
261 unsigned long start = strtoul(buffer, NULL, 16);
262 unsigned long end = strtoul(dash + 1, &endp, 16);
263 unsigned long a = strtoul(colon - 2, NULL, 16);
264 unsigned long b = strtoul(colon + 1, NULL, 16);
265 // If it is an anonymous mapping 00:00 and both readable
266 // and writeable then dump the contents of the mapping
267 // to the bytes file. Each block has a header of three
268 // unsigned longs:
269 // 0 - The number sizeof(unsigned long) to detect endianness and
270 // structure layout.
271 // 1 - The offset in VM.
272 // 2 - The Length in bytes.
273 // Followed by the bytes.
274 if (!a && !b && endp < colon && 'r' == endp[1] && 'w' == endp[2])
276 unsigned long t = sizeof(unsigned long);
277 write(bytes_fd, (void*)&t, sizeof(t));
278 write(bytes_fd, (void*)&start, sizeof(start));
279 t = end - start;
280 write(bytes_fd, (void*)&t, sizeof(t));
281 write(bytes_fd, (void*)start, (end - start));
285 fclose(fm);
287 fprintf(fp, "---------- End address map ----------\n");
288 fflush(fp);
291 void
292 GC_enumerator::enumerate()
294 print_address_map();
295 fprintf(fp, "---------- Begin object map ----------\n");
296 if (gc_ok)
297 GC_gcollect();
298 GC_apply_to_all_blocks(enumerate_callback_adaptor,
299 (word)(void*)(this));
300 fprintf(fp, "---------- End object map ----------\n");
301 fflush(fp);
303 GC_print_debug_info_file(fp);
304 fflush(fp);
305 GC_print_hblkfreelist_file(fp);
306 fflush(fp);
308 close(bytes_fd);
309 fclose(fp);
311 GC_clear_stack(0);
314 void
315 GC_enumerator::enumerate_callback_adaptor(struct hblk *h,
316 word dummy)
318 GC_enumerator* pinfo = (GC_enumerator*)dummy;
319 pinfo->enumerate_callback(h);
322 void
323 GC_enumerator::enumerate_callback(struct hblk *h)
325 hdr * hhdr = HDR(h);
326 size_t bytes = WORDS_TO_BYTES(hhdr->hb_sz);
327 int i;
329 for (i = 0; i == 0 || (i + bytes <= HBLKSIZE); i += bytes)
331 int inUse = mark_bit_from_hdr(hhdr,BYTES_TO_WORDS(i)); // in use
332 char *ptr = (char*)h+i; // address
333 int kind = hhdr->hb_obj_kind; // kind
334 void *klass = 0;
335 void *data = 0;
336 if (kind == GC_gcj_kind
337 || kind == GC_gcj_debug_kind
338 || kind == GC_gcj_debug_kind+1)
340 void* v = *(void **)ptr;
341 if (v)
343 klass = *(void **)v;
344 data = *(void **)(ptr + sizeof(void*));
347 if (inUse)
348 fprintf (fp, "used = %d, ptr = %#lx, size = %zd, kind = %d, "
349 "klass = %#lx, data = %#lx\n",
350 inUse, (unsigned long)ptr, bytes, kind,
351 (unsigned long)klass, (unsigned long)data);
356 * Fill in a char[] with low bytes of the string characters. These
357 * methods may be called while an OutOfMemoryError is being thrown, so
358 * we cannot call nice java methods to get the encoding of the string.
360 static void
361 J2A(::java::lang::String* str, char *dst)
363 jchar * pchars = JvGetStringChars(str);
364 jint len = str->length();
365 int i;
366 for (i=0; i<len; i++)
367 dst[i] = (char)pchars[i];
368 dst[i] = 0;
371 void
372 ::gnu::gcj::util::GCInfo::dump0 (::java::lang::String * name)
374 char n[name->length() + 1];
375 J2A(name, n);
377 char temp[name->length() + 20];
378 sprintf(temp, "%s%03d", n, GC_dump_count++);
379 FILE* fp = fopen(temp, "w");
381 GC_print_debug_info_file(fp);
383 fclose(fp);
386 void
387 ::gnu::gcj::util::GCInfo::enumerate0 (::java::lang::String * name)
389 char n[name->length() + 1];
390 J2A(name, n);
391 char temp[name->length() + 20];
392 sprintf(temp, "%s%03d", n, GC_dump_count++);
394 GC_enumerator x(temp);
395 x.enumerate();
398 static char *oomDumpName = NULL;
400 static void *
401 nomem_handler(size_t size)
403 if (oomDumpName)
405 char temp[strlen(oomDumpName) + 20];
406 sprintf(temp, "%s%03d", temp, GC_dump_count++);
407 printf("nomem_handler(%zd) called\n", size);
408 gc_ok--;
409 GC_enumerator x(temp);
410 x.enumerate();
411 gc_ok++;
413 return (void*)0;
416 void
417 ::gnu::gcj::util::GCInfo::setOOMDump0 (::java::lang::String * name)
419 char *oldName = oomDumpName;
420 oomDumpName = NULL;
421 free (oldName);
423 if (NULL == name)
424 return;
426 char *n = (char *)malloc(name->length() + 1);
428 J2A(name, n);
429 oomDumpName = n;
430 GC_oom_fn = nomem_handler;
433 #else // HAVE_PROC_SELF_MAPS
435 void
436 ::gnu::gcj::util::GCInfo::dump0 (::java::lang::String * name)
438 // Do nothing if dumping not supported.
441 void
442 ::gnu::gcj::util::GCInfo::enumerate0 (::java::lang::String * name)
444 // Do nothing if dumping not supported.
447 void
448 ::gnu::gcj::util::GCInfo::setOOMDump0 (::java::lang::String * name)
450 // Do nothing if dumping not supported.
453 #endif // HAVE_PROC_SELF_MAPS