1/*
2
3  Copyright (C) 2000,2004 Silicon Graphics, Inc.  All Rights Reserved.
4  Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
5
6  This program is free software; you can redistribute it and/or modify it
7  under the terms of version 2.1 of the GNU Lesser General Public License
8  as published by the Free Software Foundation.
9
10  This program is distributed in the hope that it would be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14  Further, this software is distributed without any warranty that it is
15  free of the rightful claim of any third person regarding infringement
16  or the like.  Any license provided herein, whether implied or
17  otherwise, applies only to this software file.  Patent licenses, if
18  any, provided herein do not apply to combinations of this program with
19  other software, or any other product whatsoever.
20
21  You should have received a copy of the GNU Lesser General Public
22  License along with this program; if not, write the Free Software
23  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
24  USA.
25
26  Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
27  Mountain View, CA 94043, or:
28
29  http://www.sgi.com
30
31  For further information regarding this notice, see:
32
33  http://oss.sgi.com/projects/GenInfo/NoticeExplan
34
35*/
36
37
38
39#include "config.h"
40#include "libdwarfdefs.h"
41#include <stdio.h>
42#include <string.h>
43#include "pro_incl.h"
44#include "pro_die.h"
45
46#ifndef R_MIPS_NONE
47#define R_MIPS_NONE 0
48#endif
49
50/* adds an attribute to a die */
51void _dwarf_pro_add_at_to_die(Dwarf_P_Die die, Dwarf_P_Attribute attr);
52
53/*----------------------------------------------------------------------------
54    This function creates a new die.
55    tag: tag of the new die to be created
56    parent,child,left,right: specify neighbors of the new die. Only
57    one of these may be non-null
58-----------------------------------------------------------------------------*/
59Dwarf_P_Die
60dwarf_new_die(Dwarf_P_Debug dbg,
61      Dwarf_Tag tag,
62      Dwarf_P_Die parent,
63      Dwarf_P_Die child,
64      Dwarf_P_Die left, Dwarf_P_Die right, Dwarf_Error * error)
65{
66    Dwarf_P_Die ret_die = 0;
67
68    Dwarf_P_Die new_die = (Dwarf_P_Die)
69        _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Die_s));
70    if (new_die == NULL) {
71        DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_ALLOC,
72            (Dwarf_P_Die) DW_DLV_BADADDR);
73    }
74    new_die->di_parent = NULL;
75    new_die->di_left = NULL;
76    new_die->di_right = NULL;
77    new_die->di_child = NULL;
78    new_die->di_last_child = NULL;
79    new_die->di_tag = tag;
80    new_die->di_dbg = dbg;
81    new_die->di_marker = 0;
82    ret_die =
83        dwarf_die_link(new_die, parent, child, left, right, error);
84    return ret_die;
85}
86
87/*----------------------------------------------------------------------------
88    This function links up a die to specified neighbors
89    parent,child,left,right: specify neighbors of the new die. Only
90    one of these may be non-null
91-----------------------------------------------------------------------------*/
92Dwarf_P_Die
93dwarf_die_link(Dwarf_P_Die new_die,
94       Dwarf_P_Die parent,
95       Dwarf_P_Die child,
96       Dwarf_P_Die left, Dwarf_P_Die right, Dwarf_Error * error)
97{
98    /* Count the # of non null neighbors. */
99    int n_nulls = 0;
100
101    if (parent != NULL) {
102        n_nulls++;
103        if (new_die->di_parent != NULL) {
104              DWARF_P_DBG_ERROR(NULL, DW_DLE_LINK_LOOP,
105                    (Dwarf_P_Die) DW_DLV_BADADDR);
106        }
107        new_die->di_parent = parent;
108        if (parent->di_child) {
109
110            /* di_last_child identifies the last sibling, the
111               die we want to attach new_die to. */
112            /* ASSERT: if di_child is set so is di_last_child. */
113            Dwarf_P_Die former_lastchild = parent->di_last_child;
114            parent->di_last_child = new_die;
115            /* Attach to  the new die to end of the sibling list. */
116            former_lastchild->di_right = new_die;
117            new_die->di_left = former_lastchild;
118        } else {
119            parent->di_child = new_die;
120            parent->di_last_child = new_die;
121        }
122    }
123    if (child != NULL) {
124        n_nulls++;
125        new_die->di_child = child;
126        new_die->di_last_child = child;
127        if (child->di_parent) {
128            DWARF_P_DBG_ERROR(NULL, DW_DLE_PARENT_EXISTS,
129                              (Dwarf_P_Die) DW_DLV_BADADDR);
130        } else {
131            child->di_parent = new_die;
132        }
133    }
134    if (left != NULL) {
135        n_nulls++;
136        new_die->di_left = left;
137        if (left->di_right) {
138            /* There's already a right sibling of left,
139               insert the new die in the list. */
140            new_die->di_right = left->di_right;
141            left->di_right->di_left = new_die;
142        }
143        left->di_right = new_die;
144        if (new_die->di_parent) {
145            DWARF_P_DBG_ERROR(NULL, DW_DLE_PARENT_EXISTS,
146                              (Dwarf_P_Die) DW_DLV_BADADDR);
147        } else {
148            new_die->di_parent = left->di_parent;
149        }
150    }
151    if (right != NULL) {
152        n_nulls++;
153        new_die->di_right = right;
154        if (right->di_left) {
155            /* There is already a left sibling of the right die,
156               insert the new die in the list.  */
157            new_die->di_left = right->di_left;
158            right->di_left->di_right = new_die;
159        }
160        right->di_left = new_die;
161        if (new_die->di_parent) {
162             DWARF_P_DBG_ERROR(NULL, DW_DLE_PARENT_EXISTS,
163                              (Dwarf_P_Die) DW_DLV_BADADDR);
164         } else {
165             new_die->di_parent = right->di_parent;
166        }
167    }
168    if (n_nulls > 1) {
169         /* Multiple neighbors! error! */
170         DWARF_P_DBG_ERROR(NULL, DW_DLE_EXTRA_NEIGHBORS,
171             (Dwarf_P_Die) DW_DLV_BADADDR);
172    }
173    return new_die;
174
175}
176
177Dwarf_Unsigned
178dwarf_add_die_marker(Dwarf_P_Debug dbg,
179    Dwarf_P_Die die,
180    Dwarf_Unsigned marker,
181    Dwarf_Error * error)
182{
183    if (die == NULL) {
184        DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_NULL, DW_DLV_NOCOUNT);
185    }
186    die->di_marker = marker;
187    return 0;
188}
189
190
191Dwarf_Unsigned
192dwarf_get_die_marker(Dwarf_P_Debug dbg,
193     Dwarf_P_Die die,
194     Dwarf_Unsigned * marker,
195     Dwarf_Error * error)
196{
197    if (die == NULL) {
198        DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_NULL, DW_DLV_NOCOUNT);
199    }
200    *marker = die->di_marker;
201    return 0;
202}
203
204
205/*----------------------------------------------------------------------------
206    This function adds a die to dbg struct. It should be called using
207    the root of all the dies.
208-----------------------------------------------------------------------------*/
209Dwarf_Unsigned
210dwarf_add_die_to_debug(Dwarf_P_Debug dbg,
211     Dwarf_P_Die first_die, Dwarf_Error * error)
212{
213    if (first_die == NULL) {
214        DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_NULL, DW_DLV_NOCOUNT);
215    }
216    if (first_die->di_tag != DW_TAG_compile_unit) {
217        DWARF_P_DBG_ERROR(dbg, DW_DLE_WRONG_TAG, DW_DLV_NOCOUNT);
218    }
219    dbg->de_dies = first_die;
220    return 0;
221}
222
223int
224_dwarf_pro_add_AT_stmt_list(Dwarf_P_Debug dbg,
225    Dwarf_P_Die first_die, Dwarf_Error * error)
226{
227    Dwarf_P_Attribute new_attr;
228    int uwordb_size = dbg->de_offset_size;
229
230    /* Add AT_stmt_list attribute */
231    new_attr = (Dwarf_P_Attribute)
232        _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
233    if (new_attr == NULL) {
234         DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, DW_DLV_NOCOUNT);
235    }
236
237    new_attr->ar_attribute = DW_AT_stmt_list;
238    new_attr->ar_attribute_form = dbg->de_ar_data_attribute_form;
239    new_attr->ar_rel_type = dbg->de_offset_reloc;
240
241    new_attr->ar_nbytes = uwordb_size;
242    new_attr->ar_next = NULL;
243    new_attr->ar_reloc_len = uwordb_size;
244    new_attr->ar_data = (char *)
245        _dwarf_p_get_alloc(dbg, uwordb_size);
246    if (new_attr->ar_data == NULL) {
247        DWARF_P_DBG_ERROR(NULL, DW_DLE_ADDR_ALLOC, DW_DLV_NOCOUNT);
248    }
249    {
250       Dwarf_Unsigned du = 0;
251
252       WRITE_UNALIGNED(dbg, (void *) new_attr->ar_data,
253           (const void *) &du, sizeof(du), uwordb_size);
254    }
255
256    _dwarf_pro_add_at_to_die(first_die, new_attr);
257    return 0;
258}
259
260/*-----------------------------------------------------------------------------
261    Add AT_name attribute to die
262------------------------------------------------------------------------------*/
263Dwarf_P_Attribute
264dwarf_add_AT_name(Dwarf_P_Die die, char *name, Dwarf_Error * error)
265{
266    Dwarf_P_Attribute new_attr;
267
268    if (die == NULL) {
269        DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL,
270           (Dwarf_P_Attribute) DW_DLV_BADADDR);
271    }
272    new_attr = (Dwarf_P_Attribute)
273        _dwarf_p_get_alloc(die->di_dbg,sizeof(struct Dwarf_P_Attribute_s));
274    if (new_attr == NULL) {
275        DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC,
276            (Dwarf_P_Attribute) DW_DLV_BADADDR);
277    }
278
279    /* fill in the information */
280    new_attr->ar_attribute = DW_AT_name;
281    /* assume that form is string, no debug_str yet */
282    new_attr->ar_attribute_form = DW_FORM_string;
283    new_attr->ar_nbytes = strlen(name) + 1;
284    new_attr->ar_next = NULL;
285    new_attr->ar_reloc_len = 0;
286    new_attr->ar_data = (char *)
287        _dwarf_p_get_alloc(die->di_dbg, strlen(name)+1);
288    if (new_attr->ar_data == NULL) {
289        DWARF_P_DBG_ERROR(NULL, DW_DLE_STRING_ALLOC,
290            (Dwarf_P_Attribute) DW_DLV_BADADDR);
291    }
292    strcpy(new_attr->ar_data, name);
293
294    new_attr->ar_rel_type = R_MIPS_NONE;
295
296    /* add attribute to the die */
297    _dwarf_pro_add_at_to_die(die, new_attr);
298    return new_attr;
299}
300
301
302/*-----------------------------------------------------------------------------
303    Add AT_comp_dir attribute to die
304------------------------------------------------------------------------------*/
305Dwarf_P_Attribute
306dwarf_add_AT_comp_dir(Dwarf_P_Die ownerdie,
307    char *current_working_directory,
308    Dwarf_Error * error)
309{
310    Dwarf_P_Attribute new_attr;
311
312    if (ownerdie == NULL) {
313        DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL,
314            (Dwarf_P_Attribute) DW_DLV_BADADDR);
315    }
316    new_attr = (Dwarf_P_Attribute)
317        _dwarf_p_get_alloc(ownerdie->di_dbg,
318        sizeof(struct Dwarf_P_Attribute_s));
319    if (new_attr == NULL) {
320        DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC,
321            (Dwarf_P_Attribute) DW_DLV_BADADDR);
322    }
323
324    /* fill in the information */
325    new_attr->ar_attribute = DW_AT_comp_dir;
326    /* assume that form is string, no debug_str yet */
327    new_attr->ar_attribute_form = DW_FORM_string;
328    new_attr->ar_nbytes = strlen(current_working_directory) + 1;
329    new_attr->ar_next = NULL;
330    new_attr->ar_reloc_len = 0;
331    new_attr->ar_data = (char *)
332        _dwarf_p_get_alloc(ownerdie->di_dbg,
333        strlen(current_working_directory)+1);
334    if (new_attr->ar_data == NULL) {
335        DWARF_P_DBG_ERROR(NULL, DW_DLE_STRING_ALLOC,
336            (Dwarf_P_Attribute) DW_DLV_BADADDR);
337    }
338    strcpy(new_attr->ar_data, current_working_directory);
339
340    new_attr->ar_rel_type = R_MIPS_NONE;
341
342    /* add attribute to the die */
343    _dwarf_pro_add_at_to_die(ownerdie, new_attr);
344    return new_attr;
345}
346
347int
348_dwarf_pro_add_AT_fde(Dwarf_P_Debug dbg,
349    Dwarf_P_Die die,
350    Dwarf_Unsigned offset, Dwarf_Error * error)
351{
352    Dwarf_P_Attribute new_attr;
353    int uwordb_size = dbg->de_offset_size;
354
355    if (die == NULL) {
356        DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL, -1);
357    }
358    new_attr = (Dwarf_P_Attribute)
359        _dwarf_p_get_alloc(dbg,sizeof(struct Dwarf_P_Attribute_s));
360    if (new_attr == NULL) {
361        DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, -1);
362    }
363
364    /* fill in the information */
365    new_attr->ar_attribute = DW_AT_MIPS_fde;
366    new_attr->ar_attribute_form = dbg->de_ar_data_attribute_form;;
367    new_attr->ar_rel_type = dbg->de_offset_reloc;
368    new_attr->ar_nbytes = uwordb_size;
369    new_attr->ar_next = NULL;
370    new_attr->ar_reloc_len = uwordb_size;
371    new_attr->ar_data = (char *)
372        _dwarf_p_get_alloc(dbg, uwordb_size);
373    if (new_attr->ar_data == NULL) {
374        DWARF_P_DBG_ERROR(NULL, DW_DLE_ADDR_ALLOC, DW_DLV_NOCOUNT);
375    }
376    {
377        Dwarf_Unsigned du = offset;
378
379        WRITE_UNALIGNED(dbg, (void *) new_attr->ar_data,
380            (const void *) &du, sizeof(du), uwordb_size);
381    }
382
383    _dwarf_pro_add_at_to_die(die, new_attr);
384
385    return 0;
386}
387
388int
389_dwarf_pro_add_AT_macro_info(Dwarf_P_Debug dbg,
390    Dwarf_P_Die die,
391    Dwarf_Unsigned offset, Dwarf_Error * error)
392{
393    Dwarf_P_Attribute new_attr;
394    int uwordb_size = dbg->de_offset_size;
395
396    if (die == NULL) {
397        DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL, -1);
398    }
399    new_attr = (Dwarf_P_Attribute)
400        _dwarf_p_get_alloc(dbg,sizeof(struct Dwarf_P_Attribute_s));
401    if (new_attr == NULL) {
402        DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, -1);
403    }
404
405    /* fill in the information */
406    new_attr->ar_attribute = DW_AT_macro_info;
407    new_attr->ar_attribute_form = dbg->de_ar_data_attribute_form;
408    new_attr->ar_rel_type = dbg->de_offset_reloc;
409
410    new_attr->ar_nbytes = uwordb_size;
411    new_attr->ar_next = NULL;
412    new_attr->ar_reloc_len = uwordb_size;
413    new_attr->ar_data = (char *)
414        _dwarf_p_get_alloc(dbg, uwordb_size);
415    if (new_attr->ar_data == NULL) {
416        DWARF_P_DBG_ERROR(NULL, DW_DLE_ADDR_ALLOC, DW_DLV_NOCOUNT);
417    }
418    {
419        Dwarf_Unsigned du = offset;
420
421        WRITE_UNALIGNED(dbg, (void *) new_attr->ar_data,
422            (const void *) &du, sizeof(du), uwordb_size);
423    }
424
425    _dwarf_pro_add_at_to_die(die, new_attr);
426
427    return 0;
428}
429
430
431void
432_dwarf_pro_add_at_to_die(Dwarf_P_Die die, Dwarf_P_Attribute attr)
433{
434    if (die->di_last_attr) {
435        die->di_last_attr->ar_next = attr;
436        die->di_last_attr = attr;
437        die->di_n_attr++;
438    } else {
439        die->di_n_attr = 1;
440        die->di_attrs = die->di_last_attr = attr;
441    }
442}
443