1 #ifndef INCLUDE_HEAP_JEMALLOC_STD_C
2 #define INCLUDE_HEAP_JEMALLOC_STD_C
3 #define HEAP32 1
4 #include "linux_heap_jemalloc.c"
5 #undef HEAP32
6 #endif
7 
8 #undef GH
9 #undef GHT
10 #undef GHT_MAX
11 #undef PFMTx
12 
13 // FIXME: It should be detected at runtime, not during the compilation stage
14 #if HEAP32
15 #define GH(x) x##_32
16 #define GHT ut32
17 #define GHT_MAX UT32_MAX
18 #define PFMTx PFMT32x
19 #else
20 #define GH(x) x##_64
21 #define GHT ut64
22 #define GHT_MAX UT64_MAX
23 #define PFMTx PFMT64x
24 #endif
25 
26 #if __linux__
27 // TODO: provide proper api in cbin to resolve symbols and load libraries from debug maps and such
28 // this is, provide a programmatic api for the slow dmi command
GH(je_get_va_symbol)29 static GHT GH(je_get_va_symbol)(const char *path, const char *symname) {
30 	RListIter *iter;
31 	RBinSymbol *s;
32 	RCore *core = r_core_new ();
33 	GHT vaddr = 0LL;
34 
35 	if (!core) {
36 		return GHT_MAX;
37 	}
38 
39 	RBinOptions opt;
40 	r_bin_options_init (&opt, -1, 0, 0, false);
41 	if (r_bin_open (core->bin, path, &opt)) {
42 		RList *syms = r_bin_get_symbols (core->bin);
43 		if (!syms) {
44 			r_core_free (core);
45 			return GHT_MAX;
46 		}
47 		r_list_foreach (syms, iter, s) {
48 			if (!strcmp(s->name, symname)) {
49 				vaddr = s->vaddr;
50 				break;
51 			}
52 		}
53 	}
54 	r_core_free (core);
55 	return vaddr;
56 }
57 
GH(je_matched)58 static int GH(je_matched)(const char *ptr, const char *str) {
59         int ret = strncmp (ptr, str, strlen (str) - 1);
60 	return !ret;
61 }
62 #endif
63 
GH(r_resolve_jemalloc)64 static bool GH(r_resolve_jemalloc)(RCore *core, char *symname, ut64 *symbol) {
65 	RListIter *iter;
66 	RDebugMap *map;
67 	const char *jemalloc_ver_end = NULL;
68 	ut64 jemalloc_addr = UT64_MAX;
69 
70 	if (!core || !core->dbg || !core->dbg->maps){
71 		return false;
72 	}
73 	r_debug_map_sync (core->dbg);
74 	r_list_foreach (core->dbg->maps, iter, map) {
75 		if (strstr (map->name, "libjemalloc.")) {
76 			jemalloc_addr = map->addr;
77 			jemalloc_ver_end = map->name;
78 			break;
79 		}
80 	}
81 	if (!jemalloc_ver_end) {
82 		eprintf ("Warning: Is jemalloc mapped in memory? (see dm command)\n");
83 		return false;
84 	}
85 #if __linux__
86 	bool is_debug_file = GH(je_matched)(jemalloc_ver_end, "/usr/local/lib");
87 
88 	if (!is_debug_file) {
89 		eprintf ("Warning: Is libjemalloc.so.2 in /usr/local/lib path?\n");
90 		return false;
91 	}
92 	char *path = r_str_newf ("%s", jemalloc_ver_end);
93 	if (r_file_exists (path)) {
94 		ut64 vaddr = GH(je_get_va_symbol)(path, symname);
95 		if (jemalloc_addr != GHT_MAX && vaddr != 0) {
96 			*symbol = jemalloc_addr + vaddr;
97 			free (path);
98 			return true;
99 		}
100 	}
101 	free (path);
102 	return false;
103 #else
104 	eprintf ("[*] Resolving %s from libjemalloc.2... ", symname);
105 	// this is quite sloooow, we must optimize dmi
106 	char *va = r_core_cmd_strf (core, "dmi libjemalloc.2 %s$~[1]", symname);
107 	ut64 n = r_num_get (NULL, va);
108 	if (n && n != UT64_MAX) {
109 		*symbol = n;
110 		eprintf ("0x%08"PFMT64x"\n", n);
111 	} else {
112 		eprintf ("NOT FOUND\n");
113 	}
114 	free (va);
115 	return true;
116 #endif
117 }
118 
GH(jemalloc_get_chunks)119 static void GH(jemalloc_get_chunks)(RCore *core, const char *input) {
120 	ut64 cnksz;
121 	RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
122 
123 	if (!GH(r_resolve_jemalloc)(core, "je_chunksize", &cnksz)) {
124 		eprintf ("Fail at read symbol je_chunksize\n");
125 		return;
126 	}
127 	r_io_read_at (core->io, cnksz, (ut8 *)&cnksz, sizeof (GHT));
128 
129 	switch (input[0]) {
130 	case '\0':
131 		eprintf ("need an arena_t to associate chunks");
132 		break;
133         case ' ':
134         	{
135 			GHT arena = GHT_MAX;
136 			arena_t *ar = R_NEW0 (arena_t);
137 			extent_node_t *node = R_NEW0 (extent_node_t), *head = R_NEW0 (extent_node_t);
138 			input += 1;
139 			arena = r_num_math (core->num, input);
140 
141 			if (arena) {
142 				r_io_read_at (core->io, arena, (ut8 *)ar, sizeof (arena_t));
143 				r_io_read_at (core->io, (GHT)(size_t)ar->achunks.qlh_first, (ut8 *)head, sizeof (extent_node_t));
144 				if (head->en_addr) {
145 					PRINT_YA ("   Chunk - start: ");
146 					PRINTF_BA ("0x%08"PFMT64x, (ut64)(size_t)head->en_addr);
147 					PRINT_YA (", end: ");
148 					PRINTF_BA ("0x%08"PFMT64x, (ut64)(size_t)((char *)head->en_addr + cnksz));
149 					PRINT_YA (", size: ");
150 					PRINTF_BA ("0x%08"PFMT64x"\n", (ut64)cnksz);
151 					r_io_read_at (core->io, (ut64)(size_t)head->ql_link.qre_next, (ut8 *)node, sizeof (extent_node_t));
152 					while (node && node->en_addr != head->en_addr) {
153 						PRINT_YA ("   Chunk - start: ");
154 						PRINTF_BA ("0x%08"PFMT64x, (ut64)(size_t)node->en_addr);
155 						PRINT_YA (", end: ");
156 						PRINTF_BA ("0x%"PFMT64x, (ut64)(size_t)((char *)node->en_addr + cnksz));
157 						PRINT_YA (", size: ");
158 						PRINTF_BA ("0x%08"PFMT64x"\n", cnksz);
159 						r_io_read_at (core->io, (ut64)(size_t)node->ql_link.qre_next, (ut8 *)node, sizeof (extent_node_t));
160 					}
161 				}
162 			}
163 			free (ar);
164 			free (head);
165 			free (node);
166 		break;
167         	}
168         case '*':
169 		{
170 			int i = 0;
171 			ut64 sym;
172 			GHT arenas = GHT_MAX, arena = GHT_MAX;
173 			arena_t *ar = R_NEW0 (arena_t);
174 			extent_node_t *node = R_NEW0 (extent_node_t);
175 			extent_node_t *head = R_NEW0 (extent_node_t);
176 
177 			if (!node || !head) {
178 				eprintf ("Error calling calloc\n");
179 				free (ar);
180 				free (node);
181 				free (head);
182 				return;
183 			}
184 
185 			if (GH(r_resolve_jemalloc) (core, "je_arenas", &sym)) {
186 				r_io_read_at (core->io, sym, (ut8 *)&arenas, sizeof (GHT));
187 				for (;;) {
188 					r_io_read_at (core->io, arenas + i * sizeof (GHT), (ut8 *)&arena, sizeof (GHT));
189 					if (!arena) {
190 						break;
191 					}
192 					PRINTF_GA ("arenas[%d]: @ 0x%"PFMTx" { \n", i++, (GHT)arena);
193 					r_io_read_at (core->io, arena, (ut8 *)ar, sizeof (arena_t));
194 					r_io_read_at (core->io, (GHT)(size_t)ar->achunks.qlh_first, (ut8 *)head, sizeof (extent_node_t));
195 					if (head->en_addr != 0) {
196 						PRINT_YA ("   Chunk - start: ");
197 						PRINTF_BA ("0x%08"PFMT64x, (ut64)(size_t)head->en_addr);
198 						PRINT_YA (", end: ");
199 						PRINTF_BA ("0x%"PFMT64x, (ut64)(size_t)((char *)head->en_addr + cnksz));
200 						PRINT_YA (", size: ");
201 						PRINTF_BA ("0x%08"PFMT64x"\n", (ut64)cnksz);
202 						ut64 addr = (ut64) (size_t)head->ql_link.qre_next;
203 						r_io_read_at (core->io, addr, (ut8 *)node, sizeof (extent_node_t));
204 						while (node && head && node->en_addr != head->en_addr) {
205 							PRINT_YA ("   Chunk - start: ");
206 							PRINTF_BA ("0x%08"PFMT64x, (ut64)(size_t)node->en_addr);
207 							PRINT_YA (", end: ");
208 							PRINTF_BA ("0x%"PFMT64x, (ut64)(size_t)((char *)node->en_addr + cnksz));
209 							PRINT_YA (", size: ");
210 							PRINTF_BA ("0x%"PFMT64x"\n", cnksz);
211 							r_io_read_at (core->io, (GHT)(size_t)node->ql_link.qre_next, (ut8 *)node, sizeof (extent_node_t));
212 						}
213 					}
214 					PRINT_GA ("}\n");
215 				}
216 			}
217 			free (ar);
218 			free (head);
219 			free (node);
220 		}
221 		break;
222 	}
223 }
224 
GH(jemalloc_print_narenas)225 static void GH(jemalloc_print_narenas)(RCore *core, const char *input) {
226 	ut64 symaddr;
227 	ut64 arenas;
228 	GHT arena = GHT_MAX;
229 	arena_t *ar = R_NEW0 (arena_t);
230 	if (!ar) {
231 		return;
232 	}
233 	arena_stats_t *stats = R_NEW0 (arena_stats_t);
234 	if (!stats) {
235 		free (ar);
236 		return;
237 	}
238 	int i = 0;
239 	GHT narenas = 0;
240 	RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
241 
242 	switch (input[0]) {
243 	case '\0':
244 		if (GH(r_resolve_jemalloc)(core, "narenas_total", &symaddr)) {
245 			r_io_read_at (core->io, symaddr, (ut8 *)&narenas, sizeof (GHT));
246 			PRINTF_GA ("narenas : %"PFMT64d"\n", (ut64)narenas);
247 		}
248 		if (narenas == 0) {
249 			eprintf ("No arenas allocated.\n");
250 			free (stats);
251 			free (ar);
252 			return;
253 		}
254 		if (narenas == GHT_MAX) {
255 			eprintf ("Cannot find narenas_total\n");
256 			free (stats);
257 			free (ar);
258 			return;
259 		}
260 
261 		if (GH(r_resolve_jemalloc)(core, "je_arenas", &arenas)) {
262 			r_io_read_at (core->io, arenas, (ut8 *)&arenas, sizeof (GHT));
263 			PRINTF_GA ("arenas[%"PFMT64d"] @ 0x%"PFMT64x" {\n", (ut64)narenas, (ut64)arenas);
264 			for (i = 0; i < narenas; i++) {
265 				ut64 at = arenas + (i * sizeof (GHT));
266 				r_io_read_at (core->io, at, (ut8 *)&arena, sizeof (GHT));
267 				if (!arena) {
268 					PRINTF_YA ("  arenas[%d]: (empty)\n", i);
269 					continue;
270 				}
271 				PRINTF_YA ("  arenas[%d]: ", i);
272 				PRINTF_BA ("@ 0x%"PFMT64x"\n", at);
273 			}
274 		}
275 		PRINT_GA ("}\n");
276 		break;
277 	case ' ':
278 		arena = r_num_math (core->num, input + 1);
279 		r_io_read_at (core->io, (GHT)arena, (ut8 *)ar, sizeof (arena_t));
280 
281 		PRINT_GA ("struct arena_s {\n");
282 #define OO(x) (ut64)(arena + r_offsetof (arena_t, x))
283 		PRINTF_BA ("  ind = 0x%x\n", ar->ind);
284 		PRINTF_BA ("  nthreads: application allocation = 0x%"PFMT64x"\n", (ut64)ar->nthreads[0]);
285 		PRINTF_BA ("  nthreads: internal metadata allocation = 0x%"PFMT64x"\n", (ut64)ar->nthreads[1]);
286 		PRINTF_BA ("  lock = 0x%"PFMT64x"\n", OO(lock));
287 		PRINTF_BA ("  stats = 0x%"PFMT64x"\n", OO(stats));
288 		PRINTF_BA ("  tcache_ql = 0x%"PFMT64x"\n", OO(tcache_ql));
289 		PRINTF_BA ("  prof_accumbytes = 0x%"PFMT64x"x\n", (ut64)ar->prof_accumbytes);
290 		PRINTF_BA ("  offset_state = 0x%"PFMT64x"\n", (ut64)ar->offset_state);
291 		PRINTF_BA ("  dss_prec_t = 0x%"PFMT64x"\n",OO(dss_prec));
292 		PRINTF_BA ("  achunks = 0x%"PFMT64x"\n", OO(achunks));
293 		PRINTF_BA ("  extent_sn_next = 0x%"PFMT64x"\n", (ut64)(size_t)ar->extent_sn_next);
294 		PRINTF_BA ("  spare = 0x%"PFMT64x"\n", (ut64)(size_t)ar->spare);
295 		PRINTF_BA ("  lg_dirty_mult = 0x%"PFMT64x"\n", (ut64)(ssize_t)ar->lg_dirty_mult);
296 		PRINTF_BA ("  purging = %s\n", r_str_bool (ar->purging));
297 		PRINTF_BA ("  nactive = 0x%"PFMT64x"\n", (ut64)(size_t)ar->nactive);
298 		PRINTF_BA ("  ndirty = 0x%"PFMT64x"\n", (ut64)(size_t)ar->ndirty);
299 
300 		PRINTF_BA ("  runs_dirty = 0x%"PFMT64x"\n", OO(runs_dirty));
301 		PRINTF_BA ("  chunks_cache = 0x%"PFMT64x"\n", OO(chunks_cache));
302 		PRINTF_BA ("  huge = 0x%"PFMT64x"\n", OO(huge));
303 		PRINTF_BA ("  huge_mtx = 0x%"PFMT64x"\n", OO(huge_mtx));
304 
305 		PRINTF_BA ("  chunks_szsnad_cached = 0x%"PFMT64x"\n", OO(chunks_szsnad_cached));
306 		PRINTF_BA ("  chunks_ad_cached = 0x%"PFMT64x"\n", OO(chunks_ad_cached));
307 		PRINTF_BA ("  chunks_szsnad_retained = 0x%"PFMT64x"\n", OO(chunks_szsnad_retained));
308 		PRINTF_BA ("  chunks_ad_cached = 0x%"PFMT64x"\n", OO(chunks_ad_retained));
309 
310 		PRINTF_BA ("  chunks_mtx = 0x%"PFMT64x"\n", OO(chunks_mtx));
311 		PRINTF_BA ("  node_cache = 0x%"PFMT64x"\n", OO(node_cache));
312 		PRINTF_BA ("  node_cache_mtx = 0x%"PFMT64x"\n", OO(node_cache_mtx));
313 		PRINTF_BA ("  chunks_hooks = 0x%"PFMT64x"\n", OO(chunk_hooks));
314 		PRINTF_BA ("  bins = %d 0x%"PFMT64x"\n", JM_NBINS, OO(bins));
315 		PRINTF_BA ("  runs_avail = %d 0x%"PFMT64x"\n", NPSIZES, OO(runs_avail));
316 		PRINT_GA ("}\n");
317 		break;
318 	}
319 	free (ar);
320 	free (stats);
321 }
322 
GH(jemalloc_get_bins)323 static void GH(jemalloc_get_bins)(RCore *core, const char *input) {
324 	int i = 0, j;
325 	ut64 bin_info;
326 	ut64 arenas;
327 	GHT arena = GHT_MAX; //, bin = GHT_MAX;
328 	arena_t *ar = NULL;
329 	arena_bin_info_t *b = NULL;
330 	RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
331 
332 	switch (input[0]) {
333 	case ' ':
334 		ar = R_NEW0 (arena_t);
335 		if (!ar) {
336 			break;
337 		}
338 		b = R_NEW0 (arena_bin_info_t);
339 		if (!b) {
340 			break;
341 		}
342 		if (!GH(r_resolve_jemalloc)(core, "je_arena_bin_info", &bin_info)) {
343 			eprintf ("Error resolving je_arena_bin_info\n");
344 			R_FREE (b);
345 			break;
346 		}
347 		if (GH(r_resolve_jemalloc)(core, "je_arenas", &arenas)) {
348 			r_io_read_at (core->io, arenas, (ut8 *)&arenas, sizeof (GHT));
349 			PRINTF_GA ("arenas @ 0x%"PFMTx" {\n", (GHT)arenas);
350 			for (;;) {
351 				r_io_read_at (core->io, arenas + i * sizeof (GHT), (ut8 *)&arena, sizeof (GHT));
352 				if (!arena) {
353 					R_FREE (b);
354 					break;
355 				}
356 				PRINTF_YA ("   arenas[%d]: ", i++);
357 				PRINTF_BA ("@ 0x%"PFMTx, (GHT)arena);
358 				PRINT_YA (" {\n");
359 				r_io_read_at (core->io, arena, (ut8 *)ar, sizeof (arena_t));
360 				for (j = 0; j < JM_NBINS; j++) {
361 					r_io_read_at (core->io, (GHT)(bin_info + j * sizeof (arena_bin_info_t)),
362 						(ut8*)b, sizeof (arena_bin_info_t));
363 					PRINT_YA ("    {\n");
364 					PRINT_YA ("       regsize : ");
365 					PRINTF_BA ("0x%zx\n", b->reg_size);
366 					PRINT_YA ("       redzone size ");
367 					PRINTF_BA ("0x%zx\n", b->redzone_size);
368 					PRINT_YA ("       reg_interval : ");
369 					PRINTF_BA ("0x%zx\n", b->reg_interval);
370 					PRINT_YA ("       run_size : ");
371 					PRINTF_BA ("0x%zx\n", b->run_size);
372 					PRINT_YA ("       nregs : ");
373 					PRINTF_BA ("0x%x\n", b->nregs);
374 					// FIXME: It's a structure of bitmap_info_t
375 					//PRINT_YA ("       bitmap_info : ");
376 					//PRINTF_BA ("0x%"PFMT64x"\n", b->bitmap_info);
377 					PRINT_YA ("       reg0_offset : ");
378 					PRINTF_BA ("0x%"PFMT64x"\n\n", (ut64)b->reg0_offset);
379 					// FIXME: It's a structure of malloc_mutex_t
380 					//PRINTF_YA ("       bins[%d]->lock ", j);
381 					//PRINTF_BA ("= 0x%"PFMT64x"\n", ar->bins[j].lock);
382 					// FIXME: It's a structure of arena_run_t*
383 					//PRINTF_YA ("       bins[%d]->runcur ", j);
384 					//PRINTF_BA ("@ 0x%"PFMT64x"\n", ar->bins[j].runcur);
385 					// FIXME: It's a structure of arena_run_heap_t*
386 					//PRINTF_YA ("       bins[%d]->runs ", j);
387 					//PRINTF_BA ("@ 0x%"PFMTx"\n", ar->bins[j].runs);
388 					// FIXME: It's a structure of malloc_bin_stats_t
389 					//PRINTF_YA ("       bins[%d]->stats ", j);
390 					//PRINTF_BA ("= 0x%"PFMTx"\n", ar->bins[j].stats);
391 					PRINT_YA ("    }\n");
392 				}
393 				PRINT_YA ("  }\n");
394 			}
395 		}
396 		PRINT_GA ("}\n");
397 		break;
398 	}
399 	free (ar);
400 	free (b);
401 }
402 
403 #if 0
404 static void GH(jemalloc_get_runs)(RCore *core, const char *input) {
405 	switch (input[0]) {
406 	case ' ':
407 		{
408 			int pageind;
409 			ut64 npages, chunksize_mask, map_bias, map_misc_offset, chunk, mapbits;;
410 			arena_chunk_t *c = R_NEW0 (arena_chunk_t);
411 
412 			if (!c) {
413 				eprintf ("Error calling calloc\n");
414 				return;
415 			}
416 
417 			input += 1;
418 			chunk = r_num_math (core->num, input);
419 
420 			if (!GH(r_resolve_jemalloc)(core, "je_chunk_npages", &npages)) {
421 				eprintf ("Error resolving je_chunk_npages\n");
422 				return;
423 			}
424 			if (!GH(r_resolve_jemalloc)(core, "je_chunksize_mask", &chunksize_mask)) {
425 				eprintf ("Error resolving je_chunksize_mask\n");
426 				return;
427 			}
428 			if (!GH(r_resolve_jemalloc)(core, "je_map_bias", &map_bias)) {
429 				eprintf ("Error resolving je_map_bias");
430 				return;
431 			}
432 			if (!GH(r_resolve_jemalloc)(core, "je_map_misc_offset", &map_misc_offset)) {
433 				eprintf ("Error resolving je_map_misc_offset");
434 				return;
435 			}
436 
437 			r_io_read_at (core->io, npages, (ut8*)&npages, sizeof (GHT));
438 			r_io_read_at (core->io, chunksize_mask, (ut8*)&chunksize_mask, sizeof (GHT));
439 			r_io_read_at (core->io, map_bias, (ut8*)&map_bias, sizeof (GHT));
440 			r_io_read_at (core->io, map_misc_offset, (ut8*)&map_misc_offset, sizeof (GHT));
441 
442 			eprintf ("map_misc_offset 0x%08"PFMT64x"\n", (ut64)map_misc_offset);
443 
444 			r_io_read_at (core->io, chunk, (ut8 *)c, sizeof (arena_chunk_t));
445 			mapbits = *(GHT *)&c->map_bits;
446 			eprintf ("map_bits: 0x%08"PFMT64x"\n", (ut64)mapbits);
447 
448 			uint32_t offset = r_offsetof (arena_chunk_t, map_bits);
449 
450 			arena_chunk_map_bits_t *dwords = (void *)calloc (sizeof (arena_chunk_map_bits_t), npages);
451 			r_io_read_at (core->io, chunk + offset, (ut8*)dwords, sizeof (arena_chunk_map_bits_t) * npages);
452 			eprintf ("map_bits @ 0x%08"PFMT64x"\n", (ut64)(chunk + offset));
453 
454 			arena_run_t *r = R_NEW0 (arena_run_t);
455 			if (!r) {
456 				eprintf ("Error calling calloc\n");
457 				return;
458 			}
459 			for (pageind = map_bias; pageind < npages; pageind++) {
460 				arena_chunk_map_bits_t mapelm = dwords[pageind-map_bias];
461 				if (mapelm.bits & CHUNK_MAP_ALLOCATED) {
462 					// ut64 elm = ((arena_chunk_map_misc_t *)((uintptr_t)chunk + (uintptr_t)map_misc_offset) + pageind-map_bias);
463 					ut64 elm = chunk + map_misc_offset + pageind-map_bias;
464 					eprintf ("\nelm: 0x%"PFMT64x"\n", elm);
465 					arena_chunk_map_misc_t *m = R_NEW0 (arena_chunk_map_misc_t);
466 					if (m) {
467 						ut64 run = elm + r_offsetof (arena_chunk_map_misc_t, run);
468 						r_io_read_at (core->io, elm, (ut8*)m, sizeof (arena_chunk_map_misc_t));
469 						eprintf ("Small run @ 0x%08"PFMT64x"\n", (ut64)elm);
470 						r_io_read_at (core->io, run, (ut8*)r, sizeof (arena_run_t));
471 						eprintf ("binind: 0x%08"PFMT64x"\n", (ut64)r->binind);
472 						eprintf ("nfree: 0x%08"PFMT64x"\n", (ut64)r->nfree);
473 						eprintf ("bitmap: 0x%08"PFMT64x"\n\n", (ut64)*(GHT*)r->bitmap);
474 						free (m);
475 					}
476 				} else if (mapelm.bits & CHUNK_MAP_LARGE) {
477 					ut64 run = (ut64) (size_t) chunk + (pageind << LG_PAGE);
478 					eprintf ("Large run @ 0x%08"PFMT64x"\n", run);
479 					r_io_read_at (core->io, run, (ut8*)r, sizeof (arena_run_t));
480 					eprintf ("binind: 0x%08"PFMT64x"\n", (ut64)r->binind);
481 					eprintf ("nfree: 0x%08"PFMT64x"\n", (ut64)r->nfree);
482 					eprintf ("bitmap: 0x%08"PFMT64x"\n\n", (ut64)*(GHT*)r->bitmap);
483 				}
484 			}
485 			free (c);
486 			free (r);
487          	}
488 	break;
489 	}
490 }
491 #endif
492 
GH(cmd_dbg_map_jemalloc)493 static int GH(cmd_dbg_map_jemalloc)(RCore *core, const char *input) {
494 	const char *help_msg[] = {
495 		"Usage:", "dmh", " # Memory map heap",
496 		"dmha", "[arena_t]", "show all arenas created, or print arena_t structure for given arena",
497 		"dmhb", "[arena_t]", "show all bins created for given arena",
498 		"dmhc", "*|[arena_t]", "show all chunks created in all arenas, or show all chunks created for a given arena_t instance",
499 		// "dmhr", "[arena_chunk_t]", "print all runs created for a given arena_chunk_t instance",
500 		"dmh?", "", "Show map heap help", NULL
501 	};
502 
503 	switch (input[0]) {
504 	case '?':
505 		r_core_cmd_help (core, help_msg);
506 		break;
507 	case 'a': //dmha
508 		GH(jemalloc_print_narenas) (core, input + 1);
509 		break;
510 	case 'b': //dmhb
511 		GH(jemalloc_get_bins) (core, input + 1);
512 		break;
513 	case 'c': //dmhc
514 		GH(jemalloc_get_chunks) (core, input + 1);
515 		break;
516 	/*
517 	case 'r': //dmhr
518 		GH(jemalloc_get_runs) (core, input + 1);
519 		break;
520 	*/
521 	}
522 	return 0;
523 }
524 
525