1 /* addrmap.c --- implementation of address map data structure.
3 Copyright (C) 2007-2023 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 "gdbsupport/gdb_obstack.h"
23 #include "gdbsupport/selftest.h"
25 /* Make sure splay trees can actually hold the values we want to
27 gdb_static_assert (sizeof (splay_tree_key
) >= sizeof (CORE_ADDR
*));
28 gdb_static_assert (sizeof (splay_tree_value
) >= sizeof (void *));
31 /* Fixed address maps. */
34 addrmap_fixed::set_empty (CORE_ADDR start
, CORE_ADDR end_inclusive
,
37 internal_error ("addrmap_fixed_set_empty: "
38 "fixed addrmaps can't be changed\n");
43 addrmap_fixed::find (CORE_ADDR addr
) const
45 const struct addrmap_transition
*bottom
= &transitions
[0];
46 const struct addrmap_transition
*top
= &transitions
[num_transitions
- 1];
50 /* This needs to round towards top, or else when top = bottom +
51 1 (i.e., two entries are under consideration), then mid ==
52 bottom, and then we may not narrow the range when (mid->addr
54 const addrmap_transition
*mid
= top
- (top
- bottom
) / 2;
56 if (mid
->addr
== addr
)
61 else if (mid
->addr
< addr
)
62 /* We don't eliminate mid itself here, since each transition
63 covers all subsequent addresses until the next. This is why
64 we must round up in computing the midpoint. */
75 addrmap_fixed::relocate (CORE_ADDR offset
)
79 for (i
= 0; i
< num_transitions
; i
++)
80 transitions
[i
].addr
+= offset
;
85 addrmap_fixed::foreach (addrmap_foreach_fn fn
)
89 for (i
= 0; i
< num_transitions
; i
++)
91 int res
= fn (transitions
[i
].addr
, transitions
[i
].value
);
102 /* Mutable address maps. */
104 /* Allocate a copy of CORE_ADDR. */
106 addrmap_mutable::allocate_key (CORE_ADDR addr
)
108 CORE_ADDR
*key
= XNEW (CORE_ADDR
);
111 return (splay_tree_key
) key
;
115 /* Type-correct wrappers for splay tree access. */
117 addrmap_mutable::splay_tree_lookup (CORE_ADDR addr
) const
119 return ::splay_tree_lookup (tree
, (splay_tree_key
) &addr
);
124 addrmap_mutable::splay_tree_predecessor (CORE_ADDR addr
) const
126 return ::splay_tree_predecessor (tree
, (splay_tree_key
) &addr
);
131 addrmap_mutable::splay_tree_successor (CORE_ADDR addr
)
133 return ::splay_tree_successor (tree
, (splay_tree_key
) &addr
);
138 addrmap_mutable::splay_tree_remove (CORE_ADDR addr
)
140 ::splay_tree_remove (tree
, (splay_tree_key
) &addr
);
145 addrmap_node_key (splay_tree_node node
)
147 return * (CORE_ADDR
*) node
->key
;
152 addrmap_node_value (splay_tree_node node
)
154 return (void *) node
->value
;
159 addrmap_node_set_value (splay_tree_node node
, void *value
)
161 node
->value
= (splay_tree_value
) value
;
166 addrmap_mutable::splay_tree_insert (CORE_ADDR key
, void *value
)
168 ::splay_tree_insert (tree
,
170 (splay_tree_value
) value
);
174 /* Without changing the mapping of any address, ensure that there is a
175 tree node at ADDR, even if it would represent a "transition" from
176 one value to the same value. */
178 addrmap_mutable::force_transition (CORE_ADDR addr
)
180 splay_tree_node n
= splay_tree_lookup (addr
);
184 n
= splay_tree_predecessor (addr
);
185 splay_tree_insert (addr
, n
? addrmap_node_value (n
) : NULL
);
191 addrmap_mutable::set_empty (CORE_ADDR start
, CORE_ADDR end_inclusive
,
194 splay_tree_node n
, next
;
197 /* If we're being asked to set all empty portions of the given
198 address range to empty, then probably the caller is confused.
199 (If that turns out to be useful in some cases, then we can change
200 this to simply return, since overriding NULL with NULL is a
204 /* We take a two-pass approach, for simplicity.
205 - Establish transitions where we think we might need them.
206 - First pass: change all NULL regions to OBJ.
207 - Second pass: remove any unnecessary transitions. */
209 /* Establish transitions at the start and end. */
210 force_transition (start
);
211 if (end_inclusive
< CORE_ADDR_MAX
)
212 force_transition (end_inclusive
+ 1);
214 /* Walk the area, changing all NULL regions to OBJ. */
215 for (n
= splay_tree_lookup (start
), gdb_assert (n
);
216 n
&& addrmap_node_key (n
) <= end_inclusive
;
217 n
= splay_tree_successor (addrmap_node_key (n
)))
219 if (! addrmap_node_value (n
))
220 addrmap_node_set_value (n
, obj
);
223 /* Walk the area again, removing transitions from any value to
224 itself. Be sure to visit both the transitions we forced
226 n
= splay_tree_predecessor (start
);
227 prior_value
= n
? addrmap_node_value (n
) : NULL
;
228 for (n
= splay_tree_lookup (start
), gdb_assert (n
);
229 n
&& (end_inclusive
== CORE_ADDR_MAX
230 || addrmap_node_key (n
) <= end_inclusive
+ 1);
233 next
= splay_tree_successor (addrmap_node_key (n
));
234 if (addrmap_node_value (n
) == prior_value
)
235 splay_tree_remove (addrmap_node_key (n
));
237 prior_value
= addrmap_node_value (n
);
243 addrmap_mutable::find (CORE_ADDR addr
) const
245 splay_tree_node n
= splay_tree_lookup (addr
);
248 gdb_assert (addrmap_node_key (n
) == addr
);
249 return addrmap_node_value (n
);
252 n
= splay_tree_predecessor (addr
);
255 gdb_assert (addrmap_node_key (n
) < addr
);
256 return addrmap_node_value (n
);
263 addrmap_fixed::addrmap_fixed (struct obstack
*obstack
, addrmap_mutable
*mut
)
265 size_t transition_count
= 0;
267 /* Count the number of transitions in the tree. */
268 mut
->foreach ([&] (CORE_ADDR start
, void *obj
)
274 /* Include an extra entry for the transition at zero (which fixed
275 maps have, but mutable maps do not.) */
279 transitions
= XOBNEWVEC (obstack
, struct addrmap_transition
,
281 transitions
[0].addr
= 0;
282 transitions
[0].value
= NULL
;
284 /* Copy all entries from the splay tree to the array, in order
285 of increasing address. */
286 mut
->foreach ([&] (CORE_ADDR start
, void *obj
)
288 transitions
[num_transitions
].addr
= start
;
289 transitions
[num_transitions
].value
= obj
;
294 /* We should have filled the array. */
295 gdb_assert (num_transitions
== transition_count
);
300 addrmap_mutable::relocate (CORE_ADDR offset
)
302 /* Not needed yet. */
303 internal_error (_("addrmap_relocate is not implemented yet "
304 "for mutable addrmaps"));
308 /* This is a splay_tree_foreach_fn. */
311 addrmap_mutable_foreach_worker (splay_tree_node node
, void *data
)
313 addrmap_foreach_fn
*fn
= (addrmap_foreach_fn
*) data
;
315 return (*fn
) (addrmap_node_key (node
), addrmap_node_value (node
));
320 addrmap_mutable::foreach (addrmap_foreach_fn fn
)
322 return splay_tree_foreach (tree
, addrmap_mutable_foreach_worker
, &fn
);
326 /* Compare keys as CORE_ADDR * values. */
328 splay_compare_CORE_ADDR_ptr (splay_tree_key ak
, splay_tree_key bk
)
330 CORE_ADDR a
= * (CORE_ADDR
*) ak
;
331 CORE_ADDR b
= * (CORE_ADDR
*) bk
;
333 /* We can't just return a-b here, because of over/underflow. */
344 xfree_wrapper (splay_tree_key key
)
346 xfree ((void *) key
);
349 addrmap_mutable::addrmap_mutable ()
350 : tree (splay_tree_new (splay_compare_CORE_ADDR_ptr
, xfree_wrapper
,
351 nullptr /* no delete value */))
355 addrmap_mutable::~addrmap_mutable ()
357 splay_tree_delete (tree
);
364 addrmap_dump (struct addrmap
*map
, struct ui_file
*outfile
, void *payload
)
366 /* True if the previously printed addrmap entry was for PAYLOAD.
367 If so, we want to print the next one as well (since the next
368 addrmap entry defines the end of the range). */
369 bool previous_matched
= false;
371 auto callback
= [&] (CORE_ADDR start_addr
, void *obj
)
375 bool matches
= payload
== nullptr || payload
== obj
;
376 const char *addr_str
= nullptr;
378 addr_str
= host_address_to_string (obj
);
379 else if (previous_matched
)
380 addr_str
= "<ends here>";
382 if (matches
|| previous_matched
)
383 gdb_printf (outfile
, " %s%s %s\n",
384 payload
!= nullptr ? " " : "",
385 core_addr_to_string (start_addr
),
388 previous_matched
= matches
;
393 map
->foreach (callback
);
397 namespace selftests
{
399 /* Convert P to CORE_ADDR. */
404 return (CORE_ADDR
)(uintptr_t)p
;
407 /* Check that &ARRAY[LOW]..&ARRAY[HIGH] has VAL in MAP. */
409 #define CHECK_ADDRMAP_FIND(MAP, ARRAY, LOW, HIGH, VAL) \
412 for (unsigned i = LOW; i <= HIGH; ++i) \
413 SELF_CHECK (MAP->find (core_addr (&ARRAY[i])) == VAL); \
417 /* Entry point for addrmap unit tests. */
422 /* We'll verify using the addresses of the elements of this array. */
425 /* We'll verify using these values stored into the map. */
426 void *val1
= &array
[1];
427 void *val2
= &array
[2];
429 /* Create mutable addrmap. */
430 auto_obstack temp_obstack
;
431 std::unique_ptr
<struct addrmap_mutable
> map (new addrmap_mutable
);
432 SELF_CHECK (map
!= nullptr);
434 /* Check initial state. */
435 CHECK_ADDRMAP_FIND (map
, array
, 0, 19, nullptr);
437 /* Insert address range into mutable addrmap. */
438 map
->set_empty (core_addr (&array
[10]), core_addr (&array
[12]), val1
);
439 CHECK_ADDRMAP_FIND (map
, array
, 0, 9, nullptr);
440 CHECK_ADDRMAP_FIND (map
, array
, 10, 12, val1
);
441 CHECK_ADDRMAP_FIND (map
, array
, 13, 19, nullptr);
443 /* Create corresponding fixed addrmap. */
445 = new (&temp_obstack
) addrmap_fixed (&temp_obstack
, map
.get ());
446 SELF_CHECK (map2
!= nullptr);
447 CHECK_ADDRMAP_FIND (map2
, array
, 0, 9, nullptr);
448 CHECK_ADDRMAP_FIND (map2
, array
, 10, 12, val1
);
449 CHECK_ADDRMAP_FIND (map2
, array
, 13, 19, nullptr);
451 /* Iterate over both addrmaps. */
452 auto callback
= [&] (CORE_ADDR start_addr
, void *obj
)
454 if (start_addr
== core_addr (nullptr))
455 SELF_CHECK (obj
== nullptr);
456 else if (start_addr
== core_addr (&array
[10]))
457 SELF_CHECK (obj
== val1
);
458 else if (start_addr
== core_addr (&array
[13]))
459 SELF_CHECK (obj
== nullptr);
464 SELF_CHECK (map
->foreach (callback
) == 0);
465 SELF_CHECK (map2
->foreach (callback
) == 0);
467 /* Relocate fixed addrmap. */
469 CHECK_ADDRMAP_FIND (map2
, array
, 0, 10, nullptr);
470 CHECK_ADDRMAP_FIND (map2
, array
, 11, 13, val1
);
471 CHECK_ADDRMAP_FIND (map2
, array
, 14, 19, nullptr);
473 /* Insert partially overlapping address range into mutable addrmap. */
474 map
->set_empty (core_addr (&array
[11]), core_addr (&array
[13]), val2
);
475 CHECK_ADDRMAP_FIND (map
, array
, 0, 9, nullptr);
476 CHECK_ADDRMAP_FIND (map
, array
, 10, 12, val1
);
477 CHECK_ADDRMAP_FIND (map
, array
, 13, 13, val2
);
478 CHECK_ADDRMAP_FIND (map
, array
, 14, 19, nullptr);
481 } // namespace selftests
482 #endif /* GDB_SELF_TEST */
484 void _initialize_addrmap ();
486 _initialize_addrmap ()
489 selftests::register_test ("addrmap", selftests::test_addrmap
);
490 #endif /* GDB_SELF_TEST */