]> Git Repo - binutils.git/blob - gdb/addrmap.c
gdb: remove SYMBOL_CLASS macro, add getter
[binutils.git] / gdb / addrmap.c
1 /* addrmap.c --- implementation of address map data structure.
2
3    Copyright (C) 2007-2022 Free Software Foundation, Inc.
4
5    This file is part of GDB.
6
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.
11
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.
16
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/>.  */
19
20 #include "defs.h"
21 #include "splay-tree.h"
22 #include "gdbsupport/gdb_obstack.h"
23 #include "addrmap.h"
24 #include "gdbsupport/selftest.h"
25
26 /* Make sure splay trees can actually hold the values we want to
27    store in them.  */
28 gdb_static_assert (sizeof (splay_tree_key) >= sizeof (CORE_ADDR *));
29 gdb_static_assert (sizeof (splay_tree_value) >= sizeof (void *));
30
31 \f
32 /* The "abstract class".  */
33
34 /* Functions implementing the addrmap functions for a particular
35    implementation.  */
36 struct addrmap_funcs
37 {
38   void (*set_empty) (struct addrmap *self,
39                      CORE_ADDR start, CORE_ADDR end_inclusive,
40                      void *obj);
41   void *(*find) (struct 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);
46 };
47
48
49 struct addrmap
50 {
51   const struct addrmap_funcs *funcs;
52 };
53
54
55 void
56 addrmap_set_empty (struct addrmap *map,
57                    CORE_ADDR start, CORE_ADDR end_inclusive,
58                    void *obj)
59 {
60   map->funcs->set_empty (map, start, end_inclusive, obj);
61 }
62
63
64 void *
65 addrmap_find (struct addrmap *map, CORE_ADDR addr)
66 {
67   return map->funcs->find (map, addr);
68 }
69
70
71 struct addrmap *
72 addrmap_create_fixed (struct addrmap *original, struct obstack *obstack)
73 {
74   return original->funcs->create_fixed (original, obstack);
75 }
76
77
78 /* Relocate all the addresses in MAP by OFFSET.  (This can be applied
79    to either mutable or immutable maps.)  */
80 void
81 addrmap_relocate (struct addrmap *map, CORE_ADDR offset)
82 {
83   map->funcs->relocate (map, offset);
84 }
85
86
87 int
88 addrmap_foreach (struct addrmap *map, addrmap_foreach_fn fn)
89 {
90   return map->funcs->foreach (map, fn);
91 }
92 \f
93 /* Fixed address maps.  */
94
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
97    something else.  */
98 struct addrmap_transition
99 {
100   CORE_ADDR addr;
101   void *value;
102 };
103
104
105 struct addrmap_fixed
106 {
107   struct addrmap addrmap;
108
109   /* The number of transitions in TRANSITIONS.  */
110   size_t num_transitions;
111
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];
118 };
119
120
121 static void
122 addrmap_fixed_set_empty (struct addrmap *self,
123                    CORE_ADDR start, CORE_ADDR end_inclusive,
124                    void *obj)
125 {
126   internal_error (__FILE__, __LINE__,
127                   "addrmap_fixed_set_empty: "
128                   "fixed addrmaps can't be changed\n");
129 }
130
131
132 static void *
133 addrmap_fixed_find (struct addrmap *self, CORE_ADDR addr)
134 {
135   struct addrmap_fixed *map = (struct addrmap_fixed *) self;
136   struct addrmap_transition *bottom = &map->transitions[0];
137   struct addrmap_transition *top = &map->transitions[map->num_transitions - 1];
138
139   while (bottom < top)
140     {
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
144          < addr).  */
145       struct addrmap_transition *mid = top - (top - bottom) / 2;
146
147       if (mid->addr == addr)
148         {
149           bottom = mid;
150           break;
151         }
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.  */
156         bottom = mid;
157       else
158         top = mid - 1;
159     }
160
161   return bottom->value;
162 }
163
164
165 static struct addrmap *
166 addrmap_fixed_create_fixed (struct addrmap *self, struct obstack *obstack)
167 {
168   internal_error (__FILE__, __LINE__,
169                   _("addrmap_create_fixed is not implemented yet "
170                     "for fixed addrmaps"));
171 }
172
173
174 static void
175 addrmap_fixed_relocate (struct addrmap *self, CORE_ADDR offset)
176 {
177   struct addrmap_fixed *map = (struct addrmap_fixed *) self;
178   size_t i;
179
180   for (i = 0; i < map->num_transitions; i++)
181     map->transitions[i].addr += offset;
182 }
183
184
185 static int
186 addrmap_fixed_foreach (struct addrmap *self, addrmap_foreach_fn fn)
187 {
188   struct addrmap_fixed *map = (struct addrmap_fixed *) self;
189   size_t i;
190
191   for (i = 0; i < map->num_transitions; i++)
192     {
193       int res = fn (map->transitions[i].addr, map->transitions[i].value);
194
195       if (res != 0)
196         return res;
197     }
198
199   return 0;
200 }
201
202
203 static const struct addrmap_funcs addrmap_fixed_funcs =
204 {
205   addrmap_fixed_set_empty,
206   addrmap_fixed_find,
207   addrmap_fixed_create_fixed,
208   addrmap_fixed_relocate,
209   addrmap_fixed_foreach
210 };
211
212
213 \f
214 /* Mutable address maps.  */
215
216 struct addrmap_mutable
217 {
218   struct addrmap addrmap;
219
220   /* The obstack to use for allocations for this map.  */
221   struct obstack *obstack;
222
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.
225
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 
228      simplify enough.)
229
230      The last region is assumed to end at CORE_ADDR_MAX.
231
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.  */
240   splay_tree tree;
241
242   /* A freelist for splay tree nodes, allocated on obstack, and
243      chained together by their 'right' pointers.  */
244   splay_tree_node free_nodes;
245 };
246
247
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)
251 {
252   CORE_ADDR *key = XOBNEW (map->obstack, CORE_ADDR);
253
254   *key = addr;
255   return (splay_tree_key) key;
256 }
257
258
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)
262 {
263   return splay_tree_lookup (map->tree, (splay_tree_key) &addr);
264 }
265
266
267 static splay_tree_node
268 addrmap_splay_tree_predecessor (struct addrmap_mutable *map, CORE_ADDR addr)
269 {
270   return splay_tree_predecessor (map->tree, (splay_tree_key) &addr);
271 }
272
273
274 static splay_tree_node
275 addrmap_splay_tree_successor (struct addrmap_mutable *map, CORE_ADDR addr)
276 {
277   return splay_tree_successor (map->tree, (splay_tree_key) &addr);
278 }
279
280
281 static void
282 addrmap_splay_tree_remove (struct addrmap_mutable *map, CORE_ADDR addr)
283 {
284   splay_tree_remove (map->tree, (splay_tree_key) &addr);
285 }
286
287
288 static CORE_ADDR
289 addrmap_node_key (splay_tree_node node)
290 {
291   return * (CORE_ADDR *) node->key;
292 }
293
294
295 static void *
296 addrmap_node_value (splay_tree_node node)
297 {
298   return (void *) node->value;
299 }
300
301
302 static void
303 addrmap_node_set_value (splay_tree_node node, void *value)
304 {
305   node->value = (splay_tree_value) value;
306 }
307
308
309 static void
310 addrmap_splay_tree_insert (struct addrmap_mutable *map,
311                            CORE_ADDR key, void *value)
312 {
313   splay_tree_insert (map->tree,
314                      allocate_key (map, key),
315                      (splay_tree_value) value);
316 }
317
318
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.  */
322 static void
323 force_transition (struct addrmap_mutable *self, CORE_ADDR addr)
324 {
325   splay_tree_node n
326     = addrmap_splay_tree_lookup (self, addr);
327
328   if (! n)
329     {
330       n = addrmap_splay_tree_predecessor (self, addr);
331       addrmap_splay_tree_insert (self, addr,
332                                  n ? addrmap_node_value (n) : NULL);
333     }
334 }
335
336
337 static void
338 addrmap_mutable_set_empty (struct addrmap *self,
339                            CORE_ADDR start, CORE_ADDR end_inclusive,
340                            void *obj)
341 {
342   struct addrmap_mutable *map = (struct addrmap_mutable *) self;
343   splay_tree_node n, next;
344   void *prior_value;
345
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
350      no-op.)  */
351   gdb_assert (obj);
352
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.  */
357
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);
362
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)))
367     {
368       if (! addrmap_node_value (n))
369         addrmap_node_set_value (n, obj);
370     }
371
372   /* Walk the area again, removing transitions from any value to
373      itself.  Be sure to visit both the transitions we forced
374      above.  */
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);
380        n = next)
381     {
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));
385       else
386         prior_value = addrmap_node_value (n);
387     }
388 }
389
390
391 static void *
392 addrmap_mutable_find (struct addrmap *self, CORE_ADDR addr)
393 {
394   struct addrmap_mutable *map = (struct addrmap_mutable *) self;
395   splay_tree_node n = addrmap_splay_tree_lookup (map, addr);
396   if (n != nullptr)
397     {
398       gdb_assert (addrmap_node_key (n) == addr);
399       return addrmap_node_value (n);
400     }
401
402   n = addrmap_splay_tree_predecessor (map, addr);
403   if (n != nullptr)
404     {
405       gdb_assert (addrmap_node_key (n) < addr);
406       return addrmap_node_value (n);
407     }
408
409   return nullptr;
410 }
411
412
413 /* A function to pass to splay_tree_foreach to count the number of nodes
414    in the tree.  */
415 static int
416 splay_foreach_count (splay_tree_node n, void *closure)
417 {
418   size_t *count = (size_t *) closure;
419
420   (*count)++;
421   return 0;
422 }
423
424
425 /* A function to pass to splay_tree_foreach to copy entries into a
426    fixed address map.  */
427 static int
428 splay_foreach_copy (splay_tree_node n, void *closure)
429 {
430   struct addrmap_fixed *fixed = (struct addrmap_fixed *) closure;
431   struct addrmap_transition *t = &fixed->transitions[fixed->num_transitions];
432
433   t->addr = addrmap_node_key (n);
434   t->value = addrmap_node_value (n);
435   fixed->num_transitions++;
436
437   return 0;
438 }
439
440
441 static struct addrmap *
442 addrmap_mutable_create_fixed (struct addrmap *self, struct obstack *obstack)
443 {
444   struct addrmap_mutable *mutable_obj = (struct addrmap_mutable *) self;
445   struct addrmap_fixed *fixed;
446   size_t num_transitions;
447   size_t alloc_len;
448
449   /* Count the number of transitions in the tree.  */
450   num_transitions = 0;
451   splay_tree_foreach (mutable_obj->tree, splay_foreach_count, &num_transitions);
452
453   /* Include an extra entry for the transition at zero (which fixed
454      maps have, but mutable maps do not.)  */
455   num_transitions++;
456
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;
464
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);
468
469   /* We should have filled the array.  */
470   gdb_assert (fixed->num_transitions == num_transitions);
471
472   return (struct addrmap *) fixed;
473 }
474
475
476 static void
477 addrmap_mutable_relocate (struct addrmap *self, CORE_ADDR offset)
478 {
479   /* Not needed yet.  */
480   internal_error (__FILE__, __LINE__,
481                   _("addrmap_relocate is not implemented yet "
482                     "for mutable addrmaps"));
483 }
484
485
486 /* This is a splay_tree_foreach_fn.  */
487
488 static int
489 addrmap_mutable_foreach_worker (splay_tree_node node, void *data)
490 {
491   addrmap_foreach_fn *fn = (addrmap_foreach_fn *) data;
492
493   return (*fn) (addrmap_node_key (node), addrmap_node_value (node));
494 }
495
496
497 static int
498 addrmap_mutable_foreach (struct addrmap *self, addrmap_foreach_fn fn)
499 {
500   struct addrmap_mutable *mutable_obj = (struct addrmap_mutable *) self;
501
502   return splay_tree_foreach (mutable_obj->tree, addrmap_mutable_foreach_worker,
503                              &fn);
504 }
505
506
507 static const struct addrmap_funcs addrmap_mutable_funcs =
508 {
509   addrmap_mutable_set_empty,
510   addrmap_mutable_find,
511   addrmap_mutable_create_fixed,
512   addrmap_mutable_relocate,
513   addrmap_mutable_foreach
514 };
515
516
517 static void *
518 splay_obstack_alloc (int size, void *closure)
519 {
520   struct addrmap_mutable *map = (struct addrmap_mutable *) closure;
521   splay_tree_node n;
522
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));
527
528   if (map->free_nodes)
529     {
530       n = map->free_nodes;
531       map->free_nodes = n->right;
532       return n;
533     }
534   else
535     return obstack_alloc (map->obstack, size);
536 }
537
538
539 static void
540 splay_obstack_free (void *obj, void *closure)
541 {
542   struct addrmap_mutable *map = (struct addrmap_mutable *) closure;
543   splay_tree_node n = (splay_tree_node) obj;
544
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;
549   map->free_nodes = n;
550 }
551
552
553 /* Compare keys as CORE_ADDR * values.  */
554 static int
555 splay_compare_CORE_ADDR_ptr (splay_tree_key ak, splay_tree_key bk)
556 {
557   CORE_ADDR a = * (CORE_ADDR *) ak;
558   CORE_ADDR b = * (CORE_ADDR *) bk;
559
560   /* We can't just return a-b here, because of over/underflow.  */
561   if (a < b)
562     return -1;
563   else if (a == b)
564     return 0;
565   else
566     return 1;
567 }
568
569
570 struct addrmap *
571 addrmap_create_mutable (struct obstack *obstack)
572 {
573   struct addrmap_mutable *map = XOBNEW (obstack, struct addrmap_mutable);
574
575   map->addrmap.funcs = &addrmap_mutable_funcs;
576   map->obstack = obstack;
577
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;
582
583   map->tree = splay_tree_new_with_allocator (splay_compare_CORE_ADDR_ptr,
584                                              NULL, /* no delete key */
585                                              NULL, /* no delete value */
586                                              splay_obstack_alloc,
587                                              splay_obstack_free,
588                                              map);
589
590   return (struct addrmap *) map;
591 }
592
593 /* See addrmap.h.  */
594
595 void
596 addrmap_dump (struct addrmap *map, struct ui_file *outfile, void *payload)
597 {
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;
602
603   auto callback = [&] (CORE_ADDR start_addr, void *obj)
604   {
605     QUIT;
606
607     bool matches = payload == nullptr || payload == obj;
608     const char *addr_str = nullptr;
609     if (matches)
610       addr_str = host_address_to_string (obj);
611     else if (previous_matched)
612       addr_str = "<ends here>";
613
614     if (matches || previous_matched)
615       fprintf_filtered (outfile, "  %s%s %s\n",
616                         payload != nullptr ? "  " : "",
617                         core_addr_to_string (start_addr),
618                         addr_str);
619
620     previous_matched = matches;
621
622     return 0;
623   };
624
625   addrmap_foreach (map, callback);
626 }
627
628 #if GDB_SELF_TEST
629 namespace selftests {
630
631 /* Convert P to CORE_ADDR.  */
632
633 static CORE_ADDR
634 core_addr (void *p)
635 {
636   return (CORE_ADDR)(uintptr_t)p;
637 }
638
639 /* Check that &ARRAY[LOW]..&ARRAY[HIGH] has VAL in MAP.  */
640
641 #define CHECK_ADDRMAP_FIND(MAP, ARRAY, LOW, HIGH, VAL)                  \
642   do                                                                    \
643     {                                                                   \
644       for (unsigned i = LOW; i <= HIGH; ++i)                            \
645         SELF_CHECK (addrmap_find (MAP, core_addr (&ARRAY[i])) == VAL);  \
646     }                                                                   \
647   while (0)
648
649 /* Entry point for addrmap unit tests.  */
650
651 static void
652 test_addrmap ()
653 {
654   /* We'll verify using the addresses of the elements of this array.  */
655   char array[20];
656
657   /* We'll verify using these values stored into the map.  */
658   void *val1 = &array[1];
659   void *val2 = &array[2];
660
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);
666
667   /* Check initial state.  */
668   CHECK_ADDRMAP_FIND (map, array, 0, 19, nullptr);
669
670   /* Insert address range into mutable addrmap.  */
671   addrmap_set_empty (map, core_addr (&array[10]), core_addr (&array[12]),
672                      val1);
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);
676
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);
683
684   /* Iterate over both addrmaps.  */
685   auto callback = [&] (CORE_ADDR start_addr, void *obj)
686     {
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);
693       else
694         SELF_CHECK (false);
695       return 0;
696     };
697   SELF_CHECK (addrmap_foreach (map, callback) == 0);
698   SELF_CHECK (addrmap_foreach (map2, callback) == 0);
699
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);
705
706   /* Insert partially overlapping address range into mutable addrmap.  */
707   addrmap_set_empty (map, core_addr (&array[11]), core_addr (&array[13]),
708                      val2);
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);
713
714   /* Cleanup.  */
715   obstack_free (&temp_obstack, NULL);
716 }
717
718 } // namespace selftests
719 #endif /* GDB_SELF_TEST */
720
721 void _initialize_addrmap ();
722 void
723 _initialize_addrmap ()
724 {
725 #if GDB_SELF_TEST
726   selftests::register_test ("addrmap", selftests::test_addrmap);
727 #endif /* GDB_SELF_TEST */
728 }
This page took 0.064365 seconds and 4 git commands to generate.