1 /* addrmap.c --- implementation of address map data structure.
3 Copyright (C) 2007-2022 Free Software Foundation, Inc.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include "splay-tree.h"
22 #include "gdbsupport/gdb_obstack.h"
24 #include "gdbsupport/selftest.h"
26 /* Make sure splay trees can actually hold the values we want to
28 gdb_static_assert (sizeof (splay_tree_key
) >= sizeof (CORE_ADDR
*));
29 gdb_static_assert (sizeof (splay_tree_value
) >= sizeof (void *));
32 /* The "abstract class". */
34 /* Functions implementing the addrmap functions for a particular
38 void (*set_empty
) (struct addrmap
*self
,
39 CORE_ADDR start
, CORE_ADDR end_inclusive
,
41 void *(*find
) (const addrmap
*self
, CORE_ADDR addr
);
42 struct addrmap
*(*create_fixed
) (struct addrmap
*self
,
43 struct obstack
*obstack
);
44 void (*relocate
) (struct addrmap
*self
, CORE_ADDR offset
);
45 int (*foreach
) (struct addrmap
*self
, addrmap_foreach_fn fn
);
51 const struct addrmap_funcs
*funcs
;
56 addrmap_set_empty (struct addrmap
*map
,
57 CORE_ADDR start
, CORE_ADDR end_inclusive
,
60 map
->funcs
->set_empty (map
, start
, end_inclusive
, obj
);
65 addrmap_find (const addrmap
*map
, CORE_ADDR addr
)
67 return map
->funcs
->find (map
, addr
);
72 addrmap_create_fixed (struct addrmap
*original
, struct obstack
*obstack
)
74 return original
->funcs
->create_fixed (original
, obstack
);
78 /* Relocate all the addresses in MAP by OFFSET. (This can be applied
79 to either mutable or immutable maps.) */
81 addrmap_relocate (struct addrmap
*map
, CORE_ADDR offset
)
83 map
->funcs
->relocate (map
, offset
);
88 addrmap_foreach (struct addrmap
*map
, addrmap_foreach_fn fn
)
90 return map
->funcs
->foreach (map
, fn
);
93 /* Fixed address maps. */
95 /* A transition: a point in an address map where the value changes.
96 The map maps ADDR to VALUE, but if ADDR > 0, it maps ADDR-1 to
98 struct addrmap_transition
107 struct addrmap addrmap
;
109 /* The number of transitions in TRANSITIONS. */
110 size_t num_transitions
;
112 /* An array of transitions, sorted by address. For every point in
113 the map where either ADDR == 0 or ADDR is mapped to one value and
114 ADDR - 1 is mapped to something different, we have an entry here
115 containing ADDR and VALUE. (Note that this means we always have
116 an entry for address 0). */
117 struct addrmap_transition transitions
[1];
122 addrmap_fixed_set_empty (struct addrmap
*self
,
123 CORE_ADDR start
, CORE_ADDR end_inclusive
,
126 internal_error (__FILE__
, __LINE__
,
127 "addrmap_fixed_set_empty: "
128 "fixed addrmaps can't be changed\n");
133 addrmap_fixed_find (const addrmap
*self
, CORE_ADDR addr
)
135 const addrmap_fixed
*map
= (const addrmap_fixed
*) self
;
136 const addrmap_transition
*bottom
= &map
->transitions
[0];
137 const addrmap_transition
*top
= &map
->transitions
[map
->num_transitions
- 1];
141 /* This needs to round towards top, or else when top = bottom +
142 1 (i.e., two entries are under consideration), then mid ==
143 bottom, and then we may not narrow the range when (mid->addr
145 const addrmap_transition
*mid
= top
- (top
- bottom
) / 2;
147 if (mid
->addr
== addr
)
152 else if (mid
->addr
< addr
)
153 /* We don't eliminate mid itself here, since each transition
154 covers all subsequent addresses until the next. This is why
155 we must round up in computing the midpoint. */
161 return bottom
->value
;
165 static struct addrmap
*
166 addrmap_fixed_create_fixed (struct addrmap
*self
, struct obstack
*obstack
)
168 internal_error (__FILE__
, __LINE__
,
169 _("addrmap_create_fixed is not implemented yet "
170 "for fixed addrmaps"));
175 addrmap_fixed_relocate (struct addrmap
*self
, CORE_ADDR offset
)
177 struct addrmap_fixed
*map
= (struct addrmap_fixed
*) self
;
180 for (i
= 0; i
< map
->num_transitions
; i
++)
181 map
->transitions
[i
].addr
+= offset
;
186 addrmap_fixed_foreach (struct addrmap
*self
, addrmap_foreach_fn fn
)
188 struct addrmap_fixed
*map
= (struct addrmap_fixed
*) self
;
191 for (i
= 0; i
< map
->num_transitions
; i
++)
193 int res
= fn (map
->transitions
[i
].addr
, map
->transitions
[i
].value
);
203 static const struct addrmap_funcs addrmap_fixed_funcs
=
205 addrmap_fixed_set_empty
,
207 addrmap_fixed_create_fixed
,
208 addrmap_fixed_relocate
,
209 addrmap_fixed_foreach
214 /* Mutable address maps. */
216 struct addrmap_mutable
218 struct addrmap addrmap
;
220 /* The obstack to use for allocations for this map. */
221 struct obstack
*obstack
;
223 /* A splay tree, with a node for each transition; there is a
224 transition at address T if T-1 and T map to different objects.
226 Any addresses below the first node map to NULL. (Unlike
227 fixed maps, we have no entry at (CORE_ADDR) 0; it doesn't
230 The last region is assumed to end at CORE_ADDR_MAX.
232 Since we can't know whether CORE_ADDR is larger or smaller than
233 splay_tree_key (unsigned long) --- I think both are possible,
234 given all combinations of 32- and 64-bit hosts and targets ---
235 our keys are pointers to CORE_ADDR values. Since the splay tree
236 library doesn't pass any closure pointer to the key free
237 function, we can't keep a freelist for keys. Since mutable
238 addrmaps are only used temporarily right now, we just leak keys
239 from deleted nodes; they'll be freed when the obstack is freed. */
242 /* A freelist for splay tree nodes, allocated on obstack, and
243 chained together by their 'right' pointers. */
244 splay_tree_node free_nodes
;
248 /* Allocate a copy of CORE_ADDR in MAP's obstack. */
249 static splay_tree_key
250 allocate_key (struct addrmap_mutable
*map
, CORE_ADDR addr
)
252 CORE_ADDR
*key
= XOBNEW (map
->obstack
, CORE_ADDR
);
255 return (splay_tree_key
) key
;
259 /* Type-correct wrappers for splay tree access. */
260 static splay_tree_node
261 addrmap_splay_tree_lookup (struct addrmap_mutable
*map
, CORE_ADDR addr
)
263 return splay_tree_lookup (map
->tree
, (splay_tree_key
) &addr
);
267 static splay_tree_node
268 addrmap_splay_tree_predecessor (struct addrmap_mutable
*map
, CORE_ADDR addr
)
270 return splay_tree_predecessor (map
->tree
, (splay_tree_key
) &addr
);
274 static splay_tree_node
275 addrmap_splay_tree_successor (struct addrmap_mutable
*map
, CORE_ADDR addr
)
277 return splay_tree_successor (map
->tree
, (splay_tree_key
) &addr
);
282 addrmap_splay_tree_remove (struct addrmap_mutable
*map
, CORE_ADDR addr
)
284 splay_tree_remove (map
->tree
, (splay_tree_key
) &addr
);
289 addrmap_node_key (splay_tree_node node
)
291 return * (CORE_ADDR
*) node
->key
;
296 addrmap_node_value (splay_tree_node node
)
298 return (void *) node
->value
;
303 addrmap_node_set_value (splay_tree_node node
, void *value
)
305 node
->value
= (splay_tree_value
) value
;
310 addrmap_splay_tree_insert (struct addrmap_mutable
*map
,
311 CORE_ADDR key
, void *value
)
313 splay_tree_insert (map
->tree
,
314 allocate_key (map
, key
),
315 (splay_tree_value
) value
);
319 /* Without changing the mapping of any address, ensure that there is a
320 tree node at ADDR, even if it would represent a "transition" from
321 one value to the same value. */
323 force_transition (struct addrmap_mutable
*self
, CORE_ADDR addr
)
326 = addrmap_splay_tree_lookup (self
, addr
);
330 n
= addrmap_splay_tree_predecessor (self
, addr
);
331 addrmap_splay_tree_insert (self
, addr
,
332 n
? addrmap_node_value (n
) : NULL
);
338 addrmap_mutable_set_empty (struct addrmap
*self
,
339 CORE_ADDR start
, CORE_ADDR end_inclusive
,
342 struct addrmap_mutable
*map
= (struct addrmap_mutable
*) self
;
343 splay_tree_node n
, next
;
346 /* If we're being asked to set all empty portions of the given
347 address range to empty, then probably the caller is confused.
348 (If that turns out to be useful in some cases, then we can change
349 this to simply return, since overriding NULL with NULL is a
353 /* We take a two-pass approach, for simplicity.
354 - Establish transitions where we think we might need them.
355 - First pass: change all NULL regions to OBJ.
356 - Second pass: remove any unnecessary transitions. */
358 /* Establish transitions at the start and end. */
359 force_transition (map
, start
);
360 if (end_inclusive
< CORE_ADDR_MAX
)
361 force_transition (map
, end_inclusive
+ 1);
363 /* Walk the area, changing all NULL regions to OBJ. */
364 for (n
= addrmap_splay_tree_lookup (map
, start
), gdb_assert (n
);
365 n
&& addrmap_node_key (n
) <= end_inclusive
;
366 n
= addrmap_splay_tree_successor (map
, addrmap_node_key (n
)))
368 if (! addrmap_node_value (n
))
369 addrmap_node_set_value (n
, obj
);
372 /* Walk the area again, removing transitions from any value to
373 itself. Be sure to visit both the transitions we forced
375 n
= addrmap_splay_tree_predecessor (map
, start
);
376 prior_value
= n
? addrmap_node_value (n
) : NULL
;
377 for (n
= addrmap_splay_tree_lookup (map
, start
), gdb_assert (n
);
378 n
&& (end_inclusive
== CORE_ADDR_MAX
379 || addrmap_node_key (n
) <= end_inclusive
+ 1);
382 next
= addrmap_splay_tree_successor (map
, addrmap_node_key (n
));
383 if (addrmap_node_value (n
) == prior_value
)
384 addrmap_splay_tree_remove (map
, addrmap_node_key (n
));
386 prior_value
= addrmap_node_value (n
);
392 addrmap_mutable_find (const addrmap
*self
, CORE_ADDR addr
)
394 struct addrmap_mutable
*map
= (struct addrmap_mutable
*) self
;
395 splay_tree_node n
= addrmap_splay_tree_lookup (map
, addr
);
398 gdb_assert (addrmap_node_key (n
) == addr
);
399 return addrmap_node_value (n
);
402 n
= addrmap_splay_tree_predecessor (map
, addr
);
405 gdb_assert (addrmap_node_key (n
) < addr
);
406 return addrmap_node_value (n
);
413 /* A function to pass to splay_tree_foreach to count the number of nodes
416 splay_foreach_count (splay_tree_node n
, void *closure
)
418 size_t *count
= (size_t *) closure
;
425 /* A function to pass to splay_tree_foreach to copy entries into a
426 fixed address map. */
428 splay_foreach_copy (splay_tree_node n
, void *closure
)
430 struct addrmap_fixed
*fixed
= (struct addrmap_fixed
*) closure
;
431 struct addrmap_transition
*t
= &fixed
->transitions
[fixed
->num_transitions
];
433 t
->addr
= addrmap_node_key (n
);
434 t
->value
= addrmap_node_value (n
);
435 fixed
->num_transitions
++;
441 static struct addrmap
*
442 addrmap_mutable_create_fixed (struct addrmap
*self
, struct obstack
*obstack
)
444 struct addrmap_mutable
*mutable_obj
= (struct addrmap_mutable
*) self
;
445 struct addrmap_fixed
*fixed
;
446 size_t num_transitions
;
449 /* Count the number of transitions in the tree. */
451 splay_tree_foreach (mutable_obj
->tree
, splay_foreach_count
, &num_transitions
);
453 /* Include an extra entry for the transition at zero (which fixed
454 maps have, but mutable maps do not.) */
457 alloc_len
= sizeof (*fixed
)
458 + (num_transitions
* sizeof (fixed
->transitions
[0]));
459 fixed
= (struct addrmap_fixed
*) obstack_alloc (obstack
, alloc_len
);
460 fixed
->addrmap
.funcs
= &addrmap_fixed_funcs
;
461 fixed
->num_transitions
= 1;
462 fixed
->transitions
[0].addr
= 0;
463 fixed
->transitions
[0].value
= NULL
;
465 /* Copy all entries from the splay tree to the array, in order
466 of increasing address. */
467 splay_tree_foreach (mutable_obj
->tree
, splay_foreach_copy
, fixed
);
469 /* We should have filled the array. */
470 gdb_assert (fixed
->num_transitions
== num_transitions
);
472 return (struct addrmap
*) fixed
;
477 addrmap_mutable_relocate (struct addrmap
*self
, CORE_ADDR offset
)
479 /* Not needed yet. */
480 internal_error (__FILE__
, __LINE__
,
481 _("addrmap_relocate is not implemented yet "
482 "for mutable addrmaps"));
486 /* This is a splay_tree_foreach_fn. */
489 addrmap_mutable_foreach_worker (splay_tree_node node
, void *data
)
491 addrmap_foreach_fn
*fn
= (addrmap_foreach_fn
*) data
;
493 return (*fn
) (addrmap_node_key (node
), addrmap_node_value (node
));
498 addrmap_mutable_foreach (struct addrmap
*self
, addrmap_foreach_fn fn
)
500 struct addrmap_mutable
*mutable_obj
= (struct addrmap_mutable
*) self
;
502 return splay_tree_foreach (mutable_obj
->tree
, addrmap_mutable_foreach_worker
,
507 static const struct addrmap_funcs addrmap_mutable_funcs
=
509 addrmap_mutable_set_empty
,
510 addrmap_mutable_find
,
511 addrmap_mutable_create_fixed
,
512 addrmap_mutable_relocate
,
513 addrmap_mutable_foreach
518 splay_obstack_alloc (int size
, void *closure
)
520 struct addrmap_mutable
*map
= (struct addrmap_mutable
*) closure
;
523 /* We should only be asked to allocate nodes and larger things.
524 (If, at some point in the future, this is no longer true, we can
525 just round up the size to sizeof (*n).) */
526 gdb_assert (size
>= sizeof (*n
));
531 map
->free_nodes
= n
->right
;
535 return obstack_alloc (map
->obstack
, size
);
540 splay_obstack_free (void *obj
, void *closure
)
542 struct addrmap_mutable
*map
= (struct addrmap_mutable
*) closure
;
543 splay_tree_node n
= (splay_tree_node
) obj
;
545 /* We've asserted in the allocation function that we only allocate
546 nodes or larger things, so it should be safe to put whatever
547 we get passed back on the free list. */
548 n
->right
= map
->free_nodes
;
553 /* Compare keys as CORE_ADDR * values. */
555 splay_compare_CORE_ADDR_ptr (splay_tree_key ak
, splay_tree_key bk
)
557 CORE_ADDR a
= * (CORE_ADDR
*) ak
;
558 CORE_ADDR b
= * (CORE_ADDR
*) bk
;
560 /* We can't just return a-b here, because of over/underflow. */
571 addrmap_create_mutable (struct obstack
*obstack
)
573 struct addrmap_mutable
*map
= XOBNEW (obstack
, struct addrmap_mutable
);
575 map
->addrmap
.funcs
= &addrmap_mutable_funcs
;
576 map
->obstack
= obstack
;
578 /* splay_tree_new_with_allocator uses the provided allocation
579 function to allocate the main splay_tree structure itself, so our
580 free list has to be initialized before we create the tree. */
581 map
->free_nodes
= NULL
;
583 map
->tree
= splay_tree_new_with_allocator (splay_compare_CORE_ADDR_ptr
,
584 NULL
, /* no delete key */
585 NULL
, /* no delete value */
590 return (struct addrmap
*) map
;
596 addrmap_dump (struct addrmap
*map
, struct ui_file
*outfile
, void *payload
)
598 /* True if the previously printed addrmap entry was for PAYLOAD.
599 If so, we want to print the next one as well (since the next
600 addrmap entry defines the end of the range). */
601 bool previous_matched
= false;
603 auto callback
= [&] (CORE_ADDR start_addr
, void *obj
)
607 bool matches
= payload
== nullptr || payload
== obj
;
608 const char *addr_str
= nullptr;
610 addr_str
= host_address_to_string (obj
);
611 else if (previous_matched
)
612 addr_str
= "<ends here>";
614 if (matches
|| previous_matched
)
615 gdb_printf (outfile
, " %s%s %s\n",
616 payload
!= nullptr ? " " : "",
617 core_addr_to_string (start_addr
),
620 previous_matched
= matches
;
625 addrmap_foreach (map
, callback
);
629 namespace selftests
{
631 /* Convert P to CORE_ADDR. */
636 return (CORE_ADDR
)(uintptr_t)p
;
639 /* Check that &ARRAY[LOW]..&ARRAY[HIGH] has VAL in MAP. */
641 #define CHECK_ADDRMAP_FIND(MAP, ARRAY, LOW, HIGH, VAL) \
644 for (unsigned i = LOW; i <= HIGH; ++i) \
645 SELF_CHECK (addrmap_find (MAP, core_addr (&ARRAY[i])) == VAL); \
649 /* Entry point for addrmap unit tests. */
654 /* We'll verify using the addresses of the elements of this array. */
657 /* We'll verify using these values stored into the map. */
658 void *val1
= &array
[1];
659 void *val2
= &array
[2];
661 /* Create mutable addrmap. */
662 struct obstack temp_obstack
;
663 obstack_init (&temp_obstack
);
664 struct addrmap
*map
= addrmap_create_mutable (&temp_obstack
);
665 SELF_CHECK (map
!= nullptr);
667 /* Check initial state. */
668 CHECK_ADDRMAP_FIND (map
, array
, 0, 19, nullptr);
670 /* Insert address range into mutable addrmap. */
671 addrmap_set_empty (map
, core_addr (&array
[10]), core_addr (&array
[12]),
673 CHECK_ADDRMAP_FIND (map
, array
, 0, 9, nullptr);
674 CHECK_ADDRMAP_FIND (map
, array
, 10, 12, val1
);
675 CHECK_ADDRMAP_FIND (map
, array
, 13, 19, nullptr);
677 /* Create corresponding fixed addrmap. */
678 struct addrmap
*map2
= addrmap_create_fixed (map
, &temp_obstack
);
679 SELF_CHECK (map2
!= nullptr);
680 CHECK_ADDRMAP_FIND (map2
, array
, 0, 9, nullptr);
681 CHECK_ADDRMAP_FIND (map2
, array
, 10, 12, val1
);
682 CHECK_ADDRMAP_FIND (map2
, array
, 13, 19, nullptr);
684 /* Iterate over both addrmaps. */
685 auto callback
= [&] (CORE_ADDR start_addr
, void *obj
)
687 if (start_addr
== core_addr (nullptr))
688 SELF_CHECK (obj
== nullptr);
689 else if (start_addr
== core_addr (&array
[10]))
690 SELF_CHECK (obj
== val1
);
691 else if (start_addr
== core_addr (&array
[13]))
692 SELF_CHECK (obj
== nullptr);
697 SELF_CHECK (addrmap_foreach (map
, callback
) == 0);
698 SELF_CHECK (addrmap_foreach (map2
, callback
) == 0);
700 /* Relocate fixed addrmap. */
701 addrmap_relocate (map2
, 1);
702 CHECK_ADDRMAP_FIND (map2
, array
, 0, 10, nullptr);
703 CHECK_ADDRMAP_FIND (map2
, array
, 11, 13, val1
);
704 CHECK_ADDRMAP_FIND (map2
, array
, 14, 19, nullptr);
706 /* Insert partially overlapping address range into mutable addrmap. */
707 addrmap_set_empty (map
, core_addr (&array
[11]), core_addr (&array
[13]),
709 CHECK_ADDRMAP_FIND (map
, array
, 0, 9, nullptr);
710 CHECK_ADDRMAP_FIND (map
, array
, 10, 12, val1
);
711 CHECK_ADDRMAP_FIND (map
, array
, 13, 13, val2
);
712 CHECK_ADDRMAP_FIND (map
, array
, 14, 19, nullptr);
715 obstack_free (&temp_obstack
, NULL
);
718 } // namespace selftests
719 #endif /* GDB_SELF_TEST */
721 void _initialize_addrmap ();
723 _initialize_addrmap ()
726 selftests::register_test ("addrmap", selftests::test_addrmap
);
727 #endif /* GDB_SELF_TEST */