1 /*
2
3 Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of version 2.1 of the GNU Lesser General Public License
7 as published by the Free Software Foundation.
8
9 This program is distributed in the hope that it would be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 Further, this software is distributed without any warranty that it is
14 free of the rightful claim of any third person regarding infringement
15 or the like. Any license provided herein, whether implied or
16 otherwise, applies only to this software file. Patent licenses, if
17 any, provided herein do not apply to combinations of this program with
18 other software, or any other product whatsoever.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with this program; if not, write the Free Software
22 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
23 USA.
24
25 Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
26 Mountain View, CA 94043, or:
27
28 http://www.sgi.com
29
30 For further information regarding this notice, see:
31
32 http://oss.sgi.com/projects/GenInfo/NoticeExplan
33
34 */
35 /* This code used by SGI-IRIX rqs processing, not needed by
36 any other system or application.
37 */
38
39 #include "config.h"
40 #include "libdwarfdefs.h"
41 #ifdef HAVE_ELF_H
42 #include <elf.h>
43 #endif
44 #include <dwarf.h>
45 #include <libdwarf.h>
46 #include "dwarf_base_types.h"
47 #include "dwarf_alloc.h"
48 #include "dwarf_opaque.h"
49 #include "dwarf_arange.h"
50 #include "dwarf_line.h"
51 #include "dwarf_frame.h"
52 #include <cmplrs/dwarf_addr_finder.h>
53 #include "dwarf_error.h"
54
55 typedef unsigned long long ull;
56
57 static int do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die,
58 int *errval);
59 static int
60 handle_debug_info(Dwarf_Debug dbg, int *errval);
61 static int
62 handle_debug_frame(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, int *errval);
63 static int
64 handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, int *errval);
65 static int
66 handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die, Dwarf_addr_callback_func cb_func, int *errval);
67 static int
68 handle_debug_loc(void);
69
70
71 static Dwarf_addr_callback_func send_addr_note;
72
73 int
_dwarf_addr_finder(dwarf_elf_handle elf_file_ptr,Dwarf_addr_callback_func cb_func,int * dwerr)74 _dwarf_addr_finder(dwarf_elf_handle elf_file_ptr,
75 Dwarf_addr_callback_func cb_func, int *dwerr)
76 {
77
78 Dwarf_Error err = 0;
79 Dwarf_Debug dbg = 0;
80 int res = 0;
81 int errval = 0;
82 int sections_found = 0;
83
84 res = dwarf_elf_init(elf_file_ptr, DW_DLC_READ, /* errhand */ 0,
85 /* errarg */ 0, &dbg, &err);
86 if (res == DW_DLV_ERROR) {
87 int errv = (int) dwarf_errno(err);
88
89 return errv;
90 }
91 if (res == DW_DLV_NO_ENTRY) {
92 return res;
93 }
94
95 send_addr_note = cb_func;
96
97 res = handle_debug_info(dbg, &errval);
98 switch (res) {
99 case DW_DLV_OK:
100 ++sections_found;
101 break;
102 case DW_DLV_NO_ENTRY:
103
104 break;
105 default:
106 case DW_DLV_ERROR:
107 dwarf_finish(dbg, &err);
108 *dwerr = errval;
109 return res;
110 }
111
112 res = handle_debug_aranges(dbg, cb_func, &errval);
113 switch (res) {
114 case DW_DLV_OK:
115 ++sections_found;
116 break;
117 case DW_DLV_NO_ENTRY:
118 break;
119 default:
120 case DW_DLV_ERROR:
121 dwarf_finish(dbg, &err);
122 *dwerr = errval;
123 return res;
124 }
125 res = handle_debug_frame(dbg, cb_func, &errval);
126 switch (res) {
127 case DW_DLV_OK:
128 ++sections_found;
129 break;
130 case DW_DLV_NO_ENTRY:
131 break;
132 default:
133 case DW_DLV_ERROR:
134 dwarf_finish(dbg, &err);
135 *dwerr = errval;
136 return res;
137 }
138
139 res = handle_debug_loc(); /* does nothing */
140 switch (res) {
141 case DW_DLV_OK:
142 ++sections_found;
143 break;
144 case DW_DLV_NO_ENTRY:
145 break;
146 default:
147 case DW_DLV_ERROR:
148 /* IMPOSSIBLE : handle_debug_loc cannot return this */
149 dwarf_finish(dbg, &err);
150 *dwerr = errval;
151 return res;
152 }
153
154
155
156 *dwerr = 0;
157 res = dwarf_finish(dbg, &err);
158 if (res == DW_DLV_ERROR) {
159 *dwerr = (int) dwarf_errno(err);
160 return DW_DLV_ERROR;
161 }
162 if (sections_found == 0) {
163 return DW_DLV_NO_ENTRY;
164 }
165 return DW_DLV_OK;
166
167 }
168
169 /*
170 Return DW_DLV_OK, ERROR, or NO_ENTRY.
171 */
172 static int
handle_debug_info(Dwarf_Debug dbg,int * errval)173 handle_debug_info(Dwarf_Debug dbg, int *errval)
174 {
175 Dwarf_Unsigned nxtoff = 1;
176 Dwarf_Unsigned hdr_length;
177 Dwarf_Half version_stamp;
178 Dwarf_Unsigned abbrev_offset;
179 Dwarf_Half addr_size;
180 Dwarf_Error err;
181 int terminate_now = 0;
182 int res = 0;
183 Dwarf_Die sibdie;
184 int sibres;
185 int nres = DW_DLV_OK;
186
187
188 for (nres = dwarf_next_cu_header(dbg, &hdr_length, &version_stamp,
189 &abbrev_offset,
190 &addr_size, &nxtoff, &err);
191 terminate_now == 0 && nres == DW_DLV_OK;
192 nres = dwarf_next_cu_header(dbg, &hdr_length, &version_stamp,
193 &abbrev_offset,
194 &addr_size, &nxtoff, &err)
195 ) {
196
197 Dwarf_Die curdie = 0;
198
199 /* try to get the compilation unit die */
200 sibres = dwarf_siblingof(dbg, curdie, &sibdie, &err);
201 if (sibres == DW_DLV_OK) {
202 res = do_this_die_and_dealloc(dbg, sibdie, errval);
203 switch (res) {
204 case DW_DLV_OK:
205 break;
206 case DW_DLV_NO_ENTRY:
207 break;
208 default:
209 case DW_DLV_ERROR:
210 return DW_DLV_ERROR;
211 }
212 } else if (sibres == DW_DLV_ERROR) {
213 *errval = (int) dwarf_errno(err);
214 return DW_DLV_ERROR;
215 } else {
216 /* NO ENTRY! */
217 /* impossible? */
218 }
219
220 }
221 if (nres == DW_DLV_ERROR) {
222 int localerr = (int) dwarf_errno(err);
223
224 *errval = localerr;
225 return DW_DLV_ERROR;
226 }
227 return DW_DLV_OK;
228 }
229
230 static int
231 might_have_addr[] = {
232 DW_AT_high_pc,
233 DW_AT_low_pc,
234 };
235 static int
236 might_have_locdesc[] = {
237 DW_AT_segment,
238 DW_AT_return_addr,
239 DW_AT_frame_base,
240 DW_AT_static_link,
241 DW_AT_data_member_location,
242 DW_AT_string_length,
243 DW_AT_location,
244 DW_AT_use_location,
245 DW_AT_vtable_elem_location,
246 };
247
248 /*
249 Return DW_DLV_OK if handling this went ok.
250 */
251 static int
handle_attr_addr(Dwarf_Debug dbg,Dwarf_Die die,Dwarf_Half attrnum,Dwarf_Error * perr)252 handle_attr_addr(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attrnum,
253 Dwarf_Error * perr)
254 {
255 int res = DW_DLV_OK;
256 Dwarf_Off offset;
257 Dwarf_Addr addr;
258 Dwarf_Half form;
259 int ares;
260
261 Dwarf_Attribute attr;
262
263 ares = dwarf_attr(die, attrnum, &attr, perr);
264 if (ares == DW_DLV_OK) {
265 int formres = dwarf_whatform(attr, &form, perr);
266
267 switch (formres) {
268 case DW_DLV_OK:
269 break;
270 case DW_DLV_ERROR:
271 case DW_DLV_NO_ENTRY: /* impossible. */
272 return formres;
273
274 }
275
276 switch (form) {
277 case DW_FORM_ref_addr:
278 case DW_FORM_addr:
279 res = dwarf_attr_offset(die, attr, &offset, perr);
280 if (res == DW_DLV_OK) {
281 ares = dwarf_formaddr(attr, &addr, perr);
282 if (ares == DW_DLV_OK) {
283 send_addr_note(DW_SECTION_INFO, offset, addr);
284 } else if (ares == DW_DLV_ERROR) {
285 return ares;
286 } /* no entry: ok. */
287 } else {
288 res = DW_DLV_ERROR; /* NO_ENTRY is impossible. */
289 }
290 break;
291
292 default:
293 /* surprising! An error? */
294
295 ; /* do nothing */
296 }
297 dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
298
299 } else {
300 res = ares;
301 }
302 return res;
303 }
304
305 /*
306 Return DW_DLV_OK if handling this went ok.
307 */
308 static int
handle_attr_locdesc(Dwarf_Debug dbg,Dwarf_Die die,Dwarf_Half attrnum,Dwarf_Error * perr)309 handle_attr_locdesc(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attrnum,
310 Dwarf_Error * perr)
311 {
312 int retval = DW_DLV_OK;
313 Dwarf_Attribute attr;
314 Dwarf_Locdesc *llbuf;
315 Dwarf_Signed i;
316 Dwarf_Off offset;
317 Dwarf_Loc *locp;
318 unsigned int entindx;
319 int res;
320 int ares;
321
322
323 ares = dwarf_attr(die, attrnum, &attr, perr);
324 if (ares == DW_DLV_OK) {
325 Dwarf_Half form;
326 int fres = dwarf_whatform(attr, &form, perr);
327
328 if (fres == DW_DLV_OK) {
329 switch (form) {
330 case DW_FORM_block1:
331 case DW_FORM_block2:
332 case DW_FORM_block4:
333 /* must be location description */
334 res = dwarf_attr_offset(die, attr, &offset, perr);
335 llbuf = 0;
336 if (res == DW_DLV_OK) {
337 Dwarf_Signed count;
338 int lres = dwarf_loclist(attr, &llbuf, &count, perr);
339 if (lres != DW_DLV_OK) {
340 return lres;
341 }
342 if (count != 1) {
343 /* this cannot happen! */
344 /* perr? */
345 _dwarf_error(dbg, perr,
346 DW_DLE_LOCDESC_COUNT_WRONG);
347 retval = DW_DLV_ERROR;
348 return retval;
349 }
350 for (i = 0; i < count; ++i) {
351 unsigned int ents = llbuf[i].ld_cents;
352
353 locp = llbuf[i].ld_s;
354 for (entindx = 0; entindx < ents; entindx++) {
355 Dwarf_Loc *llocp;
356
357 llocp = locp + entindx;
358 if (llocp->lr_atom == DW_OP_addr) {
359 send_addr_note(DW_SECTION_INFO, offset +
360 llocp->lr_offset + 1
361 /* The offset is the
362 offset of the atom,
363 ** and we know the
364 addr is 1 past it. */
365 , llocp->lr_number);
366 }
367 }
368 }
369
370
371 if (count > 0) {
372 for (i = 0; i < count; ++i) {
373 dwarf_dealloc(dbg, llbuf[i].ld_s,
374 DW_DLA_LOC_BLOCK);
375 }
376 dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC);
377 }
378 } else {
379 retval = res;
380 }
381 break;
382
383 default:
384 /* must be a const offset in debug_loc */
385 ; /* do nothing */
386 }
387 dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
388 } /* else error or no entry */
389 retval = fres;
390 } else {
391 retval = ares;
392 }
393 return retval;
394 }
395
396 /*
397 Return DW_DLV_OK, or DW_DLV_ERROR
398
399 Handle the addrs in a single die.
400 */
401 static int
process_this_die_attrs(Dwarf_Debug dbg,Dwarf_Die newdie,int * errval)402 process_this_die_attrs(Dwarf_Debug dbg, Dwarf_Die newdie, int *errval)
403 {
404 Dwarf_Error err;
405 Dwarf_Half i;
406 Dwarf_Half newattrnum;
407 int res;
408 int tres;
409 Dwarf_Half ltag;
410
411 Dwarf_Off doff;
412 int doffres = dwarf_dieoffset(newdie, &doff, &err);
413
414 if (doffres != DW_DLV_OK) {
415 if (doffres == DW_DLV_ERROR) {
416 *errval = (int) dwarf_errno(err);
417 }
418 return doffres;
419 }
420 tres = dwarf_tag(newdie, <ag, &err);
421 if (tres != DW_DLV_OK) {
422 return tres;
423 }
424 if (DW_TAG_compile_unit == ltag) {
425 /* because of the way the dwarf_line code works, we do lines
426 only per compile unit. This may turn out to be wrong if
427 we have lines left unconnected to a CU. of course such
428 lines will not, at present, be used by gnome. This is
429 not ideal as coded due to the dwarf_line.c issue. */
430 int lres = handle_debug_line(dbg, newdie, send_addr_note, errval);
431 if (lres == DW_DLV_ERROR) {
432 return lres;
433 }
434 }
435
436 for (i = 0; i < sizeof(might_have_addr) / sizeof(int); i++) {
437 int resattr;
438 Dwarf_Bool hasattr;
439
440 newattrnum = might_have_addr[i];
441 err = 0;
442 resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err);
443 if (DW_DLV_OK == resattr) {
444 if (hasattr) {
445 res = handle_attr_addr(dbg, newdie, newattrnum, &err);
446 if (res != DW_DLV_OK) {
447 *errval = (int) dwarf_errno(err);
448 return DW_DLV_ERROR;
449 }
450 }
451 } else {
452 if (resattr == DW_DLV_ERROR) {
453 *errval = (int) dwarf_errno(err);
454 return resattr;
455 }
456 }
457 }
458 for (i = 0; i < sizeof(might_have_locdesc) / sizeof(int); i++) {
459 int resattr;
460 Dwarf_Bool hasattr;
461
462 newattrnum = might_have_locdesc[i];
463 err = 0;
464 resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err);
465 if (DW_DLV_OK == resattr) {
466 if (hasattr) {
467 res =
468 handle_attr_locdesc(dbg, newdie, newattrnum, &err);
469 if (res != DW_DLV_OK) {
470 *errval = (int) dwarf_errno(err);
471 return DW_DLV_ERROR;
472 }
473 }
474 } else {
475 if (resattr == DW_DLV_ERROR) {
476 *errval = (int) dwarf_errno(err);
477 return resattr;
478 }
479 }
480 }
481
482 return DW_DLV_OK;
483 }
484
485 /*
486 Handle siblings as a list,
487 Do children by recursing.
488 Effectively this is walking the tree preorder.
489
490 This dealloc's any die passed to it, so the
491 caller should not do that dealloc.
492 It seems more logical to have the one causing
493 the alloc to do the dealloc, but that way this
494 routine became a mess.
495
496 */
497 static int
do_this_die_and_dealloc(Dwarf_Debug dbg,Dwarf_Die die,int * errval)498 do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die, int *errval)
499 {
500
501 Dwarf_Die prevdie = 0;
502 Dwarf_Die newdie = die;
503 Dwarf_Error err = 0;
504 int res = 0;
505 int sibres = DW_DLV_OK;
506 int tres = DW_DLV_OK;
507 Dwarf_Die sibdie;
508
509 while (sibres == DW_DLV_OK) {
510 Dwarf_Die ch_die;
511
512
513 res = process_this_die_attrs(dbg, newdie, errval);
514 switch (res) {
515 case DW_DLV_OK:
516 break;
517 case DW_DLV_NO_ENTRY:
518 break;
519 default:
520 case DW_DLV_ERROR:
521 if (prevdie) {
522 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
523 prevdie = 0;
524 }
525 return DW_DLV_ERROR;
526 }
527
528 tres = dwarf_child(newdie, &ch_die, &err);
529
530 if (tres == DW_DLV_OK) {
531 res = do_this_die_and_dealloc(dbg, ch_die, errval);
532 switch (res) {
533 case DW_DLV_OK:
534 break;
535 case DW_DLV_NO_ENTRY:
536 break;
537 default:
538 case DW_DLV_ERROR:
539 if (prevdie) {
540 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
541 prevdie = 0;
542 }
543 return DW_DLV_ERROR;
544 }
545 } else if (tres == DW_DLV_ERROR) {
546 /* An error! */
547 *errval = (int) dwarf_errno(err);
548 if (prevdie) {
549 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
550 prevdie = 0;
551 }
552 dwarf_dealloc(dbg, err, DW_DLA_ERROR);
553 return DW_DLV_ERROR;
554 } /* else was NO ENTRY */
555 prevdie = newdie;
556 sibdie = 0;
557 sibres = dwarf_siblingof(dbg, newdie, &sibdie, &err);
558 if (prevdie) {
559 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
560 prevdie = 0;
561 }
562 newdie = sibdie;
563
564 }
565 if (sibres == DW_DLV_NO_ENTRY) {
566 return DW_DLV_OK;
567 }
568 /* error. */
569 *errval = (int) dwarf_errno(err);
570 if (prevdie) {
571 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
572 prevdie = 0;
573 }
574 dwarf_dealloc(dbg, err, DW_DLA_ERROR);
575 return DW_DLV_ERROR;
576
577 }
578
579
580 static int
handle_debug_frame(Dwarf_Debug dbg,Dwarf_addr_callback_func cb_func,int * errval)581 handle_debug_frame(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func,
582 int *errval)
583 {
584 int retval = DW_DLV_OK;
585 int res;
586 Dwarf_Error err;
587 Dwarf_Addr *addrlist;
588 Dwarf_Off *offsetlist;
589 Dwarf_Signed count;
590 int i;
591
592 res =
593 _dwarf_frame_address_offsets(dbg, &addrlist, &offsetlist,
594 &count, &err);
595 if (res == DW_DLV_OK) {
596 for (i = 0; i < count; i++) {
597 cb_func(DW_SECTION_FRAME, offsetlist[i], addrlist[i]);
598 }
599 dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR);
600 dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR);
601 } else if (res == DW_DLV_NO_ENTRY) {
602 retval = res;
603 } else {
604 *errval = (int) dwarf_errno(err);
605 retval = DW_DLV_ERROR;
606 }
607 return retval;
608
609 }
610 static int
handle_debug_aranges(Dwarf_Debug dbg,Dwarf_addr_callback_func cb_func,int * errval)611 handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func,
612 int *errval)
613 {
614 int retval = DW_DLV_OK;
615 Dwarf_Error err;
616 Dwarf_Addr *aranges;
617 Dwarf_Signed count;
618 int indx;
619 Dwarf_Off *offsets;
620
621 retval =
622 _dwarf_get_aranges_addr_offsets(dbg, &aranges, &offsets, &count,
623 &err);
624 if (retval == DW_DLV_OK) {
625 if (count == 0) {
626 retval = DW_DLV_NO_ENTRY;
627 } else {
628 for (indx = 0; indx < count; indx++) {
629 cb_func(DW_SECTION_ARANGES, offsets[indx],
630 aranges[indx]);
631 }
632 }
633 dwarf_dealloc(dbg, aranges, DW_DLA_ADDR);
634 dwarf_dealloc(dbg, offsets, DW_DLA_ADDR);
635 } else if (retval == DW_DLV_NO_ENTRY) {
636 ; /* do nothing */
637 } else {
638 *errval = (int) dwarf_errno(err);
639 retval = DW_DLV_ERROR;
640 }
641 return retval;
642 }
643 static int
handle_debug_line(Dwarf_Debug dbg,Dwarf_Die cu_die,Dwarf_addr_callback_func cb_func,int * errval)644 handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die,
645 Dwarf_addr_callback_func cb_func, int *errval)
646 {
647 int retval = DW_DLV_OK;
648 int res;
649 Dwarf_Error err;
650 Dwarf_Addr *addrlist;
651 Dwarf_Off *offsetlist;
652 Dwarf_Unsigned count;
653 Dwarf_Unsigned i;
654
655 res =
656 _dwarf_line_address_offsets(dbg, cu_die, &addrlist, &offsetlist,
657 &count, &err);
658 if (res == DW_DLV_OK) {
659 for (i = 0; i < count; i++) {
660 cb_func(DW_SECTION_LINE, offsetlist[i], addrlist[i]);
661
662 }
663 dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR);
664 dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR);
665 } else if (res == DW_DLV_NO_ENTRY) {
666 retval = res;
667 } else {
668 *errval = (int) dwarf_errno(err);
669 retval = DW_DLV_ERROR;
670 }
671 return retval;
672 }
673
674 /*
675 We need to add support for this. Currently we do not
676 generate this section.
677 FIX!
678 */
679 static int
handle_debug_loc(void)680 handle_debug_loc(void)
681 {
682 int retval = DW_DLV_NO_ENTRY;
683
684 return retval;
685 }
686