xref: /titanic_50/usr/src/lib/libdwarf/common/dwarf_addr_finder.c (revision a43c88f4cac3d1b8c67d9b433164a5cb1c981311)
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
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
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
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
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
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, &ltag, &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
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
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
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
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
680 handle_debug_loc(void)
681 {
682     int retval = DW_DLV_NO_ENTRY;
683 
684     return retval;
685 }
686