/src/libdwarf/src/lib/libdwarf/dwarf_ranges.c
Line | Count | Source |
1 | | /* |
2 | | Copyright (C) 2008-2020 David Anderson. All Rights Reserved. |
3 | | Portions Copyright 2012 SN Systems Ltd. All rights reserved. |
4 | | |
5 | | This program is free software; you can redistribute it |
6 | | and/or modify it under the terms of version 2.1 of the |
7 | | GNU Lesser General Public License as published by the Free |
8 | | Software Foundation. |
9 | | |
10 | | This program is distributed in the hope that it would be |
11 | | useful, but WITHOUT ANY WARRANTY; without even the implied |
12 | | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
13 | | PURPOSE. |
14 | | |
15 | | Further, this software is distributed without any warranty |
16 | | that it is free of the rightful claim of any third person |
17 | | regarding infringement or the like. Any license provided |
18 | | herein, whether implied or otherwise, applies only to this |
19 | | software file. Patent licenses, if any, provided herein |
20 | | do not apply to combinations of this program with other |
21 | | software, or any other product whatsoever. |
22 | | |
23 | | You should have received a copy of the GNU Lesser General |
24 | | Public License along with this program; if not, write the |
25 | | Free Software Foundation, Inc., 51 Franklin Street - Fifth |
26 | | Floor, Boston MA 02110-1301, USA. |
27 | | |
28 | | */ |
29 | | |
30 | | #include <config.h> |
31 | | |
32 | | #include <stdlib.h> /* calloc() free() */ |
33 | | #include <stdio.h> /* printf debugging */ |
34 | | |
35 | | #if defined(_WIN32) && defined(HAVE_STDAFX_H) |
36 | | #include "stdafx.h" |
37 | | #endif /* HAVE_STDAFX_H */ |
38 | | |
39 | | #include "dwarf.h" |
40 | | #include "libdwarf.h" |
41 | | #include "dwarf_local_malloc.h" |
42 | | #include "libdwarf_private.h" |
43 | | #include "dwarf_base_types.h" |
44 | | #include "dwarf_opaque.h" |
45 | | #include "dwarf_alloc.h" |
46 | | #include "dwarf_error.h" |
47 | | #include "dwarf_util.h" |
48 | | #include "dwarf_string.h" |
49 | | |
50 | | #define DEBUG_RANGES 1 |
51 | | #undef DEBUG_RANGES |
52 | | |
53 | | struct ranges_entry { |
54 | | struct ranges_entry *next; |
55 | | Dwarf_Ranges cur; |
56 | | }; |
57 | | |
58 | | static void |
59 | | free_allocated_ranges( struct ranges_entry *base) |
60 | 1.85k | { |
61 | 1.85k | struct ranges_entry *cur = 0; |
62 | 1.85k | struct ranges_entry *next = 0; |
63 | 44.9k | for ( cur = base ; cur ; cur = next ) { |
64 | 43.1k | next = cur->next; |
65 | 43.1k | free(cur); |
66 | 43.1k | } |
67 | 1.85k | } |
68 | | |
69 | | /* We encapsulate the macro use so we can |
70 | | free local malloc resources that would otherwise |
71 | | leak. See the call points below. */ |
72 | | static int |
73 | | read_unaligned_addr_check(Dwarf_Debug dbg, |
74 | | Dwarf_Addr *addr_out, |
75 | | Dwarf_Small *rangeptr, |
76 | | unsigned address_size, |
77 | | Dwarf_Error *error, |
78 | | Dwarf_Small *section_end) |
79 | 86.2k | { |
80 | 86.2k | Dwarf_Addr a = 0; |
81 | | |
82 | 86.2k | READ_UNALIGNED_CK(dbg,a, |
83 | 86.2k | Dwarf_Addr, rangeptr, |
84 | 86.2k | address_size, |
85 | 86.2k | error,section_end); |
86 | 86.2k | *addr_out = a; |
87 | 86.2k | return DW_DLV_OK; |
88 | 86.2k | } |
89 | | /* As of DWARF5 the ranges section each range list set has |
90 | | a range-list-table header. See "7.28 Range List Table" |
91 | | in the DWARF5 standard. |
92 | | For DWARF5 the offset should be the offset of |
93 | | the range-list-table-header for that range list. |
94 | | For DWARF3 and DWARF4 the offset has to be that |
95 | | of a range list. |
96 | | */ |
97 | | /* Ranges and pc values can be in a split dwarf object. |
98 | | In that case the appropriate values need to be |
99 | | incremented by data from the executable in |
100 | | the compilation unit with the same dwo_id. |
101 | | |
102 | | We return an error which is on the incoming dbg, not |
103 | | the possibly-tied-dbg localdbg. |
104 | | If incoming die is NULL there is no context, so do not look |
105 | | for a tied file, and address_size is the size |
106 | | of the overall object, not the address_size of the context. */ |
107 | 42.0k | #define MAX_ADDR ((address_size == 8)? \ |
108 | 42.0k | 0xffffffffffffffffULL:0xffffffff) |
109 | | /* New 10 September 2020 to accommodate the |
110 | | GNU extension of DWARF4 split-dwarf. |
111 | | The actual_offset field is set by the function |
112 | | to the actual final offset of the ranges |
113 | | in the separate tied (a.out) file. */ |
114 | | int dwarf_get_ranges_b(Dwarf_Debug dbg, |
115 | | Dwarf_Off rangesoffset, |
116 | | Dwarf_Die die, |
117 | | Dwarf_Off *actual_offset /* in .debug_ranges */, |
118 | | Dwarf_Ranges ** rangesbuf, |
119 | | Dwarf_Signed * listlen, |
120 | | Dwarf_Unsigned * bytecount, |
121 | | Dwarf_Error * error) |
122 | 8.04k | { |
123 | 8.04k | Dwarf_Small *rangeptr = 0; |
124 | 8.04k | Dwarf_Small *beginrangeptr = 0; |
125 | 8.04k | Dwarf_Small *section_end = 0; |
126 | 8.04k | unsigned entry_count = 0; |
127 | 8.04k | struct ranges_entry *base = 0; |
128 | 8.04k | struct ranges_entry *last = 0; |
129 | 8.04k | struct ranges_entry *curre = 0; |
130 | 8.04k | Dwarf_Ranges * ranges_data_out = 0; |
131 | 8.04k | unsigned copyindex = 0; |
132 | 8.04k | Dwarf_Half address_size = 0; |
133 | 8.04k | int res = DW_DLV_ERROR; |
134 | 8.04k | Dwarf_Unsigned ranges_base = 0; |
135 | 8.04k | Dwarf_Debug localdbg = dbg; |
136 | | |
137 | | /* default for dwarf_get_ranges() */ |
138 | 8.04k | Dwarf_Half die_version = 3; |
139 | | |
140 | 8.04k | Dwarf_Half offset_size= 4; |
141 | 8.04k | Dwarf_CU_Context cucontext = 0; |
142 | | |
143 | 8.04k | CHECK_DBG(dbg,error,"dwarf_get_ranges_b()"); |
144 | 8.04k | address_size = localdbg->de_pointer_size; /* default */ |
145 | 8.04k | if (die) { |
146 | | /* printing DW_AT_ranges attribute. and the local DIE |
147 | | it belongs to. |
148 | | If we wind up using the tied file the die_version |
149 | | had better match! It cannot be other than a match. |
150 | | Can return DW_DLV_ERROR, not DW_DLV_NO_ENTRY. |
151 | | Add err code if error. Version comes from the |
152 | | cu context, not the DIE itself. */ |
153 | 8.04k | res = dwarf_get_version_of_die(die,&die_version, |
154 | 8.04k | &offset_size); |
155 | 8.04k | if (res == DW_DLV_ERROR) { |
156 | 0 | _dwarf_error(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT); |
157 | 0 | return DW_DLV_ERROR; |
158 | 0 | } |
159 | 8.04k | if (!die->di_cu_context) { |
160 | 0 | _dwarf_error(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT); |
161 | 0 | return DW_DLV_ERROR; |
162 | 0 | } |
163 | 8.04k | cucontext = die->di_cu_context; |
164 | | /* The DW4 ranges base was never used in GNU |
165 | | but did get emitted, the note says, but |
166 | | the note is probably obsolete (so, now wrong). |
167 | | http://llvm.1065342.n5.nabble.com/DebugInfo\ |
168 | | -DW-AT-GNU-ranges-base-in-non-fission-\ |
169 | | td64194.html |
170 | | HOWEVER: in dw4 GNU fission extension |
171 | | it is used and matters. |
172 | | */ |
173 | | /* ranges_base was merged from tied context. |
174 | | Otherwise it is zero. But not if |
175 | | the current die is the skeleton */ |
176 | 8.04k | if (cucontext->cc_unit_type != DW_UT_skeleton) { |
177 | 7.71k | ranges_base = cucontext->cc_ranges_base; |
178 | 7.71k | } |
179 | 8.04k | rangesoffset += ranges_base; |
180 | 8.04k | address_size = cucontext->cc_address_size; |
181 | 8.04k | } else { |
182 | | /* Printing by raw offset |
183 | | The caller will use the bytecount to |
184 | | increment to the next part of .debug_ranges |
185 | | and will call again with the next offset */ |
186 | 0 | } |
187 | | |
188 | 8.04k | localdbg = dbg; |
189 | 8.04k | res = _dwarf_load_section(localdbg, &localdbg->de_debug_ranges, |
190 | 8.04k | error); |
191 | 8.04k | if (res == DW_DLV_ERROR) { |
192 | 165 | return res; |
193 | 165 | } |
194 | | /* FIX. HAS_TIED or ? */ |
195 | 7.87k | if (res == DW_DLV_NO_ENTRY) { |
196 | | /* data is in a.out, not dwp */ |
197 | 5.34k | if (!DBG_HAS_SECONDARY(dbg)) { |
198 | 5.34k | return DW_DLV_NO_ENTRY; |
199 | 5.34k | } |
200 | 0 | localdbg = dbg->de_secondary_dbg; |
201 | 0 | res = _dwarf_load_section(localdbg, |
202 | 0 | &localdbg->de_debug_ranges, error); |
203 | 0 | if (res == DW_DLV_ERROR) { |
204 | | /* Error will automatically be put on dbg (main |
205 | | dbg), not localdbg (tieddbg) as of late 2024. */ |
206 | 0 | return res; |
207 | 0 | } |
208 | 0 | if (res == DW_DLV_NO_ENTRY) { |
209 | 0 | return res; |
210 | 0 | } |
211 | 0 | } |
212 | | |
213 | | /* Be safe in case adding rangesoffset and rangebase |
214 | | overflows. */ |
215 | 2.53k | if (rangesoffset >= localdbg->de_debug_ranges.dss_size) { |
216 | | /* Documented behavior in libdwarf2.1.mm */ |
217 | 675 | return DW_DLV_NO_ENTRY; |
218 | 675 | } |
219 | 1.85k | if (ranges_base >= localdbg->de_debug_ranges.dss_size) { |
220 | 0 | dwarfstring m; |
221 | |
|
222 | 0 | dwarfstring_constructor(&m); |
223 | 0 | dwarfstring_append_printf_u(&m, |
224 | 0 | "DW_DLE_DEBUG_RANGES_OFFSET_BAD: " |
225 | 0 | " ranges base is 0x%lx ",ranges_base); |
226 | 0 | dwarfstring_append_printf_u(&m, |
227 | 0 | " and section size is 0x%lx.", |
228 | 0 | localdbg->de_debug_ranges.dss_size); |
229 | 0 | _dwarf_error_string(dbg, error, |
230 | 0 | DW_DLE_DEBUG_RANGES_OFFSET_BAD, |
231 | 0 | dwarfstring_string(&m)); |
232 | 0 | dwarfstring_destructor(&m); |
233 | 0 | return DW_DLV_ERROR; |
234 | 0 | } |
235 | 1.85k | if (rangesoffset >= localdbg->de_debug_ranges.dss_size) { |
236 | 0 | dwarfstring m; |
237 | |
|
238 | 0 | dwarfstring_constructor(&m); |
239 | 0 | dwarfstring_append_printf_u(&m, |
240 | 0 | "DW_DLE_DEBUG_RANGES_OFFSET_BAD: " |
241 | 0 | " ranges base+offset is 0x%lx ", |
242 | 0 | ranges_base+rangesoffset); |
243 | 0 | dwarfstring_append_printf_u(&m, |
244 | 0 | " and section size is 0x%lx.", |
245 | 0 | localdbg->de_debug_ranges.dss_size); |
246 | 0 | _dwarf_error_string(dbg, error, |
247 | 0 | DW_DLE_DEBUG_RANGES_OFFSET_BAD, |
248 | 0 | dwarfstring_string(&m)); |
249 | 0 | dwarfstring_destructor(&m); |
250 | 0 | return DW_DLV_ERROR; |
251 | 0 | } |
252 | | |
253 | | /* tied address_size must match the dwo address_size */ |
254 | 1.85k | section_end = localdbg->de_debug_ranges.dss_data + |
255 | 1.85k | localdbg->de_debug_ranges.dss_size; |
256 | 1.85k | rangeptr = localdbg->de_debug_ranges.dss_data; |
257 | 1.85k | rangeptr += rangesoffset; |
258 | 1.85k | beginrangeptr = rangeptr; |
259 | | |
260 | 43.8k | for (;;) { |
261 | 43.8k | struct ranges_entry * re = 0; |
262 | | |
263 | 43.8k | if (rangeptr == section_end) { |
264 | 406 | break; |
265 | 406 | } |
266 | 43.4k | if (rangeptr > section_end) { |
267 | 0 | dwarfstring m; |
268 | |
|
269 | 0 | free_allocated_ranges(base); |
270 | 0 | dwarfstring_constructor(&m); |
271 | 0 | dwarfstring_append(&m, |
272 | 0 | "DW_DLE_DEBUG_RANGES_OFFSET_BAD: " |
273 | 0 | " ranges pointer ran off the end " |
274 | 0 | "of the section"); |
275 | 0 | _dwarf_error_string(dbg, error, |
276 | 0 | DW_DLE_DEBUG_RANGES_OFFSET_BAD, |
277 | 0 | dwarfstring_string(&m)); |
278 | 0 | dwarfstring_destructor(&m); |
279 | 0 | return DW_DLV_ERROR; |
280 | 0 | } |
281 | 43.4k | re = calloc(1, sizeof(struct ranges_entry)); |
282 | 43.4k | if (!re) { |
283 | 0 | free_allocated_ranges(base); |
284 | 0 | _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM); |
285 | 0 | return DW_DLV_ERROR; |
286 | 0 | } |
287 | 43.4k | if ((rangeptr + (2*address_size)) > section_end) { |
288 | 373 | free(re); |
289 | 373 | free_allocated_ranges(base); |
290 | 373 | _dwarf_error_string(dbg, error, |
291 | 373 | DW_DLE_DEBUG_RANGES_OFFSET_BAD, |
292 | 373 | "DW_DLE_DEBUG_RANGES_OFFSET_BAD: " |
293 | 373 | " Not at the end of the ranges section " |
294 | 373 | " but there is not enough room in the section " |
295 | 373 | " for the next ranges entry"); |
296 | 373 | return DW_DLV_ERROR; |
297 | 373 | } |
298 | 43.1k | entry_count++; |
299 | 43.1k | res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr1, |
300 | 43.1k | rangeptr, address_size,error,section_end); |
301 | 43.1k | if (res != DW_DLV_OK) { |
302 | 0 | free(re); |
303 | 0 | free_allocated_ranges(base); |
304 | 0 | return res; |
305 | 0 | } |
306 | 43.1k | rangeptr += address_size; |
307 | 43.1k | res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr2, |
308 | 43.1k | rangeptr, address_size,error,section_end); |
309 | 43.1k | if (res != DW_DLV_OK) { |
310 | 0 | free(re); |
311 | 0 | free_allocated_ranges(base); |
312 | 0 | return res; |
313 | 0 | } |
314 | 43.1k | rangeptr += address_size; |
315 | 43.1k | if (!base) { |
316 | 1.76k | base = re; |
317 | 1.76k | last = re; |
318 | 41.3k | } else { |
319 | 41.3k | last->next = re; |
320 | 41.3k | last = re; |
321 | 41.3k | } |
322 | 43.1k | if (re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) { |
323 | 1.08k | re->cur.dwr_type = DW_RANGES_END; |
324 | 1.08k | break; |
325 | 42.0k | } else if (re->cur.dwr_addr1 == MAX_ADDR) { |
326 | 1.38k | re->cur.dwr_type = DW_RANGES_ADDRESS_SELECTION; |
327 | 40.6k | } else { |
328 | 40.6k | re->cur.dwr_type = DW_RANGES_ENTRY; |
329 | 40.6k | } |
330 | 43.1k | } |
331 | | |
332 | | /* We return ranges on dbg, so use that to allocate. */ |
333 | 1.48k | ranges_data_out = (Dwarf_Ranges *) |
334 | 1.48k | _dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count); |
335 | 1.48k | if (!ranges_data_out) { |
336 | | /* Error, apply to original, not local dbg. */ |
337 | 0 | free_allocated_ranges(base); |
338 | 0 | _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM); |
339 | 0 | return DW_DLV_ERROR; |
340 | 0 | } |
341 | 1.48k | curre = base; |
342 | 1.48k | *rangesbuf = ranges_data_out; |
343 | 1.48k | *listlen = entry_count; |
344 | 31.9k | for (copyindex = 0; curre && (copyindex < entry_count); |
345 | 30.5k | ++copyindex,++ranges_data_out,curre=curre->next) { |
346 | 30.5k | *ranges_data_out = curre->cur; |
347 | 30.5k | } |
348 | | /* ASSERT: curre == NULL */ |
349 | 1.48k | free_allocated_ranges(base); |
350 | 1.48k | base = 0; |
351 | | /* Callers will often not care about the bytes used. */ |
352 | 1.48k | if (actual_offset) { |
353 | 1.48k | *actual_offset = rangesoffset; |
354 | 1.48k | } |
355 | 1.48k | if (bytecount) { |
356 | 1.48k | *bytecount = rangeptr - beginrangeptr; |
357 | 1.48k | } |
358 | 1.48k | return DW_DLV_OK; |
359 | 1.48k | } |
360 | | |
361 | | void |
362 | | dwarf_dealloc_ranges(Dwarf_Debug dbg, Dwarf_Ranges * rangesbuf, |
363 | | Dwarf_Signed rangecount) |
364 | 1.48k | { |
365 | 1.48k | (void)rangecount; |
366 | 1.48k | dwarf_dealloc(dbg,rangesbuf, DW_DLA_RANGES); |
367 | 1.48k | } |
368 | | |
369 | | /* In the past, determined DIE base_address, |
370 | | but that was wrong. |
371 | | Only a CU_die DW_AT_low_pc can provide |
372 | | a CU-wide base address and that is done when a CU is first |
373 | | read, and available as cucontext->cc_base_address |
374 | | and cc_base_address_present. */ |
375 | | static int |
376 | | _dwarf_determine_die_range_offset(Dwarf_Debug dw_dbg, |
377 | | Dwarf_Die dw_die, |
378 | | Dwarf_Bool *have_die_ranges_offset, |
379 | | Dwarf_Unsigned *die_ranges_offset, |
380 | | Dwarf_Bool *have_die_base_addr, |
381 | | Dwarf_Unsigned *die_base_addr, |
382 | | Dwarf_Error *dw_error) |
383 | 0 | { |
384 | 0 | Dwarf_Bool hasatranges = FALSE; |
385 | 0 | Dwarf_Attribute attr = 0; |
386 | 0 | Dwarf_Unsigned rangeoffset_local = 0; |
387 | 0 | int res = 0; |
388 | 0 | Dwarf_CU_Context cucon = 0; |
389 | |
|
390 | 0 | res = dwarf_hasattr(dw_die,DW_AT_ranges, &hasatranges,dw_error); |
391 | 0 | if (res != DW_DLV_OK) { |
392 | 0 | return res; |
393 | 0 | } |
394 | 0 | if (!hasatranges) { |
395 | | /* Give up, this die not directly relevant. */ |
396 | 0 | return res; |
397 | 0 | } |
398 | 0 | res = dwarf_attr(dw_die,DW_AT_ranges,&attr,dw_error); |
399 | 0 | if (res != DW_DLV_OK) { |
400 | 0 | if (res == DW_DLV_ERROR) { |
401 | 0 | dwarf_dealloc_error(dw_dbg,*dw_error); |
402 | 0 | *dw_error = 0; |
403 | 0 | } |
404 | 0 | return res; |
405 | 0 | } |
406 | 0 | res = dwarf_global_formref(attr, |
407 | 0 | &rangeoffset_local, dw_error); |
408 | 0 | if (res != DW_DLV_OK) { |
409 | 0 | if (res == DW_DLV_ERROR) { |
410 | 0 | dwarf_dealloc_attribute(attr); |
411 | 0 | dwarf_dealloc_error(dw_dbg,*dw_error); |
412 | 0 | *dw_error = 0; |
413 | 0 | return res; |
414 | 0 | } |
415 | 0 | } |
416 | 0 | cucon = dw_die->di_cu_context; |
417 | 0 | if (cucon->cc_base_address_present) { |
418 | 0 | *die_base_addr = cucon->cc_base_address; |
419 | 0 | *have_die_base_addr = TRUE; |
420 | 0 | } |
421 | | /* rangeoffset_local was set . */ |
422 | 0 | dwarf_dealloc_attribute(attr); |
423 | 0 | attr = 0; |
424 | 0 | *have_die_ranges_offset = TRUE; |
425 | 0 | *die_ranges_offset = rangeoffset_local; |
426 | 0 | return DW_DLV_OK; |
427 | 0 | } |
428 | | |
429 | | /* Must not ever return DW_DLV_NO_ENTRY. |
430 | | Uses cu_context sometimes, so the base address |
431 | | is from the CU_DIE of the CU that |
432 | | dw_die is a child of. |
433 | | We attempt to cover what compilers actually do |
434 | | in the GNU dwarf4 extensions, but rules are not |
435 | | fully documented and it is difficult to be |
436 | | sure what is fully correct. */ |
437 | | int |
438 | | dwarf_get_ranges_baseaddress(Dwarf_Debug dw_dbg, |
439 | | Dwarf_Die dw_die, |
440 | | Dwarf_Bool *dw_known_base, |
441 | | Dwarf_Unsigned *dw_baseaddress, |
442 | | Dwarf_Bool *dw_at_ranges_offset_present, |
443 | | Dwarf_Unsigned *dw_at_ranges_offset, |
444 | | Dwarf_Error *dw_error) |
445 | 0 | { |
446 | 0 | Dwarf_CU_Context context = 0; |
447 | 0 | Dwarf_Bool have_die_ranges_offset = FALSE; |
448 | 0 | Dwarf_Unsigned die_ranges_offset = 0; |
449 | 0 | Dwarf_Bool have_die_base_addr = FALSE; |
450 | 0 | Dwarf_Unsigned die_base_addr = 0; |
451 | 0 | int res = 0; |
452 | |
|
453 | 0 | CHECK_DBG(dw_dbg,dw_error,"dwarf_get_ranges_baseaddress()"); |
454 | 0 | if (!dw_die) { |
455 | 0 | if (dw_known_base) { |
456 | 0 | *dw_known_base = FALSE; |
457 | 0 | *dw_at_ranges_offset_present = FALSE; |
458 | 0 | } |
459 | 0 | if (dw_baseaddress) { |
460 | 0 | *dw_baseaddress = 0; |
461 | 0 | *dw_at_ranges_offset = 0; |
462 | 0 | } |
463 | 0 | return DW_DLV_OK; |
464 | 0 | } |
465 | | /* If the DIE passed in has a DW_AT_ranges attribute |
466 | | we use that DIE ranges offset. */ |
467 | 0 | res = _dwarf_determine_die_range_offset(dw_dbg, |
468 | 0 | dw_die,&have_die_ranges_offset,&die_ranges_offset, |
469 | 0 | &have_die_base_addr,&die_base_addr,dw_error); |
470 | 0 | if (res != DW_DLV_OK ) { |
471 | 0 | if (res == DW_DLV_ERROR) { |
472 | | /* Suppressing knowledge of any error */ |
473 | 0 | dwarf_dealloc_error(dw_dbg,*dw_error); |
474 | 0 | *dw_error = 0; |
475 | 0 | } |
476 | 0 | } |
477 | 0 | context = dw_die->di_cu_context; |
478 | 0 | if (!context) { |
479 | 0 | _dwarf_error_string(dw_dbg, dw_error, |
480 | 0 | DW_DLE_DIE_NO_CU_CONTEXT, |
481 | 0 | "DW_DLE_DIE_NO_CU_CONTEXT: in a call to " |
482 | 0 | "dwarf_get_ranges_baseaddress"); |
483 | 0 | return DW_DLV_ERROR; |
484 | 0 | } |
485 | 0 | if (dw_at_ranges_offset) { |
486 | 0 | *dw_at_ranges_offset = die_ranges_offset; |
487 | 0 | } |
488 | 0 | if (dw_at_ranges_offset_present) { |
489 | 0 | *dw_at_ranges_offset_present = have_die_ranges_offset; |
490 | 0 | } |
491 | 0 | if (context->cc_base_address_present) { |
492 | 0 | *dw_baseaddress = context->cc_base_address; |
493 | 0 | *dw_known_base = context->cc_base_address_present; |
494 | 0 | } |
495 | 0 | return DW_DLV_OK; |
496 | 0 | } |