| Ulrich Drepper | b08d5a8 | 2005-07-26 05:00:05 +0000 | [diff] [blame] | 1 | /* Get macro information. | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 2 | Copyright (C) 2002-2009, 2014 Red Hat, Inc. | 
| Mark Wielaard | de2ed97 | 2012-06-05 17:15:16 +0200 | [diff] [blame] | 3 | This file is part of elfutils. | 
| Ulrich Drepper | b08d5a8 | 2005-07-26 05:00:05 +0000 | [diff] [blame] | 4 | Written by Ulrich Drepper <drepper@redhat.com>, 2002. | 
|  | 5 |  | 
| Mark Wielaard | de2ed97 | 2012-06-05 17:15:16 +0200 | [diff] [blame] | 6 | This file is free software; you can redistribute it and/or modify | 
|  | 7 | it under the terms of either | 
| Ulrich Drepper | b08d5a8 | 2005-07-26 05:00:05 +0000 | [diff] [blame] | 8 |  | 
| Mark Wielaard | de2ed97 | 2012-06-05 17:15:16 +0200 | [diff] [blame] | 9 | * the GNU Lesser General Public License as published by the Free | 
|  | 10 | Software Foundation; either version 3 of the License, or (at | 
|  | 11 | your option) any later version | 
|  | 12 |  | 
|  | 13 | or | 
|  | 14 |  | 
|  | 15 | * the GNU General Public License as published by the Free | 
|  | 16 | Software Foundation; either version 2 of the License, or (at | 
|  | 17 | your option) any later version | 
|  | 18 |  | 
|  | 19 | or both in parallel, as here. | 
|  | 20 |  | 
|  | 21 | elfutils is distributed in the hope that it will be useful, but | 
| Ulrich Drepper | 361df7d | 2006-04-04 21:38:57 +0000 | [diff] [blame] | 22 | WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 23 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | 24 | General Public License for more details. | 
|  | 25 |  | 
| Mark Wielaard | de2ed97 | 2012-06-05 17:15:16 +0200 | [diff] [blame] | 26 | You should have received copies of the GNU General Public License and | 
|  | 27 | the GNU Lesser General Public License along with this program.  If | 
|  | 28 | not, see <http://www.gnu.org/licenses/>.  */ | 
| Ulrich Drepper | b08d5a8 | 2005-07-26 05:00:05 +0000 | [diff] [blame] | 29 |  | 
|  | 30 | #ifdef HAVE_CONFIG_H | 
|  | 31 | # include <config.h> | 
|  | 32 | #endif | 
|  | 33 |  | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 34 | #include <assert.h> | 
| Ulrich Drepper | b08d5a8 | 2005-07-26 05:00:05 +0000 | [diff] [blame] | 35 | #include <dwarf.h> | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 36 | #include <search.h> | 
|  | 37 | #include <stdlib.h> | 
| Ulrich Drepper | b08d5a8 | 2005-07-26 05:00:05 +0000 | [diff] [blame] | 38 | #include <string.h> | 
|  | 39 |  | 
|  | 40 | #include <libdwP.h> | 
|  | 41 |  | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 42 | static int | 
|  | 43 | get_offset_from (Dwarf_Die *die, int name, Dwarf_Word *retp) | 
|  | 44 | { | 
|  | 45 | /* Get the appropriate attribute.  */ | 
|  | 46 | Dwarf_Attribute attr; | 
|  | 47 | if (INTUSE(dwarf_attr) (die, name, &attr) == NULL) | 
|  | 48 | return -1; | 
|  | 49 |  | 
|  | 50 | /* Offset into the corresponding section.  */ | 
|  | 51 | return INTUSE(dwarf_formudata) (&attr, retp); | 
|  | 52 | } | 
|  | 53 |  | 
|  | 54 | static int | 
|  | 55 | macro_op_compare (const void *p1, const void *p2) | 
|  | 56 | { | 
|  | 57 | const Dwarf_Macro_Op_Table *t1 = (const Dwarf_Macro_Op_Table *) p1; | 
|  | 58 | const Dwarf_Macro_Op_Table *t2 = (const Dwarf_Macro_Op_Table *) p2; | 
|  | 59 |  | 
|  | 60 | if (t1->offset < t2->offset) | 
|  | 61 | return -1; | 
|  | 62 | if (t1->offset > t2->offset) | 
|  | 63 | return 1; | 
|  | 64 |  | 
|  | 65 | if (t1->sec_index < t2->sec_index) | 
|  | 66 | return -1; | 
|  | 67 | if (t1->sec_index > t2->sec_index) | 
|  | 68 | return 1; | 
|  | 69 |  | 
|  | 70 | return 0; | 
|  | 71 | } | 
|  | 72 |  | 
|  | 73 | static void | 
|  | 74 | build_table (Dwarf_Macro_Op_Table *table, | 
|  | 75 | Dwarf_Macro_Op_Proto op_protos[static 255]) | 
|  | 76 | { | 
|  | 77 | unsigned ct = 0; | 
|  | 78 | for (unsigned i = 1; i < 256; ++i) | 
|  | 79 | if (op_protos[i - 1].forms != NULL) | 
|  | 80 | table->table[table->opcodes[i - 1] = ct++] = op_protos[i - 1]; | 
|  | 81 | else | 
|  | 82 | table->opcodes[i - 1] = 0xff; | 
|  | 83 | } | 
|  | 84 |  | 
|  | 85 | #define MACRO_PROTO(NAME, ...)					\ | 
|  | 86 | Dwarf_Macro_Op_Proto NAME = ({				\ | 
|  | 87 | static const uint8_t proto[] = {__VA_ARGS__};		\ | 
|  | 88 | (Dwarf_Macro_Op_Proto) {sizeof proto, proto};		\ | 
|  | 89 | }) | 
|  | 90 |  | 
|  | 91 | enum { macinfo_data_size = offsetof (Dwarf_Macro_Op_Table, table[5]) }; | 
|  | 92 | static unsigned char macinfo_data[macinfo_data_size] | 
|  | 93 | __attribute__ ((aligned (__alignof (Dwarf_Macro_Op_Table)))); | 
|  | 94 |  | 
|  | 95 | static __attribute__ ((constructor)) void | 
|  | 96 | init_macinfo_table (void) | 
|  | 97 | { | 
|  | 98 | MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string); | 
|  | 99 | MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata); | 
|  | 100 | MACRO_PROTO (p_none); | 
|  | 101 |  | 
|  | 102 | Dwarf_Macro_Op_Proto op_protos[255] = | 
|  | 103 | { | 
|  | 104 | [DW_MACINFO_define - 1] = p_udata_str, | 
|  | 105 | [DW_MACINFO_undef - 1] = p_udata_str, | 
|  | 106 | [DW_MACINFO_vendor_ext - 1] = p_udata_str, | 
|  | 107 | [DW_MACINFO_start_file - 1] = p_udata_udata, | 
|  | 108 | [DW_MACINFO_end_file - 1] = p_none, | 
|  | 109 | /* If you are adding more elements to this array, increase | 
|  | 110 | MACINFO_DATA_SIZE above.  */ | 
|  | 111 | }; | 
|  | 112 |  | 
|  | 113 | Dwarf_Macro_Op_Table *macinfo_table = (void *) macinfo_data; | 
|  | 114 | memset (macinfo_table, 0, sizeof macinfo_data); | 
|  | 115 | build_table (macinfo_table, op_protos); | 
|  | 116 | macinfo_table->sec_index = IDX_debug_macinfo; | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | static Dwarf_Macro_Op_Table * | 
|  | 120 | get_macinfo_table (Dwarf *dbg, Dwarf_Word macoff, Dwarf_Die *cudie) | 
|  | 121 | { | 
|  | 122 | assert (cudie != NULL); | 
|  | 123 |  | 
|  | 124 | Dwarf_Attribute attr_mem, *attr | 
|  | 125 | = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem); | 
|  | 126 | Dwarf_Off line_offset = (Dwarf_Off) -1; | 
|  | 127 | if (attr != NULL) | 
|  | 128 | INTUSE(dwarf_formudata) (attr, &line_offset); | 
|  | 129 |  | 
|  | 130 | Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table, | 
|  | 131 | macinfo_data_size, 1); | 
|  | 132 | memcpy (table, macinfo_data, macinfo_data_size); | 
|  | 133 |  | 
|  | 134 | table->offset = macoff; | 
|  | 135 | table->sec_index = IDX_debug_macinfo; | 
|  | 136 | table->line_offset = line_offset; | 
|  | 137 | table->is_64bit = cudie->cu->address_size == 8; | 
|  | 138 | table->comp_dir = __libdw_getcompdir (cudie); | 
|  | 139 |  | 
|  | 140 | return table; | 
|  | 141 | } | 
|  | 142 |  | 
|  | 143 | static Dwarf_Macro_Op_Table * | 
|  | 144 | get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff, | 
|  | 145 | const unsigned char *readp, | 
|  | 146 | const unsigned char *const endp, | 
|  | 147 | Dwarf_Die *cudie) | 
|  | 148 | { | 
|  | 149 | const unsigned char *startp = readp; | 
|  | 150 |  | 
|  | 151 | /* Request at least 3 bytes for header.  */ | 
|  | 152 | if (readp + 3 > endp) | 
|  | 153 | { | 
|  | 154 | invalid_dwarf: | 
|  | 155 | __libdw_seterrno (DWARF_E_INVALID_DWARF); | 
|  | 156 | return NULL; | 
|  | 157 | } | 
|  | 158 |  | 
|  | 159 | uint16_t version = read_2ubyte_unaligned_inc (dbg, readp); | 
|  | 160 | if (version != 4) | 
|  | 161 | { | 
|  | 162 | __libdw_seterrno (DWARF_E_INVALID_VERSION); | 
|  | 163 | return NULL; | 
|  | 164 | } | 
|  | 165 |  | 
|  | 166 | uint8_t flags = *readp++; | 
|  | 167 | bool is_64bit = (flags & 0x1) != 0; | 
|  | 168 |  | 
|  | 169 | Dwarf_Off line_offset = (Dwarf_Off) -1; | 
|  | 170 | if ((flags & 0x2) != 0) | 
|  | 171 | { | 
|  | 172 | line_offset = read_addr_unaligned_inc (is_64bit ? 8 : 4, dbg, readp); | 
|  | 173 | if (readp > endp) | 
|  | 174 | goto invalid_dwarf; | 
|  | 175 | } | 
|  | 176 | else if (cudie != NULL) | 
|  | 177 | { | 
|  | 178 | Dwarf_Attribute attr_mem, *attr | 
|  | 179 | = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem); | 
|  | 180 | if (attr != NULL) | 
|  | 181 | INTUSE(dwarf_formudata) (attr, &line_offset); | 
|  | 182 | } | 
|  | 183 |  | 
|  | 184 | /* """The macinfo entry types defined in this standard may, but | 
|  | 185 | might not, be described in the table""". | 
|  | 186 |  | 
|  | 187 | I.e. these may be present.  It's tempting to simply skip them, | 
|  | 188 | but it's probably more correct to tolerate that a producer tweaks | 
|  | 189 | the way certain opcodes are encoded, for whatever reasons.  */ | 
|  | 190 |  | 
|  | 191 | MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string); | 
|  | 192 | MACRO_PROTO (p_udata_strp, DW_FORM_udata, DW_FORM_strp); | 
|  | 193 | MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata); | 
|  | 194 | MACRO_PROTO (p_secoffset, DW_FORM_sec_offset); | 
|  | 195 | MACRO_PROTO (p_none); | 
|  | 196 |  | 
|  | 197 | Dwarf_Macro_Op_Proto op_protos[255] = | 
|  | 198 | { | 
|  | 199 | [DW_MACRO_GNU_define - 1] = p_udata_str, | 
|  | 200 | [DW_MACRO_GNU_undef - 1] = p_udata_str, | 
|  | 201 | [DW_MACRO_GNU_define_indirect - 1] = p_udata_strp, | 
|  | 202 | [DW_MACRO_GNU_undef_indirect - 1] = p_udata_strp, | 
|  | 203 | [DW_MACRO_GNU_start_file - 1] = p_udata_udata, | 
|  | 204 | [DW_MACRO_GNU_end_file - 1] = p_none, | 
|  | 205 | [DW_MACRO_GNU_transparent_include - 1] = p_secoffset, | 
|  | 206 | /* N.B. DW_MACRO_undef_indirectx, DW_MACRO_define_indirectx | 
|  | 207 | should be added when 130313.1 is supported.  */ | 
|  | 208 | }; | 
|  | 209 |  | 
|  | 210 | if ((flags & 0x4) != 0) | 
|  | 211 | { | 
|  | 212 | unsigned count = *readp++; | 
|  | 213 | for (unsigned i = 0; i < count; ++i) | 
|  | 214 | { | 
|  | 215 | unsigned opcode = *readp++; | 
|  | 216 |  | 
|  | 217 | Dwarf_Macro_Op_Proto e; | 
|  | 218 | get_uleb128 (e.nforms, readp); // XXX checking | 
|  | 219 | e.forms = readp; | 
|  | 220 | op_protos[opcode - 1] = e; | 
|  | 221 |  | 
|  | 222 | readp += e.nforms; | 
|  | 223 | if (readp > endp) | 
|  | 224 | { | 
|  | 225 | __libdw_seterrno (DWARF_E_INVALID_DWARF); | 
|  | 226 | return NULL; | 
|  | 227 | } | 
|  | 228 | } | 
|  | 229 | } | 
|  | 230 |  | 
|  | 231 | size_t ct = 0; | 
|  | 232 | for (unsigned i = 1; i < 256; ++i) | 
|  | 233 | if (op_protos[i - 1].forms != NULL) | 
|  | 234 | ++ct; | 
|  | 235 |  | 
|  | 236 | /* We support at most 0xfe opcodes defined in the table, as 0xff is | 
|  | 237 | a value that means that given opcode is not stored at all.  But | 
|  | 238 | that should be fine, as opcode 0 is not allocated.  */ | 
|  | 239 | assert (ct < 0xff); | 
|  | 240 |  | 
|  | 241 | size_t macop_table_size = offsetof (Dwarf_Macro_Op_Table, table[ct]); | 
|  | 242 |  | 
|  | 243 | Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table, | 
|  | 244 | macop_table_size, 1); | 
|  | 245 |  | 
|  | 246 | *table = (Dwarf_Macro_Op_Table) { | 
|  | 247 | .offset = macoff, | 
|  | 248 | .sec_index = IDX_debug_macro, | 
|  | 249 | .line_offset = line_offset, | 
|  | 250 | .header_len = readp - startp, | 
|  | 251 | .version = version, | 
|  | 252 | .is_64bit = is_64bit, | 
|  | 253 |  | 
|  | 254 | /* NULL if CUDIE is NULL or DW_AT_comp_dir is absent.  */ | 
|  | 255 | .comp_dir = __libdw_getcompdir (cudie), | 
|  | 256 | }; | 
|  | 257 | build_table (table, op_protos); | 
|  | 258 |  | 
|  | 259 | return table; | 
|  | 260 | } | 
|  | 261 |  | 
|  | 262 | static Dwarf_Macro_Op_Table * | 
|  | 263 | cache_op_table (Dwarf *dbg, int sec_index, Dwarf_Off macoff, | 
|  | 264 | const unsigned char *startp, | 
|  | 265 | const unsigned char *const endp, | 
|  | 266 | Dwarf_Die *cudie) | 
|  | 267 | { | 
|  | 268 | Dwarf_Macro_Op_Table fake = { .offset = macoff, .sec_index = sec_index }; | 
|  | 269 | Dwarf_Macro_Op_Table **found = tfind (&fake, &dbg->macro_ops, | 
|  | 270 | macro_op_compare); | 
|  | 271 | if (found != NULL) | 
|  | 272 | return *found; | 
|  | 273 |  | 
|  | 274 | Dwarf_Macro_Op_Table *table = sec_index == IDX_debug_macro | 
|  | 275 | ? get_table_for_offset (dbg, macoff, startp, endp, cudie) | 
|  | 276 | : get_macinfo_table (dbg, macoff, cudie); | 
|  | 277 |  | 
|  | 278 | if (table == NULL) | 
|  | 279 | return NULL; | 
|  | 280 |  | 
|  | 281 | Dwarf_Macro_Op_Table **ret = tsearch (table, &dbg->macro_ops, | 
|  | 282 | macro_op_compare); | 
|  | 283 | if (unlikely (ret == NULL)) | 
|  | 284 | { | 
|  | 285 | __libdw_seterrno (DWARF_E_NOMEM); | 
|  | 286 | return NULL; | 
|  | 287 | } | 
|  | 288 |  | 
|  | 289 | return *ret; | 
|  | 290 | } | 
|  | 291 |  | 
|  | 292 | static ptrdiff_t | 
|  | 293 | read_macros (Dwarf *dbg, int sec_index, | 
|  | 294 | Dwarf_Off macoff, int (*callback) (Dwarf_Macro *, void *), | 
|  | 295 | void *arg, ptrdiff_t offset, bool accept_0xff, | 
|  | 296 | Dwarf_Die *cudie) | 
|  | 297 | { | 
|  | 298 | Elf_Data *d = dbg->sectiondata[sec_index]; | 
|  | 299 | if (unlikely (d == NULL || d->d_buf == NULL)) | 
|  | 300 | { | 
|  | 301 | __libdw_seterrno (DWARF_E_NO_ENTRY); | 
|  | 302 | return -1; | 
|  | 303 | } | 
|  | 304 |  | 
|  | 305 | if (unlikely (macoff >= d->d_size)) | 
|  | 306 | { | 
|  | 307 | __libdw_seterrno (DWARF_E_INVALID_DWARF); | 
|  | 308 | return -1; | 
|  | 309 | } | 
|  | 310 |  | 
|  | 311 | const unsigned char *const startp = d->d_buf + macoff; | 
|  | 312 | const unsigned char *const endp = d->d_buf + d->d_size; | 
|  | 313 |  | 
|  | 314 | Dwarf_Macro_Op_Table *table = cache_op_table (dbg, sec_index, macoff, | 
|  | 315 | startp, endp, cudie); | 
|  | 316 | if (table == NULL) | 
|  | 317 | return -1; | 
|  | 318 |  | 
|  | 319 | if (offset == 0) | 
|  | 320 | offset = table->header_len; | 
|  | 321 |  | 
|  | 322 | assert (offset >= 0); | 
|  | 323 | assert (offset < endp - startp); | 
|  | 324 | const unsigned char *readp = startp + offset; | 
|  | 325 |  | 
|  | 326 | while (readp < endp) | 
|  | 327 | { | 
|  | 328 | unsigned int opcode = *readp++; | 
|  | 329 | if (opcode == 0) | 
|  | 330 | /* Nothing more to do.  */ | 
|  | 331 | return 0; | 
|  | 332 |  | 
|  | 333 | if (unlikely (opcode == 0xff && ! accept_0xff)) | 
|  | 334 | { | 
|  | 335 | /* See comment below at dwarf_getmacros for explanation of | 
|  | 336 | why we are doing this.  */ | 
|  | 337 | __libdw_seterrno (DWARF_E_INVALID_OPCODE); | 
|  | 338 | return -1; | 
|  | 339 | } | 
|  | 340 |  | 
|  | 341 | unsigned int idx = table->opcodes[opcode - 1]; | 
|  | 342 | if (idx == 0xff) | 
|  | 343 | { | 
|  | 344 | __libdw_seterrno (DWARF_E_INVALID_OPCODE); | 
|  | 345 | return -1; | 
|  | 346 | } | 
|  | 347 |  | 
|  | 348 | Dwarf_Macro_Op_Proto *proto = &table->table[idx]; | 
|  | 349 |  | 
|  | 350 | /* A fake CU with bare minimum data to fool dwarf_formX into | 
|  | 351 | doing the right thing with the attributes that we put out. | 
|  | 352 | We arbitrarily pretend it's version 4.  */ | 
|  | 353 | Dwarf_CU fake_cu = { | 
|  | 354 | .dbg = dbg, | 
|  | 355 | .version = 4, | 
|  | 356 | .offset_size = table->is_64bit ? 8 : 4, | 
|  | 357 | }; | 
|  | 358 |  | 
|  | 359 | Dwarf_Attribute attributes[proto->nforms]; | 
|  | 360 | for (Dwarf_Word i = 0; i < proto->nforms; ++i) | 
|  | 361 | { | 
|  | 362 | /* We pretend this is a DW_AT_GNU_macros attribute so that | 
|  | 363 | DW_FORM_sec_offset forms get correctly interpreted as | 
|  | 364 | offset into .debug_macro.  */ | 
|  | 365 | attributes[i].code = DW_AT_GNU_macros; | 
|  | 366 | attributes[i].form = proto->forms[i]; | 
|  | 367 | attributes[i].valp = (void *) readp; | 
|  | 368 | attributes[i].cu = &fake_cu; | 
|  | 369 |  | 
| Mark Wielaard | cb73b5a | 2014-12-04 21:43:44 +0100 | [diff] [blame^] | 370 | size_t len = __libdw_form_val_len (dbg, &fake_cu, | 
|  | 371 | proto->forms[i], readp, endp); | 
|  | 372 | if (len == (size_t) -1) | 
|  | 373 | return -1; | 
|  | 374 |  | 
|  | 375 | readp += len; | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 376 | } | 
|  | 377 |  | 
|  | 378 | Dwarf_Macro macro = { | 
|  | 379 | .table = table, | 
|  | 380 | .opcode = opcode, | 
|  | 381 | .attributes = attributes, | 
|  | 382 | }; | 
|  | 383 |  | 
|  | 384 | if (callback (¯o, arg) != DWARF_CB_OK) | 
|  | 385 | return readp - startp; | 
|  | 386 | } | 
|  | 387 |  | 
|  | 388 | return 0; | 
|  | 389 | } | 
|  | 390 |  | 
| Petr Machata | edb079a | 2014-12-02 21:22:14 +0100 | [diff] [blame] | 391 | /* Token layout: | 
|  | 392 |  | 
|  | 393 | - The highest bit is used for distinguishing between callers that | 
|  | 394 | know that opcode 0xff may have one of two incompatible meanings. | 
|  | 395 | The mask that we use for selecting this bit is | 
|  | 396 | DWARF_GETMACROS_START. | 
|  | 397 |  | 
|  | 398 | - The rest of the token (31 or 63 bits) encodes address inside the | 
|  | 399 | macro unit. | 
|  | 400 |  | 
|  | 401 | Besides, token value of 0 signals end of iteration and -1 is | 
|  | 402 | reserved for signaling errors.  That means it's impossible to | 
|  | 403 | represent maximum offset of a .debug_macro unit to new-style | 
|  | 404 | callers (which in practice decreases the permissible macro unit | 
|  | 405 | size by another 1 byte).  */ | 
|  | 406 |  | 
|  | 407 | static ptrdiff_t | 
|  | 408 | token_from_offset (ptrdiff_t offset, bool accept_0xff) | 
|  | 409 | { | 
|  | 410 | if (offset == -1 || offset == 0) | 
|  | 411 | return offset; | 
|  | 412 |  | 
|  | 413 | /* Make sure the offset didn't overflow into the flag bit.  */ | 
|  | 414 | if ((offset & DWARF_GETMACROS_START) != 0) | 
|  | 415 | { | 
|  | 416 | __libdw_seterrno (DWARF_E_TOO_BIG); | 
|  | 417 | return -1; | 
|  | 418 | } | 
|  | 419 |  | 
|  | 420 | if (accept_0xff) | 
|  | 421 | offset |= DWARF_GETMACROS_START; | 
|  | 422 |  | 
|  | 423 | return offset; | 
|  | 424 | } | 
|  | 425 |  | 
|  | 426 | static ptrdiff_t | 
|  | 427 | offset_from_token (ptrdiff_t token, bool *accept_0xffp) | 
|  | 428 | { | 
|  | 429 | *accept_0xffp = (token & DWARF_GETMACROS_START) != 0; | 
|  | 430 | token &= ~DWARF_GETMACROS_START; | 
|  | 431 |  | 
|  | 432 | return token; | 
|  | 433 | } | 
|  | 434 |  | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 435 | static ptrdiff_t | 
|  | 436 | gnu_macros_getmacros_off (Dwarf *dbg, Dwarf_Off macoff, | 
|  | 437 | int (*callback) (Dwarf_Macro *, void *), | 
| Petr Machata | edb079a | 2014-12-02 21:22:14 +0100 | [diff] [blame] | 438 | void *arg, ptrdiff_t offset, bool accept_0xff, | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 439 | Dwarf_Die *cudie) | 
|  | 440 | { | 
| Petr Machata | edb079a | 2014-12-02 21:22:14 +0100 | [diff] [blame] | 441 | assert (offset >= 0); | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 442 |  | 
|  | 443 | if (macoff >= dbg->sectiondata[IDX_debug_macro]->d_size) | 
|  | 444 | { | 
|  | 445 | __libdw_seterrno (DWARF_E_INVALID_OFFSET); | 
|  | 446 | return -1; | 
|  | 447 | } | 
|  | 448 |  | 
| Petr Machata | edb079a | 2014-12-02 21:22:14 +0100 | [diff] [blame] | 449 | return read_macros (dbg, IDX_debug_macro, macoff, | 
|  | 450 | callback, arg, offset, accept_0xff, cudie); | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 451 | } | 
|  | 452 |  | 
|  | 453 | static ptrdiff_t | 
|  | 454 | macro_info_getmacros_off (Dwarf *dbg, Dwarf_Off macoff, | 
|  | 455 | int (*callback) (Dwarf_Macro *, void *), | 
| Petr Machata | edb079a | 2014-12-02 21:22:14 +0100 | [diff] [blame] | 456 | void *arg, ptrdiff_t offset, Dwarf_Die *cudie) | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 457 | { | 
| Petr Machata | edb079a | 2014-12-02 21:22:14 +0100 | [diff] [blame] | 458 | assert (offset >= 0); | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 459 |  | 
|  | 460 | return read_macros (dbg, IDX_debug_macinfo, macoff, | 
| Petr Machata | edb079a | 2014-12-02 21:22:14 +0100 | [diff] [blame] | 461 | callback, arg, offset, true, cudie); | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 462 | } | 
|  | 463 |  | 
|  | 464 | ptrdiff_t | 
|  | 465 | dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff, | 
|  | 466 | int (*callback) (Dwarf_Macro *, void *), | 
|  | 467 | void *arg, ptrdiff_t token) | 
|  | 468 | { | 
|  | 469 | if (dbg == NULL) | 
|  | 470 | { | 
|  | 471 | __libdw_seterrno (DWARF_E_NO_DWARF); | 
|  | 472 | return -1; | 
|  | 473 | } | 
|  | 474 |  | 
| Petr Machata | edb079a | 2014-12-02 21:22:14 +0100 | [diff] [blame] | 475 | bool accept_0xff; | 
|  | 476 | ptrdiff_t offset = offset_from_token (token, &accept_0xff); | 
|  | 477 | assert (accept_0xff); | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 478 |  | 
| Petr Machata | edb079a | 2014-12-02 21:22:14 +0100 | [diff] [blame] | 479 | offset = gnu_macros_getmacros_off (dbg, macoff, callback, arg, offset, | 
|  | 480 | accept_0xff, NULL); | 
|  | 481 |  | 
|  | 482 | return token_from_offset (offset, accept_0xff); | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 483 | } | 
|  | 484 |  | 
| Petr Machata | edb079a | 2014-12-02 21:22:14 +0100 | [diff] [blame] | 485 | ptrdiff_t | 
|  | 486 | dwarf_getmacros (cudie, callback, arg, token) | 
|  | 487 | Dwarf_Die *cudie; | 
|  | 488 | int (*callback) (Dwarf_Macro *, void *); | 
|  | 489 | void *arg; | 
|  | 490 | ptrdiff_t token; | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 491 | { | 
|  | 492 | if (cudie == NULL) | 
|  | 493 | { | 
|  | 494 | __libdw_seterrno (DWARF_E_NO_DWARF); | 
|  | 495 | return -1; | 
|  | 496 | } | 
|  | 497 |  | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 498 | /* This function might be called from a code that expects to see | 
|  | 499 | DW_MACINFO_* opcodes, not DW_MACRO_{GNU_,}* ones.  It is fine to | 
|  | 500 | serve most DW_MACRO_{GNU_,}* opcodes to such code, because those | 
|  | 501 | whose values are the same as DW_MACINFO_* ones also have the same | 
|  | 502 | behavior.  It is not very likely that a .debug_macro section | 
|  | 503 | would only use the part of opcode space that it shares with | 
|  | 504 | .debug_macinfo, but it is possible.  Serving the opcodes that are | 
|  | 505 | only valid in DW_MACRO_{GNU_,}* domain is OK as well, because | 
|  | 506 | clients in general need to be ready that newer standards define | 
|  | 507 | more opcodes, and have coping mechanisms for unfamiliar opcodes. | 
| Roland McGrath | e7c1633 | 2009-05-07 18:57:18 -0700 | [diff] [blame] | 508 |  | 
| Petr Machata | fb90bf3 | 2014-10-17 02:47:03 +0200 | [diff] [blame] | 509 | The one exception to the above rule is opcode 0xff, which has | 
|  | 510 | concrete semantics in .debug_macinfo, but falls into vendor block | 
|  | 511 | in .debug_macro, and can be assigned to do whatever.  There is | 
|  | 512 | some small probability that the two opcodes would look | 
|  | 513 | superficially similar enough that a client would be confused and | 
|  | 514 | misbehave as a result.  For this reason, we refuse to serve | 
| Petr Machata | edb079a | 2014-12-02 21:22:14 +0100 | [diff] [blame] | 515 | through this interface 0xff's originating from .debug_macro | 
|  | 516 | unless the TOKEN that we obtained indicates the call originates | 
|  | 517 | from a new-style caller.  See above for details on what | 
|  | 518 | information is encoded into tokens.  */ | 
| Petr Machata | f3df61f | 2009-05-07 21:02:33 +0200 | [diff] [blame] | 519 |  | 
| Petr Machata | edb079a | 2014-12-02 21:22:14 +0100 | [diff] [blame] | 520 | bool accept_0xff; | 
|  | 521 | ptrdiff_t offset = offset_from_token (token, &accept_0xff); | 
|  | 522 |  | 
|  | 523 | /* DW_AT_macro_info */ | 
|  | 524 | if (dwarf_hasattr (cudie, DW_AT_macro_info)) | 
|  | 525 | { | 
|  | 526 | Dwarf_Word macoff; | 
|  | 527 | if (get_offset_from (cudie, DW_AT_macro_info, &macoff) != 0) | 
|  | 528 | return -1; | 
|  | 529 | offset = macro_info_getmacros_off (cudie->cu->dbg, macoff, | 
|  | 530 | callback, arg, offset, cudie); | 
|  | 531 | } | 
|  | 532 | else | 
|  | 533 | { | 
|  | 534 | /* DW_AT_GNU_macros, DW_AT_macros */ | 
|  | 535 | Dwarf_Word macoff; | 
|  | 536 | if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0) | 
|  | 537 | return -1; | 
|  | 538 | offset = gnu_macros_getmacros_off (cudie->cu->dbg, macoff, | 
|  | 539 | callback, arg, offset, accept_0xff, | 
|  | 540 | cudie); | 
|  | 541 | } | 
|  | 542 |  | 
|  | 543 | return token_from_offset (offset, accept_0xff); | 
| Ulrich Drepper | b08d5a8 | 2005-07-26 05:00:05 +0000 | [diff] [blame] | 544 | } |