Update copyright year range in all GDB files.
[deliverable/binutils-gdb.git] / sim / common / sim-arange.c
CommitLineData
c906108c 1/* Address ranges.
b811d2c2 2 Copyright (C) 1998-2020 Free Software Foundation, Inc.
c906108c
SS
3 Contributed by Cygnus Solutions.
4
5This file is part of the GNU Simulators.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
4744ac1b
JB
9the Free Software Foundation; either version 3 of the License, or
10(at your option) any later version.
c906108c
SS
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
4744ac1b
JB
17You should have received a copy of the GNU General Public License
18along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c 19
ef986697
SH
20#ifndef _SIM_ARANGE_C_
21#define _SIM_ARANGE_C_
c906108c
SS
22
23#include "libiberty.h"
24#include "sim-basics.h"
ef986697 25#include "sim-arange.h"
c906108c
SS
26
27#ifdef HAVE_STDLIB_H
28#include <stdlib.h>
29#endif
30
c4093a6a
JM
31#ifdef HAVE_STRING_H
32#include <string.h>
33#endif
34
c906108c
SS
35/* Insert a range. */
36
37static void
38insert_range (ADDR_SUBRANGE **pos, ADDR_SUBRANGE *asr)
39{
40 asr->next = *pos;
41 *pos = asr;
42}
43
44/* Delete a range. */
45
46static void
47delete_range (ADDR_SUBRANGE **thisasrp)
48{
49 ADDR_SUBRANGE *thisasr;
50
51 thisasr = *thisasrp;
52 *thisasrp = thisasr->next;
53
54 free (thisasr);
55}
56
57/* Add or delete an address range.
58 This code was borrowed from linux's locks.c:posix_lock_file().
59 ??? Todo: Given our simpler needs this could be simplified
60 (split into two fns). */
61
62static void
63frob_range (ADDR_RANGE *ar, address_word start, address_word end, int delete_p)
64{
65 ADDR_SUBRANGE *asr;
66 ADDR_SUBRANGE *new_asr, *new_asr2;
67 ADDR_SUBRANGE *left = NULL;
68 ADDR_SUBRANGE *right = NULL;
69 ADDR_SUBRANGE **before;
70 ADDR_SUBRANGE init_caller;
71 ADDR_SUBRANGE *caller = &init_caller;
72 int added_p = 0;
73
74 memset (caller, 0, sizeof (ADDR_SUBRANGE));
75 new_asr = ZALLOC (ADDR_SUBRANGE);
76 new_asr2 = ZALLOC (ADDR_SUBRANGE);
77
78 caller->start = start;
79 caller->end = end;
80 before = &ar->ranges;
81
82 while ((asr = *before) != NULL)
83 {
84 if (! delete_p)
85 {
86 /* Try next range if current range preceeds new one and not
87 adjacent or overlapping. */
88 if (asr->end < caller->start - 1)
89 goto next_range;
90
91 /* Break out if new range preceeds current one and not
92 adjacent or overlapping. */
93 if (asr->start > caller->end + 1)
94 break;
95
96 /* If we come here, the new and current ranges are adjacent or
97 overlapping. Make one range yielding from the lower start address
98 of both ranges to the higher end address. */
99 if (asr->start > caller->start)
100 asr->start = caller->start;
101 else
102 caller->start = asr->start;
103 if (asr->end < caller->end)
104 asr->end = caller->end;
105 else
106 caller->end = asr->end;
107
108 if (added_p)
109 {
110 delete_range (before);
111 continue;
112 }
113 caller = asr;
114 added_p = 1;
115 }
116 else /* deleting a range */
117 {
118 /* Try next range if current range preceeds new one. */
119 if (asr->end < caller->start)
120 goto next_range;
121
122 /* Break out if new range preceeds current one. */
123 if (asr->start > caller->end)
124 break;
125
126 added_p = 1;
127
128 if (asr->start < caller->start)
129 left = asr;
130
131 /* If the next range in the list has a higher end
132 address than the new one, insert the new one here. */
133 if (asr->end > caller->end)
134 {
135 right = asr;
136 break;
137 }
138 if (asr->start >= caller->start)
139 {
140 /* The new range completely replaces an old
141 one (This may happen several times). */
142 if (added_p)
143 {
144 delete_range (before);
145 continue;
146 }
147
148 /* Replace the old range with the new one. */
149 asr->start = caller->start;
150 asr->end = caller->end;
151 caller = asr;
152 added_p = 1;
153 }
154 }
155
156 /* Go on to next range. */
157 next_range:
158 before = &asr->next;
159 }
160
161 if (!added_p)
162 {
163 if (delete_p)
164 goto out;
165 new_asr->start = caller->start;
166 new_asr->end = caller->end;
167 insert_range (before, new_asr);
168 new_asr = NULL;
169 }
170 if (right)
171 {
172 if (left == right)
173 {
174 /* The new range breaks the old one in two pieces,
175 so we have to use the second new range. */
176 new_asr2->start = right->start;
177 new_asr2->end = right->end;
178 left = new_asr2;
179 insert_range (before, left);
180 new_asr2 = NULL;
181 }
182 right->start = caller->end + 1;
183 }
184 if (left)
185 {
186 left->end = caller->start - 1;
187 }
188
189 out:
190 if (new_asr)
34b47c38 191 free (new_asr);
c906108c 192 if (new_asr2)
34b47c38 193 free (new_asr2);
c906108c
SS
194}
195
196/* Free T and all subtrees. */
197
198static void
199free_search_tree (ADDR_RANGE_TREE *t)
200{
201 if (t != NULL)
202 {
203 free_search_tree (t->lower);
204 free_search_tree (t->higher);
205 free (t);
206 }
207}
208
209/* Subroutine of build_search_tree to recursively build a balanced tree.
210 ??? It's not an optimum tree though. */
211
212static ADDR_RANGE_TREE *
213build_tree_1 (ADDR_SUBRANGE **asrtab, unsigned int n)
214{
215 unsigned int mid = n / 2;
216 ADDR_RANGE_TREE *t;
217
218 if (n == 0)
219 return NULL;
220 t = (ADDR_RANGE_TREE *) xmalloc (sizeof (ADDR_RANGE_TREE));
221 t->start = asrtab[mid]->start;
222 t->end = asrtab[mid]->end;
223 if (mid != 0)
224 t->lower = build_tree_1 (asrtab, mid);
225 else
226 t->lower = NULL;
227 if (n > mid + 1)
228 t->higher = build_tree_1 (asrtab + mid + 1, n - mid - 1);
229 else
230 t->higher = NULL;
231 return t;
232}
233
234/* Build a search tree for address range AR. */
235
236static void
237build_search_tree (ADDR_RANGE *ar)
238{
239 /* ??? Simple version for now. */
240 ADDR_SUBRANGE *asr,**asrtab;
241 unsigned int i, n;
242
243 for (n = 0, asr = ar->ranges; asr != NULL; ++n, asr = asr->next)
244 continue;
245 asrtab = (ADDR_SUBRANGE **) xmalloc (n * sizeof (ADDR_SUBRANGE *));
246 for (i = 0, asr = ar->ranges; i < n; ++i, asr = asr->next)
247 asrtab[i] = asr;
248 ar->range_tree = build_tree_1 (asrtab, n);
249 free (asrtab);
250}
251
ef986697
SH
252INLINE_SIM_ARANGE\
253(void)
c906108c
SS
254sim_addr_range_add (ADDR_RANGE *ar, address_word start, address_word end)
255{
256 frob_range (ar, start, end, 0);
257
258 /* Rebuild the search tree. */
259 /* ??? Instead of rebuilding it here it could be done in a module resume
260 handler, say by first checking for a `changed' flag, assuming of course
261 this would never be done while the simulation is running. */
262 free_search_tree (ar->range_tree);
263 build_search_tree (ar);
264}
265
ef986697
SH
266INLINE_SIM_ARANGE\
267(void)
c906108c
SS
268sim_addr_range_delete (ADDR_RANGE *ar, address_word start, address_word end)
269{
270 frob_range (ar, start, end, 1);
271
272 /* Rebuild the search tree. */
273 /* ??? Instead of rebuilding it here it could be done in a module resume
274 handler, say by first checking for a `changed' flag, assuming of course
275 this would never be done while the simulation is running. */
276 free_search_tree (ar->range_tree);
277 build_search_tree (ar);
278}
279
ef986697
SH
280INLINE_SIM_ARANGE\
281(int)
c906108c
SS
282sim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr)
283{
284 ADDR_RANGE_TREE *t = ar->range_tree;
285
286 while (t != NULL)
287 {
288 if (addr < t->start)
289 t = t->lower;
290 else if (addr > t->end)
291 t = t->higher;
292 else
293 return 1;
294 }
295 return 0;
296}
297
ef986697 298#endif /* _SIM_ARANGE_C_ */
This page took 0.880281 seconds and 4 git commands to generate.