1 /* Block-relocating memory allocator.
2 Copyright (C) 1990 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* This package works by allocating blocks from a zone of memory
21 above that used by malloc (). When malloc needs more space that
22 would enter our zone, we relocate blocks upward. The bottom of
23 our zone is kept in the variable `virtual_break_value'. The top
24 of our zone is indicated by `real_break_value'.
26 As blocks are freed, a free list is maintained and we attempt
27 to satisfy further requests for space using a first-fit policy.
28 If there are holes, but none fit, memory is compacted and a new
29 block is obtained at the top of the zone.
31 NOTE that our blocks are always rounded to page boundaries. */
36 Once this is stable, I can speed things up by intially leaving a large
37 gap between real_break_value and true_break_value, or maybe making
38 a large hole before the first block.
40 If we also kept track of size_wanted, we could gain some
41 extra space upon compactification.
43 Perhaps we should just note a hole when malloc does doing sbrk(-n)?
45 Relocating downward upon freeing the first block would simplify
48 When r_alloc places a block in a hole, we could easily check if there's
49 much more than required, and leave a hole.
52 #include "mem_limits.h"
54 static POINTER
r_alloc_sbrk ();
55 static POINTER
sbrk ();
56 static POINTER
brk ();
58 /* Variable `malloc' uses for the function which gets more space
60 extern POINTER (*__morecore
) ();
62 /* List of variables which point into the associated data block. */
66 struct other_pointer
*next
;
69 /* List describing all the user's pointers to relocatable blocks. */
70 typedef struct rel_pointers
72 struct rel_pointers
*next
;
73 struct rel_pointers
*prev
;
74 struct other_pointer
*others
; /* Other variables which use this block. */
75 POINTER
*location
; /* Location of the block's pointer. */
76 POINTER block
; /* Address of the actual data. */
77 int size
; /* The size of the block. */
78 } relocatable_pointer
;
80 #define REL_NIL ((struct rel_pointers *) 0)
82 static relocatable_pointer
*pointer_list
;
83 static relocatable_pointer
*last_pointer
;
87 /* Vector of available holes among allocated blocks. This can include
88 a hole at the beginning of the list, but never the end. */
95 static hole_descriptor r_alloc_holes
[MAX_HOLES
];
97 /* Number of holes currently available. */
100 /* The process break value (i.e., curbrk) */
101 static POINTER real_break_value
;
103 /* The REAL (i.e., page aligned) break value. */
104 static POINTER true_break_value
;
106 /* Address of start of data space in use by relocatable blocks.
107 This is what `malloc' thinks is the process break value. */
108 static POINTER virtual_break_value
;
110 /* Nonzero if we have told `malloc' to start using `r_alloc_sbrk'
111 instead of calling `sbrk' directly. */
114 #define PAGE (getpagesize ())
115 #define ALIGNED(addr) (((unsigned int) (addr) & (PAGE - 1)) == 0)
116 #define ROUNDUP(size) (((unsigned int) (size) + PAGE) & ~(PAGE - 1))
119 Level number of warnings already issued.
120 0 -- no warnings issued.
121 1 -- 75% warning already issued.
122 2 -- 85% warning already issued.
124 static int warnlevel
;
126 /* Function to call to issue a warning;
127 0 means don't issue them. */
128 static void (*warnfunction
) ();
130 /* Call this to start things off. It determines the current process
131 break value, as well as the `true' break value--because the system
132 allocates memory in page increments, if the break value is not page
133 aligned it means that space up to the next page boundary is actually
137 malloc_init (start
, warn_func
)
139 void (*warn_func
) ();
142 __morecore
= r_alloc_sbrk
;
144 virtual_break_value
= real_break_value
= sbrk (0);
145 if (ALIGNED (real_break_value
))
146 true_break_value
= real_break_value
;
148 true_break_value
= (POINTER
) ROUNDUP (real_break_value
);
151 data_space_start
= start
;
154 warnfunction
= warn_func
;
159 /* Get more space for us to use. Return a pointer to SIZE more
160 bytes of space. SIZE is internally rounded up to a page boundary,
161 and requests for integral pages prefetch an extra page. */
164 get_more_space (size
)
167 unsigned int margin
= true_break_value
- real_break_value
;
169 POINTER old_break
= real_break_value
;
172 return real_break_value
;
176 real_break_value
+= size
;
180 get
= ROUNDUP (size
- margin
);
181 if (sbrk (get
) < (POINTER
) 0)
184 true_break_value
+= get
;
185 real_break_value
= (old_break
+ size
);
190 /* Relinquish size bytes of space to the system. Space is only returned
191 in page increments. If successful, return real_break_value. */
197 unsigned int margin
= (true_break_value
- real_break_value
) + size
;
198 unsigned int to_return
= (margin
/ PAGE
) * PAGE
;
199 unsigned new_margin
= margin
% PAGE
;
201 true_break_value
-= to_return
;
202 if (! brk (true_break_value
))
205 real_break_value
= true_break_value
- new_margin
;
206 return real_break_value
;
209 /* Record a new hole in memory beginning at ADDRESS of size SIZE.
210 Holes are ordered by location. Adjacent holes are merged.
211 Holes are zero filled before being noted. */
214 note_hole (address
, size
)
218 register int this_hole
= holes
- 1; /* Start at the last hole. */
219 register POINTER end
= address
+ size
; /* End of the hole. */
224 /* Find the hole which should precede this new one. */
225 while (this_hole
>= 0 && r_alloc_holes
[this_hole
].address
> address
)
228 /* Can we merge with preceding? */
230 && r_alloc_holes
[this_hole
].address
+ r_alloc_holes
[this_hole
].size
233 r_alloc_holes
[this_hole
].size
+= size
;
235 if (this_hole
== holes
- 1)
238 /* Can we also merge with following? */
239 if (end
== r_alloc_holes
[this_hole
+ 1].address
)
241 r_alloc_holes
[this_hole
].size
242 += r_alloc_holes
[this_hole
+ 1].size
;
244 for (i
= this_hole
+ 1; i
< holes
- 1; i
++)
245 r_alloc_holes
[i
] = r_alloc_holes
[i
+ 1];
252 if (this_hole
< holes
- 1) /* there are following holes */
254 register int next_hole
= this_hole
+ 1;
256 /* Can we merge with the next hole? */
257 if (end
== r_alloc_holes
[next_hole
].address
)
259 r_alloc_holes
[next_hole
].address
= address
;
260 r_alloc_holes
[next_hole
].size
+= size
;
264 /* Can't merge, so insert. */
265 for (i
= holes
; i
> next_hole
; i
--)
266 r_alloc_holes
[i
] = r_alloc_holes
[i
- 1];
267 r_alloc_holes
[next_hole
].address
= address
;
268 r_alloc_holes
[next_hole
].size
= size
;
273 else /* Simply add this hole at the end. */
275 r_alloc_holes
[holes
].address
= address
;
276 r_alloc_holes
[holes
].size
= size
;
284 else /* Make the first hole. */
287 r_alloc_holes
[0].address
= address
;
288 r_alloc_holes
[0].size
= size
;
292 /* Mark hole HOLE as no longer available by re-organizing the vector.
293 HOLE is the Nth hole, beginning with 0. This doesn *not* affect memory
302 for (i
= hole
; i
< holes
- 1; i
++)
303 r_alloc_holes
[i
] = r_alloc_holes
[i
+ 1];
308 /* Insert a newly allocated pointer, NEW_PTR, at the appropriate
309 place in our list. */
313 register relocatable_pointer
*new_ptr
;
315 register relocatable_pointer
*this_ptr
= pointer_list
;
317 while (this_ptr
!= REL_NIL
&& this_ptr
->block
< new_ptr
->block
)
318 this_ptr
= this_ptr
->next
;
320 if (this_ptr
== REL_NIL
)
321 abort (); /* Use `attach' for appending. */
323 new_ptr
->next
= this_ptr
;
324 new_ptr
->prev
= this_ptr
->prev
;
325 this_ptr
->prev
= new_ptr
;
327 if (this_ptr
== pointer_list
)
328 pointer_list
= new_ptr
;
330 new_ptr
->prev
->next
= new_ptr
;
333 /* Attach a newly allocated pointer, NEW_PTR, to the end of our list. */
337 relocatable_pointer
*new_ptr
;
339 if (pointer_list
== REL_NIL
)
341 pointer_list
= new_ptr
;
342 last_pointer
= new_ptr
;
343 new_ptr
->next
= new_ptr
->prev
= REL_NIL
;
347 new_ptr
->next
= REL_NIL
;
348 last_pointer
->next
= new_ptr
;
349 new_ptr
->prev
= last_pointer
;
350 last_pointer
= new_ptr
;
354 static relocatable_pointer
*
358 register relocatable_pointer
*this_ptr
= pointer_list
;
360 while (this_ptr
!= REL_NIL
&& this_ptr
->block
!= block
)
361 this_ptr
= this_ptr
->next
;
366 static relocatable_pointer
*
367 find_location (address
)
370 register relocatable_pointer
*this_ptr
= pointer_list
;
372 while (this_ptr
!= REL_NIL
&& this_ptr
->location
!= address
)
374 struct other_pointer
*op
= this_ptr
->others
;
376 while (op
!= (struct other_pointer
*) 0)
378 if (op
->location
== address
)
384 this_ptr
= this_ptr
->next
;
391 static void compactify ();
393 /* Record of last new block allocated. */
394 static relocatable_pointer
*last_record
;
396 /* Allocate a block of size SIZE and record that PTR points to it.
397 If successful, store the address of the block in *PTR and return
398 it as well. Otherwise return NULL. */
405 register relocatable_pointer
*record
406 = (relocatable_pointer
*) malloc (sizeof (relocatable_pointer
));
407 register POINTER block
;
409 /* If we can't get space to record this pointer, fail. */
413 last_record
= record
;
415 if (holes
) /* Search for a hole the right size. */
419 for (i
= 0; i
< holes
; i
++)
420 if (r_alloc_holes
[i
].size
>= size
)
422 record
->location
= ptr
;
423 record
->others
= (struct other_pointer
*) 0;
424 record
->block
= *ptr
= r_alloc_holes
[i
].address
;
425 if (r_alloc_holes
[i
].size
> ROUNDUP (size
))
427 record
->size
= ROUNDUP (size
);
428 r_alloc_holes
[i
].size
-= ROUNDUP (size
);
429 r_alloc_holes
[i
].address
+= ROUNDUP (size
);
433 record
->size
= r_alloc_holes
[i
].size
;
438 *ptr
= record
->block
;
439 return record
->block
;
442 /* No holes large enough. Burp. */
446 /* No holes: grow the process. */
447 block
= get_more_space (size
);
454 /* Return the address of the block. */
457 /* Record and append this pointer to our list. */
458 record
->location
= ptr
;
459 record
->others
= (struct other_pointer
*) 0;
460 record
->block
= block
;
467 /* Declare VAR to be a pointer which points into the block of r_alloc'd
470 If VAR is already delcared for this block, simply return.
471 If VAR currently points to some other block, remove that declaration
472 of it, then install the new one.
474 Return 0 if successful, -1 otherwise. */
477 r_alloc_declare (var
, block
)
479 register POINTER block
;
481 register relocatable_pointer
*block_ptr
= find_block (block
);
482 relocatable_pointer
*var_ptr
= find_location (var
);
483 register struct other_pointer
*other
;
485 if (block_ptr
== REL_NIL
)
488 if (var_ptr
!= REL_NIL
) /* Var already declared somewhere. */
490 register struct other_pointer
*po
;
492 if (var_ptr
== block_ptr
) /* Var already points to this block. */
495 po
= (struct other_pointer
*) 0;
496 other
= var_ptr
->others
;
497 while (other
&& other
->location
!= var
)
503 if (!other
) /* This only happens if the location is */
504 abort (); /* the main pointer and not an `other' */
506 if (po
) /* In the chain */
508 po
->next
= other
->next
;
511 else /* Only element of the chain */
513 free (var_ptr
->others
);
514 var_ptr
->others
= (struct other_pointer
*) 0;
518 /* Install this variable as an `other' element */
520 other
= (struct other_pointer
*) malloc (sizeof (struct other_pointer
));
525 /* If the malloc relocated this data block, adjust this variable. */
526 if (block
!= block_ptr
->block
)
528 int offset
= block_ptr
->block
- block
;
533 other
->location
= var
;
534 other
->next
= (struct other_pointer
*) 0;
536 if (block_ptr
->others
== (struct other_pointer
*) 0)
537 block_ptr
->others
= other
;
540 register struct other_pointer
*op
= block_ptr
->others
;
542 while (op
->next
!= (struct other_pointer
*) 0)
550 /* Recursively free the linked list of `other' pointers to a block. */
553 free_others (another
)
554 struct other_pointer
*another
;
556 if (another
== (struct other_pointer
*) 0)
559 free_others (another
->next
);
563 /* Remove the element pointed to by PTR from the doubly linked list.
564 Record the newly freed space in `holes', unless it was at the end,
565 in which case return that space to the system. Return 0 if successful,
570 register POINTER
*ptr
;
572 register relocatable_pointer
*this_ptr
= find_block (*ptr
);
574 if (this_ptr
== REL_NIL
)
578 register relocatable_pointer
*prev
= this_ptr
->prev
;
579 register relocatable_pointer
*next
= this_ptr
->next
;
580 if (next
&& prev
) /* Somewhere in the middle */
585 else if (prev
) /* Last block */
587 prev
->next
= REL_NIL
;
589 return_space (this_ptr
->size
);
590 free_others (this_ptr
->others
);
595 else if (next
) /* First block */
597 next
->prev
= REL_NIL
;
600 else if (this_ptr
= pointer_list
) /* ONLY block */
602 pointer_list
= REL_NIL
;
603 last_pointer
= REL_NIL
;
604 if (holes
) /* A hole precedes this block. */
607 return_space (real_break_value
- virtual_break_value
);
610 return_space (this_ptr
->size
);
612 if (real_break_value
!= virtual_break_value
)
615 free_others (this_ptr
->others
);
617 /* Turn off r_alloc_in_use? */
622 abort (); /* Weird shit */
624 free_others (this_ptr
->others
);
626 bzero (this_ptr
->block
, this_ptr
->size
);
627 note_hole (this_ptr
->block
, this_ptr
->size
);
629 if (holes
== MAX_HOLES
)
636 /* Change the size of the block pointed to by the thing in PTR.
637 If neccessary, r_alloc a new block and copy the data there.
638 Return a pointer to the block if successfull, NULL otherwise.
640 Note that if the size requested is less than the actual bloc size,
641 nothing is done and the pointer is simply returned. */
644 r_re_alloc (ptr
, size
)
648 register relocatable_pointer
*this_ptr
= find_block (*ptr
);
654 if (this_ptr
->size
>= size
) /* Already have enough space. */
657 /* Here we could try relocating the blocks just above... */
658 block
= r_alloc (ptr
, size
);
661 bcopy (this_ptr
->block
, block
, this_ptr
->size
);
662 if (this_ptr
->others
)
663 last_record
->others
= this_ptr
->others
;
665 if (! r_alloc_free (this_ptr
->block
))
676 /* Move and relocate all blocks from FIRST_PTR to LAST_PTR, inclusive,
677 downwards to space starting at ADDRESS. */
680 move_blocks_downward (first_ptr
, last_ptr
, address
)
681 relocatable_pointer
*first_ptr
, *last_ptr
;
684 int size
= (last_ptr
->block
+ last_ptr
->size
) - first_ptr
->block
;
685 register relocatable_pointer
*this_ptr
= first_ptr
;
686 register offset
= first_ptr
->block
- address
;
687 register struct other_pointer
*op
;
689 /* Move all the data. */
690 bcopy (first_ptr
->block
, address
, size
);
692 /* Now relocate all the pointers to those blocks. */
695 this_ptr
->block
-= offset
;
696 *this_ptr
->location
= this_ptr
->block
;
698 op
= this_ptr
->others
;
699 while (op
!= (struct other_pointer
*) 0)
701 *op
->location
-= offset
;
705 if (this_ptr
== last_ptr
)
708 this_ptr
= this_ptr
->next
;
714 /* Burp our memory zone. */
719 register relocatable_pointer
*this_ptr
= pointer_list
;
720 relocatable_pointer
*first_to_move
;
721 register relocatable_pointer
*last_to_move
;
722 hole_descriptor
*this_hole
= &r_alloc_holes
[0];
723 register hole_descriptor
*next_hole
;
724 register POINTER end
; /* First address after hole */
725 unsigned int space_regained
= 0;
727 while (holes
) /* While there are holes */
729 /* Find the first block after this hole. */
730 end
= this_hole
->address
+ this_hole
->size
;
731 while (this_ptr
&& this_ptr
->block
!= end
)
732 this_ptr
= this_ptr
->next
;
737 next_hole
= this_hole
+ 1;
738 last_to_move
= first_to_move
= this_ptr
;
739 this_ptr
= this_ptr
->next
;
741 /* Note all blocks located before the next hole. */
742 while (this_ptr
&& this_ptr
->block
< next_hole
->address
)
744 last_to_move
= this_ptr
;
745 this_ptr
= this_ptr
->next
;
748 move_blocks_downward (first_to_move
, last_to_move
, this_hole
->address
);
751 this_hole
= next_hole
;
754 return_space (space_regained
);
757 /* Relocate the list elements from the beginning of the list up to and
758 including UP_TO_THIS_PTR to the area beginning at FREE_SPACE, which is
759 after all current blocks.
761 First copy all the data, then adjust the pointers and reorganize
762 the list. NOTE that this *only* works for contiguous blocks. */
765 relocate_to_end (up_to_this_ptr
, free_space
)
766 register relocatable_pointer
*up_to_this_ptr
;
769 register relocatable_pointer
*this_ptr
;
770 POINTER block_start
= pointer_list
->block
;
771 POINTER block_end
= up_to_this_ptr
->block
+ up_to_this_ptr
->size
;
772 unsigned int total_size
= block_end
- block_start
;
773 unsigned int offset
= (int) (free_space
- block_start
);
775 bcopy (block_start
, free_space
, total_size
);
776 for (this_ptr
= up_to_this_ptr
; this_ptr
; this_ptr
= this_ptr
->prev
)
778 struct other_pointer
*op
= this_ptr
->others
;
780 *this_ptr
->location
+= offset
;
781 this_ptr
->block
+= offset
;
783 while (op
!= (struct other_pointer
*) 0)
785 *op
->location
+= offset
;
790 /* Connect the head to the tail. */
791 last_pointer
->next
= pointer_list
;
792 pointer_list
->prev
= last_pointer
;
795 up_to_this_ptr
->next
->prev
= REL_NIL
;
796 pointer_list
= up_to_this_ptr
->next
;
797 up_to_this_ptr
->next
= REL_NIL
;
798 last_pointer
= up_to_this_ptr
;
800 return total_size
; /* of space relocated. */
803 /* Relocate the list elements from FROM_THIS_PTR to (and including)
804 the last to the zone beginning at FREE_SPACE, which is located
807 First copy all the data, then adjust the pointers and reorganize
808 the list. NOTE that this *only* works for contiguous blocks. */
811 relocate_to_beginning (from_this_ptr
, free_space
)
812 register relocatable_pointer
*from_this_ptr
;
815 POINTER block_start
= from_this_ptr
->block
;
816 POINTER block_end
= last_pointer
->block
+ last_pointer
->size
;
817 unsigned int total_size
= (int) (block_end
- block_start
);
818 unsigned int offset
= (int) (from_this_ptr
->block
- free_space
);
819 register relocatable_pointer
*this_ptr
;
821 bcopy (block_start
, free_space
, total_size
);
822 for (this_ptr
= from_this_ptr
; this_ptr
; this_ptr
= this_ptr
->next
)
824 struct other_pointer
*op
= this_ptr
->others
;
826 *this_ptr
->location
-= offset
;
827 this_ptr
->block
-= offset
;
829 while (op
!= (struct other_pointer
*) 0)
831 *op
->location
-= offset
;
836 /* Connect the end to the beginning. */
837 last_pointer
->next
= pointer_list
;
838 pointer_list
->prev
= last_pointer
;
840 /* Disconnect and reset first and last. */
841 from_this_ptr
->prev
->next
= REL_NIL
;
842 last_pointer
= from_this_ptr
->prev
;
843 pointer_list
= from_this_ptr
;
844 pointer_list
->prev
= REL_NIL
;
846 return total_size
; /* of space moved. */
849 /* Relocate any blocks neccessary, either upwards or downwards,
850 to obtain a space of SIZE bytes. Assumes we have at least one block. */
856 register relocatable_pointer
*ptr
;
857 register int got
= 0;
859 if (size
> 0) /* Up: Relocate enough blocs to get SIZE. */
861 register POINTER new_space
;
863 for (ptr
= pointer_list
; got
< size
&& ptr
; ptr
= ptr
->next
)
869 new_space
= get_more_space (size
);
873 return (relocate_to_end (ptr
, pointer_list
->block
+ size
));
876 if (size
< 0) /* Down: relocate as many blocs as will
877 fit in SIZE bytes of space. */
879 register POINTER to_zone
;
882 for (ptr
= last_pointer
; got
>= size
&& ptr
; ptr
= ptr
->prev
)
889 /* Back off one block to be <= size */
896 to_zone
= virtual_break_value
- size
+ got
;
897 moved
= relocate_to_beginning (ptr
, to_zone
);
899 return_space (moved
);
910 /* This function encapsulates `sbrk' to preserve the relocatable blocks.
911 It is called just like `sbrk'. When relocatable blocks are in use,
912 `malloc' must use this function instead of `sbrk'. */
918 POINTER new_zone
; /* Start of the zone we will return. */
921 if (! r_alloc_in_use
)
922 return (POINTER
) sbrk (size
);
926 return virtual_break_value
;
928 if (size
> 0) /* Get more space */
930 register unsigned int space
;
932 if (pointer_list
== REL_NIL
)
934 POINTER space
= get_more_space (size
);
936 virtual_break_value
= real_break_value
;
940 new_zone
= virtual_break_value
;
942 /* Check if there is a hole just before the buffer zone. */
943 if (holes
&& r_alloc_holes
[0].address
== virtual_break_value
)
945 if (r_alloc_holes
[0].size
> size
)
947 /* Adjust the hole size. */
948 r_alloc_holes
[0].size
-= size
;
949 r_alloc_holes
[0].address
+= size
;
950 virtual_break_value
+= size
;
955 if (r_alloc_holes
[0].size
== size
)
957 virtual_break_value
+= size
;
963 /* Adjust the size requested by space
964 already available in this hole. */
965 size
-= r_alloc_holes
[0].size
;
966 virtual_break_value
+= r_alloc_holes
[0].size
;
970 space
= relocate (size
);
974 #ifdef REL_ALLOC_SAVE_SPACE
977 bzero (new_zone
, space
);
979 note_hole (new_zone
+ size
, space
- size
);
980 #endif /* REL_ALLOC_SAVE_SPACE */
982 virtual_break_value
+= size
;
985 else /* Return space to system */
989 POINTER old_break_value
;
991 if (pointer_list
== REL_NIL
)
993 POINTER space
= return_space (-size
);
994 virtual_break_value
= real_break_value
;
999 if (holes
&& r_alloc_holes
[0].address
== virtual_break_value
)
1001 size
-= r_alloc_holes
[0].size
;
1005 moved
= relocate (size
);
1006 old_break_value
= virtual_break_value
;
1009 return (POINTER
) -1;
1011 left_over
= moved
+ size
;
1012 virtual_break_value
+= size
;
1016 #ifdef REL_ALLOC_SAVE_SPACE
1017 move_blocks_downward
1019 bzero (virtual_break_value
, left_over
);
1020 note_hole (virtual_break_value
, left_over
);
1021 #endif /* not REL_ALLOC_SAVE_SPACE */
1024 return old_break_value
;
1035 relocatable_pointer
*ptr
;
1038 fprintf (stderr
, "virtual: 0x%x\n real: 0x%x\n true: 0x%x\n\n",
1039 virtual_break_value
, real_break_value
, true_break_value
);
1040 fprintf (stderr
, "Blocks:\n");
1041 for (ptr
= pointer_list
; ptr
; ptr
= ptr
->next
)
1043 fprintf (stderr
, " address: 0x%x\n", ptr
->block
);
1044 fprintf (stderr
, " size: 0x%x\n", ptr
->size
);
1047 struct other_pointer
*op
= ptr
->others
;
1048 fprintf (stderr
, " others:", ptr
->size
);
1051 fprintf (stderr
, " 0x%x", op
->location
);
1054 fprintf (stderr
, "\n");
1060 fprintf (stderr
, "\nHoles:\n");
1061 for (i
= 0; i
< holes
; i
++)
1063 fprintf (stderr
, " address: 0x%x\n", r_alloc_holes
[i
].address
);
1064 fprintf (stderr
, " size: 0x%x\n", r_alloc_holes
[i
].size
);
1068 fprintf (stderr
, "\n\n");