Fix: strip --strip-debug breaks relocations
[binutils-gdb.git] / gdb / addrmap.c
blobb10888008c91da5aac4fe995bc32a879ee04eb49
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/>. */
20 #include "defs.h"
21 #include "gdbsupport/gdb_obstack.h"
22 #include "addrmap.h"
23 #include "gdbsupport/selftest.h"
25 /* Make sure splay trees can actually hold the values we want to
26 store in them. */
27 static_assert (sizeof (splay_tree_key) >= sizeof (CORE_ADDR *));
28 static_assert (sizeof (splay_tree_value) >= sizeof (void *));
31 /* Fixed address maps. */
33 void
34 addrmap_fixed::set_empty (CORE_ADDR start, CORE_ADDR end_inclusive,
35 void *obj)
37 internal_error ("addrmap_fixed_set_empty: "
38 "fixed addrmaps can't be changed\n");
42 void *
43 addrmap_fixed::do_find (CORE_ADDR addr) const
45 const struct addrmap_transition *bottom = &transitions[0];
46 const struct addrmap_transition *top = &transitions[num_transitions - 1];
48 while (bottom < top)
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
53 < addr). */
54 const addrmap_transition *mid = top - (top - bottom) / 2;
56 if (mid->addr == addr)
58 bottom = mid;
59 break;
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. */
65 bottom = mid;
66 else
67 top = mid - 1;
70 return bottom->value;
74 void
75 addrmap_fixed::relocate (CORE_ADDR offset)
77 size_t i;
79 for (i = 0; i < num_transitions; i++)
80 transitions[i].addr += offset;
84 int
85 addrmap_fixed::do_foreach (addrmap_foreach_fn fn) const
87 size_t i;
89 for (i = 0; i < num_transitions; i++)
91 int res = fn (transitions[i].addr, transitions[i].value);
93 if (res != 0)
94 return res;
97 return 0;
102 /* Mutable address maps. */
104 /* Allocate a copy of CORE_ADDR. */
105 splay_tree_key
106 addrmap_mutable::allocate_key (CORE_ADDR addr)
108 CORE_ADDR *key = XNEW (CORE_ADDR);
110 *key = addr;
111 return (splay_tree_key) key;
115 /* Type-correct wrappers for splay tree access. */
116 splay_tree_node
117 addrmap_mutable::splay_tree_lookup (CORE_ADDR addr) const
119 return ::splay_tree_lookup (tree, (splay_tree_key) &addr);
123 splay_tree_node
124 addrmap_mutable::splay_tree_predecessor (CORE_ADDR addr) const
126 return ::splay_tree_predecessor (tree, (splay_tree_key) &addr);
130 splay_tree_node
131 addrmap_mutable::splay_tree_successor (CORE_ADDR addr)
133 return ::splay_tree_successor (tree, (splay_tree_key) &addr);
137 void
138 addrmap_mutable::splay_tree_remove (CORE_ADDR addr)
140 ::splay_tree_remove (tree, (splay_tree_key) &addr);
144 static CORE_ADDR
145 addrmap_node_key (splay_tree_node node)
147 return * (CORE_ADDR *) node->key;
151 static void *
152 addrmap_node_value (splay_tree_node node)
154 return (void *) node->value;
158 static void
159 addrmap_node_set_value (splay_tree_node node, void *value)
161 node->value = (splay_tree_value) value;
165 void
166 addrmap_mutable::splay_tree_insert (CORE_ADDR key, void *value)
168 ::splay_tree_insert (tree,
169 allocate_key (key),
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. */
177 void
178 addrmap_mutable::force_transition (CORE_ADDR addr)
180 splay_tree_node n = splay_tree_lookup (addr);
182 if (! n)
184 n = splay_tree_predecessor (addr);
185 splay_tree_insert (addr, n ? addrmap_node_value (n) : NULL);
190 void
191 addrmap_mutable::set_empty (CORE_ADDR start, CORE_ADDR end_inclusive,
192 void *obj)
194 splay_tree_node n, next;
195 void *prior_value;
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
201 no-op.) */
202 gdb_assert (obj);
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
225 above. */
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);
231 n = next)
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));
236 else
237 prior_value = addrmap_node_value (n);
242 void *
243 addrmap_mutable::do_find (CORE_ADDR addr) const
245 splay_tree_node n = splay_tree_lookup (addr);
246 if (n != nullptr)
248 gdb_assert (addrmap_node_key (n) == addr);
249 return addrmap_node_value (n);
252 n = splay_tree_predecessor (addr);
253 if (n != nullptr)
255 gdb_assert (addrmap_node_key (n) < addr);
256 return addrmap_node_value (n);
259 return nullptr;
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)
270 ++transition_count;
271 return 0;
274 /* Include an extra entry for the transition at zero (which fixed
275 maps have, but mutable maps do not.) */
276 transition_count++;
278 num_transitions = 1;
279 transitions = XOBNEWVEC (obstack, struct addrmap_transition,
280 transition_count);
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;
290 ++num_transitions;
291 return 0;
294 /* We should have filled the array. */
295 gdb_assert (num_transitions == transition_count);
299 void
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. */
310 static int
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::do_foreach (addrmap_foreach_fn fn) const
322 return splay_tree_foreach (tree, addrmap_mutable_foreach_worker, &fn);
326 /* Compare keys as CORE_ADDR * values. */
327 static int
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. */
334 if (a < b)
335 return -1;
336 else if (a == b)
337 return 0;
338 else
339 return 1;
343 static void
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);
361 /* See addrmap.h. */
363 void
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, const void *obj)
373 QUIT;
375 bool matches = payload == nullptr || payload == obj;
376 const char *addr_str = nullptr;
377 if (matches)
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),
386 addr_str);
388 previous_matched = matches;
390 return 0;
393 map->foreach (callback);
396 #if GDB_SELF_TEST
397 namespace selftests {
399 /* Convert P to CORE_ADDR. */
401 static CORE_ADDR
402 core_addr (void *p)
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) \
410 do \
412 for (unsigned i = LOW; i <= HIGH; ++i) \
413 SELF_CHECK (MAP->find (core_addr (&ARRAY[i])) == VAL); \
415 while (0)
417 /* Entry point for addrmap unit tests. */
419 static void
420 test_addrmap ()
422 /* We'll verify using the addresses of the elements of this array. */
423 char array[20];
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 auto map = std::make_unique<struct 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. */
444 struct addrmap *map2
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);
460 else
461 SELF_CHECK (false);
462 return 0;
464 SELF_CHECK (map->foreach (callback) == 0);
465 SELF_CHECK (map2->foreach (callback) == 0);
467 /* Relocate fixed addrmap. */
468 map2->relocate (1);
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 ();
485 void
486 _initialize_addrmap ()
488 #if GDB_SELF_TEST
489 selftests::register_test ("addrmap", selftests::test_addrmap);
490 #endif /* GDB_SELF_TEST */