1 /* 2 3 Copyright (C) 2000, 2002 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., 1600 Amphitheatre Pky, 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 36 37 38 #include "config.h" 39 #include "dwarf_incl.h" 40 #include <stdio.h> 41 #include "dwarf_global.h" 42 43 int 44 dwarf_get_globals(Dwarf_Debug dbg, 45 Dwarf_Global ** globals, 46 Dwarf_Signed * return_count, Dwarf_Error * error) 47 { 48 int res; 49 50 res = 51 _dwarf_load_section(dbg, 52 dbg->de_debug_pubnames_index, 53 &dbg->de_debug_pubnames, 54 error); 55 if (res != DW_DLV_OK) { 56 return res; 57 } 58 59 60 61 return _dwarf_internal_get_pubnames_like_data(dbg, 62 dbg-> 63 de_debug_pubnames, 64 dbg-> 65 de_debug_pubnames_size, 66 globals, return_count, 67 error, 68 DW_DLA_GLOBAL_CONTEXT, 69 DW_DLE_PUBNAMES_LENGTH_BAD, 70 DW_DLE_PUBNAMES_VERSION_ERROR); 71 72 } 73 74 75 /* Sweeps the complete section. 76 */ 77 int 78 _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg, 79 Dwarf_Small * section_data_ptr, 80 Dwarf_Unsigned section_length, 81 Dwarf_Global ** globals, 82 Dwarf_Signed * return_count, 83 Dwarf_Error * error, 84 int allocation_code, 85 int length_err_num, 86 int version_err_num) 87 { 88 89 90 Dwarf_Small *pubnames_like_ptr; 91 92 93 94 /* 95 Points to the context for the current set of global names, and 96 contains information to identify the compilation-unit that the 97 set refers to. */ 98 Dwarf_Global_Context pubnames_context; 99 100 Dwarf_Half version; 101 102 /* 103 Offset from the start of compilation-unit for the current 104 global. */ 105 Dwarf_Off die_offset_in_cu; 106 107 Dwarf_Unsigned global_count = 0; 108 109 /* Points to the current global read. */ 110 Dwarf_Global global; 111 112 /* 113 Used to chain the Dwarf_Global_s structs for creating contiguous 114 list of pointers to the structs. */ 115 Dwarf_Chain curr_chain, prev_chain, head_chain = NULL; 116 117 /* Points to contiguous block of Dwarf_Global's to be returned. */ 118 Dwarf_Global *ret_globals; 119 120 /* Temporary counter. */ 121 Dwarf_Unsigned i; 122 123 124 125 126 if (dbg == NULL) { 127 _dwarf_error(NULL, error, DW_DLE_DBG_NULL); 128 return (DW_DLV_ERROR); 129 } 130 /* We will eventually need the .debug_info data. Load it now. */ 131 if(!dbg->de_debug_info) { 132 int res = _dwarf_load_debug_info(dbg,error); 133 if(res != DW_DLV_OK) { 134 return res; 135 } 136 } 137 138 if (section_data_ptr == NULL) { 139 return (DW_DLV_NO_ENTRY); 140 } 141 142 pubnames_like_ptr = section_data_ptr; 143 do { 144 Dwarf_Unsigned length; 145 int local_extension_size; 146 int local_length_size; 147 148 /* Some compilers emit padding at the end of each cu's 149 area. pubnames_ptr_past_end_cu records the true 150 area end for this cu's data. Essentially the 151 length in the header and the 0 terminator of the 152 data are redundant information. The dwarf2/3 153 spec does not mention what to do if the length 154 is past the 0 terminator. So we take any bytes 155 left after the 0 as padding and ignore them. */ 156 Dwarf_Small *pubnames_ptr_past_end_cu = 0; 157 158 159 pubnames_context = (Dwarf_Global_Context) 160 _dwarf_get_alloc(dbg, allocation_code, 1); 161 if (pubnames_context == NULL) { 162 _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); 163 return (DW_DLV_ERROR); 164 } 165 /* READ_AREA_LENGTH updates pubnames_like_ptr for consumed 166 bytes */ 167 READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, 168 pubnames_like_ptr, local_length_size, 169 local_extension_size); 170 pubnames_context->pu_length_size = local_length_size; 171 pubnames_context->pu_extension_size = local_extension_size; 172 pubnames_context->pu_dbg = dbg; 173 174 pubnames_ptr_past_end_cu = pubnames_like_ptr + length; 175 176 READ_UNALIGNED(dbg, version, Dwarf_Half, 177 pubnames_like_ptr, sizeof(Dwarf_Half)); 178 pubnames_like_ptr += sizeof(Dwarf_Half); 179 if (version != CURRENT_VERSION_STAMP) { 180 _dwarf_error(dbg, error, version_err_num); 181 return (DW_DLV_ERROR); 182 } 183 184 /* offset of CU header in debug section */ 185 READ_UNALIGNED(dbg, pubnames_context->pu_offset_of_cu_header, 186 Dwarf_Off, pubnames_like_ptr, 187 pubnames_context->pu_length_size); 188 pubnames_like_ptr += pubnames_context->pu_length_size; 189 190 191 READ_UNALIGNED(dbg, pubnames_context->pu_info_length, 192 Dwarf_Unsigned, pubnames_like_ptr, 193 pubnames_context->pu_length_size); 194 pubnames_like_ptr += pubnames_context->pu_length_size; 195 196 if (pubnames_like_ptr > (section_data_ptr + section_length)) { 197 _dwarf_error(dbg, error, length_err_num); 198 return (DW_DLV_ERROR); 199 } 200 201 /* read initial offset (of DIE within CU) of a pubname, final 202 entry is not a pair, just a zero offset */ 203 READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off, 204 pubnames_like_ptr, 205 pubnames_context->pu_length_size); 206 pubnames_like_ptr += pubnames_context->pu_length_size; 207 208 /* loop thru pairs. DIE off with CU followed by string */ 209 while (die_offset_in_cu != 0) { 210 211 /* Already read offset, pubnames_like_ptr now points to the 212 string */ 213 global = 214 (Dwarf_Global) _dwarf_get_alloc(dbg, DW_DLA_GLOBAL, 1); 215 if (global == NULL) { 216 _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); 217 return (DW_DLV_ERROR); 218 } 219 global_count++; 220 221 global->gl_context = pubnames_context; 222 223 global->gl_named_die_offset_within_cu = die_offset_in_cu; 224 225 global->gl_name = pubnames_like_ptr; 226 227 pubnames_like_ptr = pubnames_like_ptr + 228 strlen((char *) pubnames_like_ptr) + 1; 229 230 231 /* finish off current entry chain */ 232 curr_chain = 233 (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); 234 if (curr_chain == NULL) { 235 _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); 236 return (DW_DLV_ERROR); 237 } 238 239 /* Put current global on singly_linked list. */ 240 curr_chain->ch_item = (Dwarf_Global) global; 241 242 if (head_chain == NULL) 243 head_chain = prev_chain = curr_chain; 244 else { 245 prev_chain->ch_next = curr_chain; 246 prev_chain = curr_chain; 247 } 248 249 /* read offset for the *next* entry */ 250 READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off, 251 pubnames_like_ptr, 252 pubnames_context->pu_length_size); 253 254 pubnames_like_ptr += pubnames_context->pu_length_size; 255 if (pubnames_like_ptr > (section_data_ptr + section_length)) { 256 _dwarf_error(dbg, error, length_err_num); 257 return (DW_DLV_ERROR); 258 } 259 } 260 /* ASSERT: die_offset_in_cu == 0 */ 261 if(pubnames_like_ptr > pubnames_ptr_past_end_cu) { 262 /* This is some kind of error. This simply cannot happen. 263 The encoding is wrong or the length in the header 264 for this cu's contribution is wrong. */ 265 _dwarf_error(dbg, error, length_err_num); 266 return (DW_DLV_ERROR); 267 268 } 269 /* If there is some kind of padding at the end of 270 the section, as emitted by some compilers, 271 skip over that padding and simply ignore the bytes 272 thus passed-over. With most compilers, 273 pubnames_like_ptr == pubnames_ptr_past_end_cu 274 at this point */ 275 pubnames_like_ptr = pubnames_ptr_past_end_cu; 276 277 } while (pubnames_like_ptr < (section_data_ptr + section_length)); 278 279 /* Points to contiguous block of Dwarf_Global's. */ 280 ret_globals = (Dwarf_Global *) 281 _dwarf_get_alloc(dbg, DW_DLA_LIST, global_count); 282 if (ret_globals == NULL) { 283 _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); 284 return (DW_DLV_ERROR); 285 } 286 287 /* 288 Store pointers to Dwarf_Global_s structs in contiguous block, 289 and deallocate the chain. */ 290 curr_chain = head_chain; 291 for (i = 0; i < global_count; i++) { 292 *(ret_globals + i) = curr_chain->ch_item; 293 prev_chain = curr_chain; 294 curr_chain = curr_chain->ch_next; 295 dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); 296 } 297 298 *globals = ret_globals; 299 *return_count = (global_count); 300 return DW_DLV_OK; 301 } 302 303 /* 304 Given a pubnames entry (or other like section entry) 305 return thru the ret_name pointer 306 a pointer to the string which is the entry name. 307 308 */ 309 int 310 dwarf_globname(Dwarf_Global glob, char **ret_name, Dwarf_Error * error) 311 { 312 if (glob == NULL) { 313 _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); 314 return (DW_DLV_ERROR); 315 } 316 317 *ret_name = (char *) (glob->gl_name); 318 return DW_DLV_OK; 319 } 320 321 322 /* 323 Given a pubnames entry (or other like section entry) 324 return thru the ret_off pointer the 325 global offset of the DIE for this entry. 326 The global offset is the offset within the .debug_info 327 section as a whole. 328 */ 329 int 330 dwarf_global_die_offset(Dwarf_Global global, 331 Dwarf_Off * ret_off, Dwarf_Error * error) 332 { 333 if (global == NULL) { 334 _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); 335 return (DW_DLV_ERROR); 336 } 337 338 if (global->gl_context == NULL) { 339 _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); 340 return (DW_DLV_ERROR); 341 } 342 343 *ret_off = (global->gl_named_die_offset_within_cu + 344 global->gl_context->pu_offset_of_cu_header); 345 return DW_DLV_OK; 346 } 347 348 /* 349 Given a pubnames entry (or other like section entry) 350 return thru the ret_off pointer the 351 offset of the compilation unit header of the 352 compilation unit the global is part of. 353 354 In early versions of this, the value returned was 355 the offset of the compilation unit die, and 356 other cu-local die offsets were faked so adding this to 357 such a cu-local offset got a true section offset. 358 Now things do as they say (adding *cu_header_offset to 359 a cu-local offset gets the section offset). 360 361 */ 362 int 363 dwarf_global_cu_offset(Dwarf_Global global, 364 Dwarf_Off * cu_header_offset, 365 Dwarf_Error * error) 366 { 367 Dwarf_Global_Context con; 368 369 if (global == NULL) { 370 _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); 371 return (DW_DLV_ERROR); 372 } 373 374 con = global->gl_context; 375 376 if (con == NULL) { 377 _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); 378 return (DW_DLV_ERROR); 379 } 380 381 /* In early libdwarf, this incorrectly returned the offset of the 382 CU DIE. Now correctly returns the header offset. */ 383 *cu_header_offset = con->pu_offset_of_cu_header; 384 385 return DW_DLV_OK; 386 } 387 388 /* 389 Give back the pubnames entry (or any other like section) 390 name, symbol DIE offset, and the cu-DIE offset. 391 */ 392 int 393 dwarf_global_name_offsets(Dwarf_Global global, 394 char **ret_name, 395 Dwarf_Off * die_offset, 396 Dwarf_Off * cu_die_offset, 397 Dwarf_Error * error) 398 { 399 Dwarf_Global_Context con; 400 Dwarf_Debug dbg; 401 Dwarf_Off off; 402 403 if (global == NULL) { 404 _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); 405 return (DW_DLV_ERROR); 406 } 407 408 con = global->gl_context; 409 410 if (con == NULL) { 411 _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); 412 return (DW_DLV_ERROR); 413 } 414 415 off = con->pu_offset_of_cu_header; 416 if (die_offset != NULL) { 417 *die_offset = global->gl_named_die_offset_within_cu + off; 418 } 419 420 dbg = con->pu_dbg; 421 if (dbg == NULL) { 422 _dwarf_error(NULL, error, DW_DLE_DBG_NULL); 423 return (DW_DLV_ERROR); 424 } 425 426 if (cu_die_offset != NULL) { 427 int res = _dwarf_load_debug_info(dbg,error); 428 if(res != DW_DLV_OK) { 429 return res; 430 } 431 *cu_die_offset = off + _dwarf_length_of_cu_header(dbg, off); 432 } 433 434 *ret_name = (char *) global->gl_name; 435 436 return DW_DLV_OK; 437 } 438 439 /* 440 We have the offset to a CU header. 441 Return thru outFileOffset the offset of the CU DIE. 442 443 New June, 2001. 444 Used by SGI debuggers. 445 No error is possible. 446 */ 447 448 /* ARGSUSED */ 449 int 450 dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg, 451 Dwarf_Off 452 in_cu_header_offset, 453 Dwarf_Off * 454 out_cu_die_offset, 455 Dwarf_Error * err) 456 { 457 Dwarf_Off len = 458 _dwarf_length_of_cu_header(dbg, in_cu_header_offset); 459 460 Dwarf_Off newoff = in_cu_header_offset + len; 461 462 *out_cu_die_offset = newoff; 463 return DW_DLV_OK; 464 } 465