]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/elftoolchain/libdwarf/libdwarf_attr.c
libdwarf: Use the cached strtab pointer when reading string attributes.
[FreeBSD/FreeBSD.git] / contrib / elftoolchain / libdwarf / libdwarf_attr.c
1 /*-
2  * Copyright (c) 2007 John Birrell (jb@freebsd.org)
3  * Copyright (c) 2009-2011 Kai Wang
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include "_libdwarf.h"
29
30 ELFTC_VCSID("$Id: libdwarf_attr.c 3064 2014-06-06 19:35:55Z kaiwang27 $");
31
32 int
33 _dwarf_attr_alloc(Dwarf_Die die, Dwarf_Attribute *atp, Dwarf_Error *error)
34 {
35         Dwarf_Attribute at;
36
37         assert(die != NULL);
38         assert(atp != NULL);
39
40         if ((at = calloc(1, sizeof(struct _Dwarf_Attribute))) == NULL) {
41                 DWARF_SET_ERROR(die->die_dbg, error, DW_DLE_MEMORY);
42                 return (DW_DLE_MEMORY);
43         }
44
45         *atp = at;
46
47         return (DW_DLE_NONE);
48 }
49
50 static int
51 _dwarf_attr_add(Dwarf_Die die, Dwarf_Attribute atref, Dwarf_Attribute *atp,
52     Dwarf_Error *error)
53 {
54         Dwarf_Attribute at;
55         int ret;
56
57         if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE)
58                 return (ret);
59
60         memcpy(at, atref, sizeof(struct _Dwarf_Attribute));
61
62         STAILQ_INSERT_TAIL(&die->die_attr, at, at_next);
63
64         /* Save a pointer to the attribute name if this is one. */
65         if (at->at_attrib == DW_AT_name) {
66                 switch (at->at_form) {
67                 case DW_FORM_strp:
68                         die->die_name = at->u[1].s;
69                         break;
70                 case DW_FORM_string:
71                         die->die_name = at->u[0].s;
72                         break;
73                 default:
74                         break;
75                 }
76         }
77
78         if (atp != NULL)
79                 *atp = at;
80
81         return (DW_DLE_NONE);
82 }
83
84 Dwarf_Attribute
85 _dwarf_attr_find(Dwarf_Die die, Dwarf_Half attr)
86 {
87         Dwarf_Attribute at;
88
89         STAILQ_FOREACH(at, &die->die_attr, at_next) {
90                 if (at->at_attrib == attr)
91                         break;
92         }
93
94         return (at);
95 }
96
97 int
98 _dwarf_attr_init(Dwarf_Debug dbg, Dwarf_Section *ds, uint64_t *offsetp,
99     int dwarf_size, Dwarf_CU cu, Dwarf_Die die, Dwarf_AttrDef ad,
100     uint64_t form, int indirect, Dwarf_Error *error)
101 {
102         struct _Dwarf_Attribute atref;
103         int ret;
104
105         ret = DW_DLE_NONE;
106         memset(&atref, 0, sizeof(atref));
107         atref.at_die = die;
108         atref.at_offset = *offsetp;
109         atref.at_attrib = ad->ad_attrib;
110         atref.at_form = indirect ? form : ad->ad_form;
111         atref.at_indirect = indirect;
112         atref.at_ld = NULL;
113
114         switch (form) {
115         case DW_FORM_addr:
116                 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
117                     cu->cu_pointer_size);
118                 break;
119         case DW_FORM_block:
120         case DW_FORM_exprloc:
121                 atref.u[0].u64 = _dwarf_read_uleb128(ds->ds_data, offsetp);
122                 atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
123                     atref.u[0].u64);
124                 break;
125         case DW_FORM_block1:
126                 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 1);
127                 atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
128                     atref.u[0].u64);
129                 break;
130         case DW_FORM_block2:
131                 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 2);
132                 atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
133                     atref.u[0].u64);
134                 break;
135         case DW_FORM_block4:
136                 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 4);
137                 atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
138                     atref.u[0].u64);
139                 break;
140         case DW_FORM_data1:
141         case DW_FORM_flag:
142         case DW_FORM_ref1:
143                 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 1);
144                 break;
145         case DW_FORM_data2:
146         case DW_FORM_ref2:
147                 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 2);
148                 break;
149         case DW_FORM_data4:
150         case DW_FORM_ref4:
151                 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 4);
152                 break;
153         case DW_FORM_data8:
154         case DW_FORM_ref8:
155                 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 8);
156                 break;
157         case DW_FORM_indirect:
158                 form = _dwarf_read_uleb128(ds->ds_data, offsetp);
159                 return (_dwarf_attr_init(dbg, ds, offsetp, dwarf_size, cu, die,
160                     ad, form, 1, error));
161         case DW_FORM_ref_addr:
162                 if (cu->cu_version == 2)
163                         atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
164                             cu->cu_pointer_size);
165                 else
166                         atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
167                             dwarf_size);
168                 break;
169         case DW_FORM_ref_udata:
170         case DW_FORM_udata:
171                 atref.u[0].u64 = _dwarf_read_uleb128(ds->ds_data, offsetp);
172                 break;
173         case DW_FORM_sdata:
174                 atref.u[0].s64 = _dwarf_read_sleb128(ds->ds_data, offsetp);
175                 break;
176         case DW_FORM_sec_offset:
177                 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size);
178                 break;
179         case DW_FORM_string:
180                 atref.u[0].s = _dwarf_read_string(ds->ds_data, ds->ds_size,
181                     offsetp);
182                 break;
183         case DW_FORM_strp:
184                 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size);
185                 atref.u[1].s = _dwarf_strtab_get_table(dbg) + atref.u[0].u64;
186                 break;
187         case DW_FORM_ref_sig8:
188                 atref.u[0].u64 = 8;
189                 atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
190                     atref.u[0].u64);
191                 break;
192         case DW_FORM_flag_present:
193                 /* This form has no value encoded in the DIE. */
194                 atref.u[0].u64 = 1;
195                 break;
196         default:
197                 DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
198                 ret = DW_DLE_ATTR_FORM_BAD;
199                 break;
200         }
201
202         if (ret == DW_DLE_NONE) {
203                 if (form == DW_FORM_block || form == DW_FORM_block1 ||
204                     form == DW_FORM_block2 || form == DW_FORM_block4) {
205                         atref.at_block.bl_len = atref.u[0].u64;
206                         atref.at_block.bl_data = atref.u[1].u8p;
207                 }
208                 ret = _dwarf_attr_add(die, &atref, NULL, error);
209         }
210
211         return (ret);
212 }
213
214 static int
215 _dwarf_attr_write(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs,
216     Dwarf_CU cu, Dwarf_Attribute at, int pass2, Dwarf_Error *error)
217 {
218         struct _Dwarf_P_Expr_Entry *ee;
219         uint64_t value, offset, bs;
220         int ret;
221
222         assert(dbg != NULL && ds != NULL && cu != NULL && at != NULL);
223
224         /* Fill in reference to other DIE in the second pass. */
225         if (pass2) {
226                 if (at->at_form != DW_FORM_ref4 && at->at_form != DW_FORM_ref8)
227                         return (DW_DLE_NONE);
228                 if (at->at_refdie == NULL || at->at_offset == 0)
229                         return (DW_DLE_NONE);
230                 offset = at->at_offset;
231                 dbg->write(ds->ds_data, &offset, at->at_refdie->die_offset,
232                     at->at_form == DW_FORM_ref4 ? 4 : 8);
233                 return (DW_DLE_NONE);
234         }
235
236         switch (at->at_form) {
237         case DW_FORM_addr:
238                 if (at->at_relsym)
239                         ret = _dwarf_reloc_entry_add(dbg, drs, ds,
240                             dwarf_drt_data_reloc, cu->cu_pointer_size,
241                             ds->ds_size, at->at_relsym, at->u[0].u64, NULL,
242                             error);
243                 else
244                         ret = WRITE_VALUE(at->u[0].u64, cu->cu_pointer_size);
245                 break;
246         case DW_FORM_block:
247         case DW_FORM_block1:
248         case DW_FORM_block2:
249         case DW_FORM_block4:
250                 /* Write block size. */
251                 if (at->at_form == DW_FORM_block) {
252                         ret = _dwarf_write_uleb128_alloc(&ds->ds_data,
253                             &ds->ds_cap, &ds->ds_size, at->u[0].u64, error);
254                         if (ret != DW_DLE_NONE)
255                                 break;
256                 } else {
257                         if (at->at_form == DW_FORM_block1)
258                                 bs = 1;
259                         else if (at->at_form == DW_FORM_block2)
260                                 bs = 2;
261                         else
262                                 bs = 4;
263                         ret = WRITE_VALUE(at->u[0].u64, bs);
264                         if (ret != DW_DLE_NONE)
265                                 break;
266                 }
267
268                 /* Keep block data offset for later use. */
269                 offset = ds->ds_size;
270
271                 /* Write block data. */
272                 ret = WRITE_BLOCK(at->u[1].u8p, at->u[0].u64);
273                 if (ret != DW_DLE_NONE)
274                         break;
275                 if (at->at_expr == NULL)
276                         break;
277
278                 /* Generate relocation entry for DW_OP_addr expressions. */
279                 STAILQ_FOREACH(ee, &at->at_expr->pe_eelist, ee_next) {
280                         if (ee->ee_loc.lr_atom != DW_OP_addr || ee->ee_sym == 0)
281                                 continue;
282                         ret = _dwarf_reloc_entry_add(dbg, drs, ds,
283                             dwarf_drt_data_reloc, dbg->dbg_pointer_size,
284                             offset + ee->ee_loc.lr_offset + 1, ee->ee_sym,
285                             ee->ee_loc.lr_number, NULL, error);
286                         if (ret != DW_DLE_NONE)
287                                 break;
288                 }
289                 break;
290         case DW_FORM_data1:
291         case DW_FORM_flag:
292         case DW_FORM_ref1:
293                 ret = WRITE_VALUE(at->u[0].u64, 1);
294                 break;
295         case DW_FORM_data2:
296         case DW_FORM_ref2:
297                 ret = WRITE_VALUE(at->u[0].u64, 2);
298                 break;
299         case DW_FORM_data4:
300                 if (at->at_relsym || at->at_relsec != NULL)
301                         ret = _dwarf_reloc_entry_add(dbg, drs, ds,
302                             dwarf_drt_data_reloc, 4, ds->ds_size, at->at_relsym,
303                             at->u[0].u64, at->at_relsec, error);
304                 else
305                         ret = WRITE_VALUE(at->u[0].u64, 4);
306                 break;
307         case DW_FORM_data8:
308                 if (at->at_relsym || at->at_relsec != NULL)
309                         ret = _dwarf_reloc_entry_add(dbg, drs, ds,
310                             dwarf_drt_data_reloc, 8, ds->ds_size, at->at_relsym,
311                             at->u[0].u64, at->at_relsec, error);
312                 else
313                         ret = WRITE_VALUE(at->u[0].u64, 8);
314                 break;
315         case DW_FORM_ref4:
316         case DW_FORM_ref8:
317                 /*
318                  * The value of ref4 and ref8 could be a reference to another
319                  * DIE within the CU. And if we don't know the ref DIE's
320                  * offset at the moement, then we remember at_offset and fill
321                  * it in the second pass.
322                  */
323                 if (at->at_refdie) {
324                         value = at->at_refdie->die_offset;
325                         if (value == 0) {
326                                 cu->cu_pass2 = 1;
327                                 at->at_offset = ds->ds_size;
328                         }
329                 } else
330                         value = at->u[0].u64;
331                 ret = WRITE_VALUE(value, at->at_form == DW_FORM_ref4 ? 4 : 8);
332                 break;
333         case DW_FORM_indirect:
334                 /* TODO. */
335                 DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
336                 ret = DW_DLE_ATTR_FORM_BAD;
337                 break;
338         case DW_FORM_ref_addr:
339                 /* DWARF2 format. */
340                 if (at->at_relsym)
341                         ret = _dwarf_reloc_entry_add(dbg, drs, ds,
342                             dwarf_drt_data_reloc, cu->cu_pointer_size,
343                             ds->ds_size, at->at_relsym, at->u[0].u64, NULL,
344                             error);
345                 else
346                         ret = WRITE_VALUE(at->u[0].u64, cu->cu_pointer_size);
347                 break;
348         case DW_FORM_ref_udata:
349         case DW_FORM_udata:
350                 ret = WRITE_ULEB128(at->u[0].u64);
351                 break;
352         case DW_FORM_sdata:
353                 ret = WRITE_SLEB128(at->u[0].s64);
354                 break;
355         case DW_FORM_string:
356                 assert(at->u[0].s != NULL);
357                 ret = WRITE_STRING(at->u[0].s);
358                 break;
359         case DW_FORM_strp:
360                 ret = _dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc,
361                     4, ds->ds_size, 0, at->u[0].u64, ".debug_str", error);
362                 break;
363         default:
364                 DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
365                 ret = DW_DLE_ATTR_FORM_BAD;
366                 break;
367         }
368
369         return (ret);
370 }
371
372 int
373 _dwarf_add_AT_dataref(Dwarf_P_Debug dbg, Dwarf_P_Die die, Dwarf_Half attr,
374     Dwarf_Unsigned pc_value, Dwarf_Unsigned sym_index, const char *secname,
375     Dwarf_P_Attribute *atp, Dwarf_Error *error)
376 {
377         Dwarf_Attribute at;
378         int ret;
379
380         assert(dbg != NULL && die != NULL);
381
382         if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE)
383                 return (ret);
384
385         at->at_die = die;
386         at->at_attrib = attr;
387         if (dbg->dbg_pointer_size == 4)
388                 at->at_form = DW_FORM_data4;
389         else
390                 at->at_form = DW_FORM_data8;
391         at->at_relsym = sym_index;
392         at->at_relsec = secname;
393         at->u[0].u64 = pc_value;
394
395         STAILQ_INSERT_TAIL(&die->die_attr, at, at_next);
396
397         if (atp)
398                 *atp = at;
399
400         return (DW_DLE_NONE);
401 }
402
403 int
404 _dwarf_add_string_attr(Dwarf_P_Die die, Dwarf_P_Attribute *atp, Dwarf_Half attr,
405     char *string, Dwarf_Error *error)
406 {
407         Dwarf_Attribute at;
408         Dwarf_Debug dbg;
409         int ret;
410
411         dbg = die != NULL ? die->die_dbg : NULL;
412
413         assert(atp != NULL);
414
415         if (die == NULL || string == NULL) {
416                 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
417                 return (DW_DLE_ARGUMENT);
418         }
419
420         if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE)
421                 return (ret);
422
423         at->at_die = die;
424         at->at_attrib = attr;
425         at->at_form = DW_FORM_strp;
426         if ((ret = _dwarf_strtab_add(dbg, string, &at->u[0].u64,
427             error)) != DW_DLE_NONE) {
428                 free(at);
429                 return (ret);
430         }
431         at->u[1].s = _dwarf_strtab_get_table(dbg) + at->u[0].u64;
432
433         *atp = at;
434
435         STAILQ_INSERT_TAIL(&die->die_attr, at, at_next);
436
437         return (DW_DLE_NONE);
438 }
439
440 int
441 _dwarf_attr_gen(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs,
442     Dwarf_CU cu, Dwarf_Die die, int pass2, Dwarf_Error *error)
443 {
444         Dwarf_Attribute at;
445         int ret;
446
447         assert(dbg != NULL && ds != NULL && cu != NULL && die != NULL);
448
449         STAILQ_FOREACH(at, &die->die_attr, at_next) {
450                 ret = _dwarf_attr_write(dbg, ds, drs, cu, at, pass2, error);
451                 if (ret != DW_DLE_NONE)
452                         return (ret);
453         }
454
455         return (DW_DLE_NONE);
456 }