1/*
2
3  Copyright (C) 2000,2002,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., 59 Temple Place - Suite 330, Boston MA 02111-1307,
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 "dwarf_addr_finder.h"
53#include "dwarf_error.h"
54
55typedef unsigned long long ull;
56
57static int do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die,
58				   int *errval);
59static int
60  handle_debug_info(Dwarf_Debug dbg, int *errval);
61static int
62  handle_debug_frame(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, int *errval);
63static int
64  handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, int *errval);
65static int
66  handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die, Dwarf_addr_callback_func cb_func, int *errval);
67static int
68  handle_debug_loc(void);
69
70
71static Dwarf_addr_callback_func send_addr_note;
72
73int
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*/
172static int
173handle_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
230static int
231  might_have_addr[] = {
232    DW_AT_high_pc,
233    DW_AT_low_pc,
234};
235static 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*/
251static int
252handle_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*/
308static int
309handle_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 =
339			dwarf_loclist(attr, &llbuf, &count, perr);
340		    if (lres != DW_DLV_OK) {
341			return lres;
342		    }
343		    if (count != 1) {
344			/* this cannot happen! */
345			/* perr? */
346			_dwarf_error(dbg, perr,
347				     DW_DLE_LOCDESC_COUNT_WRONG);
348			retval = DW_DLV_ERROR;
349			return retval;
350		    }
351		    for (i = 0; i < count; ++i) {
352			unsigned int ents = llbuf[i].ld_cents;
353
354			locp = llbuf[i].ld_s;
355			for (entindx = 0; entindx < ents; entindx++) {
356			    Dwarf_Loc *llocp;
357
358			    llocp = locp + entindx;
359			    if (llocp->lr_atom == DW_OP_addr) {
360				send_addr_note(DW_SECTION_INFO, offset +
361					       llocp->lr_offset + 1
362					       /* The offset is the
363					          offset of the atom,
364					          ** and we know the
365					          addr is 1 past it. */
366					       , llocp->lr_number);
367			    }
368			}
369		    }
370
371
372		    if (count > 0) {
373			for (i = 0; i < count; ++i) {
374			    dwarf_dealloc(dbg, llbuf[i].ld_s,
375					  DW_DLA_LOC_BLOCK);
376			}
377			dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC);
378		    }
379		} else {
380		    retval = res;
381		}
382		break;
383
384	    default:
385		/* must be a const offset in debug_loc */
386		;		/* do nothing */
387	    }
388	    dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
389	}			/* else error or no entry */
390	retval = fres;
391    } else {
392	retval = ares;
393    }
394    return retval;
395}
396
397/*
398  Return DW_DLV_OK, or DW_DLV_ERROR
399
400  Handle the addrs in a single die.
401*/
402static int
403process_this_die_attrs(Dwarf_Debug dbg, Dwarf_Die newdie, int *errval)
404{
405    Dwarf_Error err;
406    Dwarf_Half i;
407    Dwarf_Half newattrnum;
408    int res;
409    int tres;
410    Dwarf_Half ltag;
411
412    Dwarf_Off doff;
413    int doffres = dwarf_dieoffset(newdie, &doff, &err);
414
415    if (doffres != DW_DLV_OK) {
416	if (doffres == DW_DLV_ERROR) {
417	    *errval = (int) dwarf_errno(err);
418	}
419	return doffres;
420    }
421    tres = dwarf_tag(newdie, &ltag, &err);
422    if (tres != DW_DLV_OK) {
423	return tres;
424    }
425    if (DW_TAG_compile_unit == ltag) {
426	/* because of the way the dwarf_line code works, we ** do lines
427	   only per compile unit. ** This may turn out to be wrong if
428	   we have lines ** left unconnected to a CU. ** of course such
429	   lines will not, at present, be ** used by gnome ** This is
430	   not ideal as coded due to the dwarf_line.c issue. */
431	int lres;
432
433	lres = handle_debug_line(dbg, newdie, send_addr_note, errval);
434	if (lres == DW_DLV_ERROR) {
435	    return lres;
436	}
437    }
438
439    for (i = 0; i < sizeof(might_have_addr) / sizeof(int); i++) {
440	int resattr;
441	Dwarf_Bool hasattr;
442
443	newattrnum = might_have_addr[i];
444	err = 0;
445	resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err);
446	if (DW_DLV_OK == resattr) {
447	    if (hasattr) {
448		res = handle_attr_addr(dbg, newdie, newattrnum, &err);
449		if (res != DW_DLV_OK) {
450		    *errval = (int) dwarf_errno(err);
451		    return DW_DLV_ERROR;
452		}
453	    }
454	} else {
455	    if (resattr == DW_DLV_ERROR) {
456		*errval = (int) dwarf_errno(err);
457		return resattr;
458	    }
459	}
460    }
461    for (i = 0; i < sizeof(might_have_locdesc) / sizeof(int); i++) {
462	int resattr;
463	Dwarf_Bool hasattr;
464
465	newattrnum = might_have_locdesc[i];
466	err = 0;
467	resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err);
468	if (DW_DLV_OK == resattr) {
469	    if (hasattr) {
470		res =
471		    handle_attr_locdesc(dbg, newdie, newattrnum, &err);
472		if (res != DW_DLV_OK) {
473		    *errval = (int) dwarf_errno(err);
474		    return DW_DLV_ERROR;
475		}
476	    }
477	} else {
478	    if (resattr == DW_DLV_ERROR) {
479		*errval = (int) dwarf_errno(err);
480		return resattr;
481	    }
482	}
483    }
484
485    return DW_DLV_OK;
486}
487
488/*
489	Handle siblings as a list,
490	Do children by recursing.
491	Effectively this is walking the tree preorder.
492
493	This dealloc's any die passed to it, so the
494	caller should not do that dealloc.
495	It seems more logical to have the one causing
496	the alloc to do the dealloc, but that way this
497	routine became a mess.
498
499*/
500static int
501do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die, int *errval)
502{
503
504    Dwarf_Die prevdie = 0;
505    Dwarf_Die newdie = die;
506    Dwarf_Error err = 0;
507    int res = 0;
508    int sibres = DW_DLV_OK;
509    int tres = DW_DLV_OK;
510    Dwarf_Die sibdie;
511
512    while (sibres == DW_DLV_OK) {
513	Dwarf_Die ch_die;
514
515
516	res = process_this_die_attrs(dbg, newdie, errval);
517	switch (res) {
518	case DW_DLV_OK:
519	    break;
520	case DW_DLV_NO_ENTRY:
521	    break;
522	default:
523	case DW_DLV_ERROR:
524	    if (prevdie) {
525		dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
526		prevdie = 0;
527	    }
528	    return DW_DLV_ERROR;
529	}
530
531	tres = dwarf_child(newdie, &ch_die, &err);
532
533	if (tres == DW_DLV_OK) {
534	    res = do_this_die_and_dealloc(dbg, ch_die, errval);
535	    switch (res) {
536	    case DW_DLV_OK:
537		break;
538	    case DW_DLV_NO_ENTRY:
539		break;
540	    default:
541	    case DW_DLV_ERROR:
542		if (prevdie) {
543		    dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
544		    prevdie = 0;
545		}
546		return DW_DLV_ERROR;
547	    }
548	} else if (tres == DW_DLV_ERROR) {
549	    /* An error! */
550	    *errval = (int) dwarf_errno(err);
551	    if (prevdie) {
552		dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
553		prevdie = 0;
554	    }
555	    dwarf_dealloc(dbg, err, DW_DLA_ERROR);
556	    return DW_DLV_ERROR;
557	}			/* else was NO ENTRY */
558	prevdie = newdie;
559	sibdie = 0;
560	sibres = dwarf_siblingof(dbg, newdie, &sibdie, &err);
561	if (prevdie) {
562	    dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
563	    prevdie = 0;
564	}
565	newdie = sibdie;
566
567    }
568    if (sibres == DW_DLV_NO_ENTRY) {
569	return DW_DLV_OK;
570    }
571    /* error. */
572    *errval = (int) dwarf_errno(err);
573    if (prevdie) {
574	dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
575	prevdie = 0;
576    }
577    dwarf_dealloc(dbg, err, DW_DLA_ERROR);
578    return DW_DLV_ERROR;
579
580}
581
582
583static int
584handle_debug_frame(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func,
585		   int *errval)
586{
587    int retval = DW_DLV_OK;
588    int res;
589    Dwarf_Error err;
590    Dwarf_Addr *addrlist;
591    Dwarf_Off *offsetlist;
592    Dwarf_Signed count;
593    int i;
594
595    res =
596	_dwarf_frame_address_offsets(dbg, &addrlist, &offsetlist,
597				     &count, &err);
598    if (res == DW_DLV_OK) {
599	for (i = 0; i < count; i++) {
600	    cb_func(DW_SECTION_FRAME, offsetlist[i], addrlist[i]);
601	}
602	dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR);
603	dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR);
604    } else if (res == DW_DLV_NO_ENTRY) {
605	retval = res;
606    } else {
607	*errval = (int) dwarf_errno(err);
608	retval = DW_DLV_ERROR;
609    }
610    return retval;
611
612}
613static int
614handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func,
615		     int *errval)
616{
617    int retval = DW_DLV_OK;
618    Dwarf_Error err;
619    Dwarf_Addr *aranges;
620    Dwarf_Signed count;
621    int indx;
622    Dwarf_Off *offsets;
623
624    retval =
625	_dwarf_get_aranges_addr_offsets(dbg, &aranges, &offsets, &count,
626					&err);
627    if (retval == DW_DLV_OK) {
628	if (count == 0) {
629	    retval = DW_DLV_NO_ENTRY;
630	} else {
631	    for (indx = 0; indx < count; indx++) {
632		cb_func(DW_SECTION_ARANGES, offsets[indx],
633			aranges[indx]);
634	    }
635	}
636	dwarf_dealloc(dbg, aranges, DW_DLA_ADDR);
637	dwarf_dealloc(dbg, offsets, DW_DLA_ADDR);
638    } else if (retval == DW_DLV_NO_ENTRY) {
639	;			/* do nothing */
640    } else {
641	*errval = (int) dwarf_errno(err);
642	retval = DW_DLV_ERROR;
643    }
644    return retval;
645}
646static int
647handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die,
648		  Dwarf_addr_callback_func cb_func, int *errval)
649{
650    int retval = DW_DLV_OK;
651    int res;
652    Dwarf_Error err;
653    Dwarf_Addr *addrlist;
654    Dwarf_Off *offsetlist;
655    Dwarf_Unsigned count;
656    Dwarf_Unsigned i;
657
658    res =
659	_dwarf_line_address_offsets(dbg, cu_die, &addrlist, &offsetlist,
660				    &count, &err);
661    if (res == DW_DLV_OK) {
662	for (i = 0; i < count; i++) {
663	    cb_func(DW_SECTION_LINE, offsetlist[i], addrlist[i]);
664
665	}
666	dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR);
667	dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR);
668    } else if (res == DW_DLV_NO_ENTRY) {
669	retval = res;
670    } else {
671	*errval = (int) dwarf_errno(err);
672	retval = DW_DLV_ERROR;
673    }
674    return retval;
675}
676
677/*
678	We need to add support for this. Currently we do not
679	generate this section.
680	FIX!
681*/
682static int
683handle_debug_loc(void)
684{
685    int retval = DW_DLV_NO_ENTRY;
686
687    return retval;
688}
689