1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #include <stdio.h> 27 #include "msg.h" 28 #include "_debug.h" 29 #include "libld.h" 30 #include "_string_table.h" 31 32 /* 33 * Format an input section descriptor name for output, in the format 34 * [ndx]name 35 * If possible, a user supplied fixed size buffer is used. Failing that, 36 * dynamic memory is allocated, which must be freed by the caller. 37 * 38 * entry: 39 * [dbg_fmt_isec_name2]: name, scnndx - Name and section index 40 * [dbg_fmt_isec_name]: isp - Input section descriptor giving name 41 * and index. 42 * 43 * buf - Caller supplied buffer 44 * alloc_mem - Address of pointer to be set to address of allocated 45 * memory, or NULL if no memory is allocated. 46 * 47 * exit: 48 * A pointer to the formatted string is returned. If the supplied buffer 49 * was sufficient, *alloc_mem is set to NULL. If memory was allocated, 50 * *alloc_mem references it. The caller must free this memory after use. 51 */ 52 const char * 53 dbg_fmt_isec_name2(const char *name, Word scnndx, dbg_isec_name_buf_t buf, 54 char **alloc_mem) 55 { 56 int cnt; 57 58 /* 59 * If the section index is 0, it's not a real section. 60 * Just use the name as is. 61 */ 62 if (scnndx == 0) { 63 *alloc_mem = NULL; 64 return (name); 65 } 66 67 /* Format into the fixed buffer */ 68 cnt = snprintf(buf, sizeof (dbg_isec_name_buf_t), 69 MSG_ORIG(MSG_FMT_ISEC_NAME), EC_WORD(scnndx), name); 70 71 /* 72 * If the name was too long, try to allocate a dynamic buffer. 73 * Failing that, fall through and use the clipped one already 74 * formatted into buf, as that's better than nothing. 75 */ 76 if ((cnt >= sizeof (dbg_isec_name_buf_t)) && 77 ((*alloc_mem = malloc(cnt + 1)) != NULL)) { 78 (void) snprintf(*alloc_mem, cnt + 1, 79 MSG_ORIG(MSG_FMT_ISEC_NAME), EC_WORD(scnndx), name); 80 return (*alloc_mem); 81 } 82 83 /* Return the caller supplied buffer */ 84 *alloc_mem = NULL; 85 return (buf); 86 } 87 const char * 88 dbg_fmt_isec_name(Is_desc *isp, dbg_isec_name_buf_t buf, char **alloc_mem) 89 { 90 return (dbg_fmt_isec_name2(isp->is_name, isp->is_scnndx, buf, 91 alloc_mem)); 92 } 93 94 void 95 Dbg_sec_strtab(Lm_list *lml, Os_desc *osp, Str_tbl *stp) 96 { 97 uint_t cnt; 98 99 if (DBG_NOTCLASS(DBG_C_STRTAB)) 100 return; 101 102 if (!osp) 103 return; 104 105 Dbg_util_nl(lml, DBG_NL_STD); 106 if (stp->st_flags & FLG_STTAB_COMPRESS) 107 dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_COMP), osp->os_name, 108 EC_XWORD(stp->st_fullstrsize), EC_XWORD(stp->st_strsize)); 109 else 110 dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_STND), osp->os_name, 111 EC_XWORD(stp->st_fullstrsize)); 112 113 if ((DBG_NOTDETAIL()) || 114 ((stp->st_flags & FLG_STTAB_COMPRESS) == 0)) 115 return; 116 117 dbg_print(lml, MSG_ORIG(MSG_STR_EMPTY)); 118 dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_HD), osp->os_name, 119 stp->st_hbckcnt); 120 121 for (cnt = 0; cnt < stp->st_hbckcnt; cnt++) { 122 Str_hash *strhash = stp->st_hashbcks[cnt]; 123 124 if (strhash == NULL) 125 continue; 126 127 dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_BCKT), cnt); 128 129 while (strhash) { 130 size_t stroff = strhash->hi_mstr->sm_strlen - 131 strhash->hi_strlen; 132 133 if (stroff == 0) { 134 dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_MSTR), 135 EC_XWORD(strhash->hi_refcnt), 136 strhash->hi_mstr->sm_str); 137 } else { 138 dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_SUFSTR), 139 EC_XWORD(strhash->hi_refcnt), 140 &strhash->hi_mstr->sm_str[stroff], 141 strhash->hi_mstr->sm_str); 142 } 143 144 strhash = strhash->hi_next; 145 } 146 } 147 } 148 149 void 150 Dbg_sec_genstr_compress(Lm_list *lml, const char *os_name, 151 Xword raw_size, Xword merge_size) 152 { 153 if (DBG_NOTCLASS(DBG_C_SECTIONS)) 154 return; 155 156 dbg_print(lml, MSG_INTL(MSG_SEC_GENSTR_COMP), os_name, 157 EC_XWORD(raw_size), EC_XWORD(merge_size)); 158 } 159 160 void 161 Dbg_sec_unsup_strmerge(Lm_list *lml, Is_desc *isp) 162 { 163 dbg_isec_name_buf_t buf; 164 char *alloc_mem; 165 const char *str; 166 167 if (DBG_NOTCLASS(DBG_C_SECTIONS)) 168 return; 169 170 /* 171 * We can only merge string table sections with single byte 172 * (char) characters. For any other (wide) character types, 173 * issue a message so the user will understand why these 174 * sections are not being picked up. 175 */ 176 if ((isp->is_shdr->sh_entsize > 1) || 177 (isp->is_shdr->sh_addralign > 1)) { 178 str = (isp->is_file != NULL) ? isp->is_file->ifl_name : 179 MSG_INTL(MSG_STR_NULL); 180 dbg_print(lml, MSG_INTL(MSG_SEC_STRMERGE_UNSUP), 181 dbg_fmt_isec_name(isp, buf, &alloc_mem), str, 182 EC_XWORD(isp->is_shdr->sh_addralign), 183 EC_XWORD(isp->is_shdr->sh_entsize)); 184 if (alloc_mem != NULL) 185 free(alloc_mem); 186 } 187 } 188 189 void 190 Dbg_sec_backing(Lm_list *lml) 191 { 192 if (DBG_NOTCLASS(DBG_C_SECTIONS)) 193 return; 194 195 Dbg_util_nl(lml, DBG_NL_STD); 196 dbg_print(lml, MSG_INTL(MSG_SEC_BACKING)); 197 } 198 199 void 200 Dbg_sec_in(Lm_list *lml, Is_desc *isp) 201 { 202 if (DBG_NOTCLASS(DBG_C_SECTIONS)) 203 return; 204 205 if (isp->is_flags & FLG_IS_GNSTRMRG) { 206 /* 207 * This section was generated because we have 1 or 208 * more SHF_MERGE|SHF_STRINGS input sections that we 209 * wish to merge. This new section will ultimately 210 * end up replacing those sections once it has been filled 211 * with their strings (merged and compressed) and relocations 212 * have been redirected. 213 */ 214 dbg_print(lml, MSG_INTL(MSG_SEC_INPUT_GENSTR), isp->is_name); 215 } else if (isp->is_file == NULL) { 216 /* Generated input section */ 217 dbg_print(lml, MSG_INTL(MSG_SEC_INPUT_GEN), isp->is_name); 218 } else { 219 /* Standard input section */ 220 dbg_isec_name_buf_t buf; 221 char *alloc_mem; 222 223 dbg_print(lml, MSG_INTL(MSG_SEC_INPUT), 224 dbg_fmt_isec_name(isp, buf, &alloc_mem), 225 isp->is_file->ifl_name); 226 if (alloc_mem != NULL) 227 free(alloc_mem); 228 } 229 } 230 231 void 232 Dbg_sec_added(Lm_list *lml, Os_desc *osp, Sg_desc *sgp) 233 { 234 const char *str; 235 236 if (DBG_NOTCLASS(DBG_C_SECTIONS)) 237 return; 238 239 if (sgp->sg_name && *sgp->sg_name) 240 str = sgp->sg_name; 241 else 242 str = MSG_INTL(MSG_STR_NULL); 243 244 dbg_print(lml, MSG_INTL(MSG_SEC_ADDED), osp->os_name, str); 245 } 246 247 void 248 Dbg_sec_created(Lm_list *lml, Os_desc *osp, Sg_desc *sgp) 249 { 250 const char *str; 251 252 if (DBG_NOTCLASS(DBG_C_SECTIONS)) 253 return; 254 255 if (sgp->sg_name && *sgp->sg_name) 256 str = sgp->sg_name; 257 else 258 str = MSG_INTL(MSG_STR_NULL); 259 260 dbg_print(lml, MSG_INTL(MSG_SEC_CREATED), osp->os_name, str); 261 } 262 263 void 264 Dbg_sec_discarded(Lm_list *lml, Is_desc *isp, Is_desc *disp) 265 { 266 if (DBG_NOTCLASS(DBG_C_SECTIONS | DBG_C_UNUSED)) 267 return; 268 269 if ((isp->is_flags & FLG_IS_INSTRMRG) && 270 (disp->is_flags & FLG_IS_GNSTRMRG)) { 271 /* 272 * This SHF_MERGE|SHF_STRINGS input section is being 273 * discarded in favor of the generated merged string section. 274 */ 275 dbg_isec_name_buf_t buf; 276 char *alloc_mem; 277 278 dbg_print(lml, MSG_INTL(MSG_SEC_STRMERGE_DISCARDED), 279 dbg_fmt_isec_name(isp, buf, &alloc_mem), 280 isp->is_file->ifl_name); 281 if (alloc_mem != NULL) 282 free(alloc_mem); 283 } else { 284 /* Generic section discard */ 285 dbg_isec_name_buf_t buf1, buf2; 286 char *alloc_mem1, *alloc_mem2; 287 288 dbg_print(lml, MSG_INTL(MSG_SEC_DISCARDED), 289 dbg_fmt_isec_name(isp, buf1, &alloc_mem1), 290 isp->is_file->ifl_name, 291 dbg_fmt_isec_name(disp, buf2, &alloc_mem2), 292 disp->is_file->ifl_name); 293 if (alloc_mem1 != NULL) 294 free(alloc_mem1); 295 if (alloc_mem2 != NULL) 296 free(alloc_mem2); 297 } 298 } 299 300 void 301 Dbg_sec_group(Lm_list *lml, Is_desc *isp, Group_desc *gdp) 302 { 303 dbg_isec_name_buf_t buf; 304 char *alloc_mem; 305 const char *comdat, *isp_str; 306 307 if (DBG_NOTCLASS(DBG_C_SECTIONS)) 308 return; 309 310 if (gdp->gd_data[0] & GRP_COMDAT) 311 comdat = MSG_ORIG(MSG_STR_COMDAT); 312 else 313 comdat = MSG_ORIG(MSG_STR_EMPTY); 314 315 isp_str = dbg_fmt_isec_name(isp, buf, &alloc_mem); 316 317 if (isp->is_shdr->sh_type == SHT_GROUP) { 318 dbg_print(lml, MSG_INTL(MSG_SEC_GRP_DEFINE), isp_str, 319 isp->is_file->ifl_name, comdat, gdp->gd_name); 320 } else { 321 dbg_print(lml, MSG_INTL(MSG_SEC_GRP_MEMBER), isp_str, 322 isp->is_file->ifl_name, comdat, gdp->gd_name); 323 } 324 325 if (gdp->gd_oisc) { 326 dbg_print(lml, MSG_INTL(MSG_SEC_GRP_DISCARDED), isp_str, 327 isp->is_file->ifl_name, gdp->gd_name, 328 gdp->gd_oisc->is_file->ifl_name); 329 } 330 331 if (alloc_mem != NULL) 332 free(alloc_mem); 333 } 334 335 void 336 Dbg_sec_order_list(Ofl_desc *ofl, int flag) 337 { 338 Os_desc *osp; 339 Is_desc *isp1; 340 Aliste idx1; 341 Lm_list *lml = ofl->ofl_lml; 342 const char *str; 343 344 if (DBG_NOTCLASS(DBG_C_SECTIONS)) 345 return; 346 if (DBG_NOTDETAIL()) 347 return; 348 349 Dbg_util_nl(lml, DBG_NL_STD); 350 351 /* 352 * If the flag == 0, then the routine is called before sorting. 353 */ 354 if (flag == 0) 355 str = MSG_INTL(MSG_ORD_SORT_BEFORE); 356 else 357 str = MSG_INTL(MSG_ORD_SORT_AFTER); 358 359 for (APLIST_TRAVERSE(ofl->ofl_ordered, idx1, osp)) { 360 Aliste idx2; 361 Sort_desc *sort = osp->os_sort; 362 363 Dbg_util_nl(lml, DBG_NL_STD); 364 dbg_print(lml, str, osp->os_name); 365 dbg_print(lml, MSG_INTL(MSG_ORD_HDR_1), 366 EC_WORD(sort->st_beforecnt), EC_WORD(sort->st_aftercnt), 367 EC_WORD(sort->st_ordercnt)); 368 369 for (APLIST_TRAVERSE(osp->os_isdescs, idx2, isp1)) { 370 dbg_isec_name_buf_t buf; 371 char *alloc_mem; 372 const char *isp1_str; 373 Word link; 374 Ifl_desc *ifl = isp1->is_file; 375 Is_desc *isp2; 376 const char *msg; 377 378 /* 379 * An output section with sorted input sections 380 * can also have a large number of unsorted sections. 381 * Skip these without comment. 382 */ 383 if ((isp1->is_flags & FLG_IS_ORDERED) == 0) { 384 continue; 385 } 386 387 if (isp1->is_shdr->sh_flags & SHF_ORDERED) { 388 link = isp1->is_shdr->sh_info; 389 msg = MSG_ORIG(MSG_SH_INFO); 390 } else { /* SHF_LINK_ORDER */ 391 link = isp1->is_shdr->sh_link; 392 msg = MSG_ORIG(MSG_SH_LINK); 393 } 394 395 isp1_str = dbg_fmt_isec_name(isp1, buf, &alloc_mem); 396 397 if (link == SHN_BEFORE) { 398 dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_1), msg, 399 isp1_str, isp1->is_file->ifl_name); 400 } else if (link == SHN_AFTER) { 401 dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_2), msg, 402 isp1_str, isp1->is_file->ifl_name); 403 } else { 404 isp2 = ifl->ifl_isdesc[link]; 405 dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_3), 406 EC_WORD(isp2->is_keyident), isp1_str, 407 ifl->ifl_name, msg, isp2->is_name); 408 } 409 if (alloc_mem != NULL) 410 free(alloc_mem); 411 } 412 } 413 Dbg_util_nl(lml, DBG_NL_STD); 414 } 415 416 /* 417 * Error message string table. 418 */ 419 static const Msg order_errors[] = { 420 MSG_ORD_ERR_INFORANGE, /* MSG_INTL(MSG_ORD_ERR_INFORANGE) */ 421 MSG_ORD_ERR_ORDER, /* MSG_INTL(MSG_ORD_ERR_ORDER) */ 422 MSG_ORD_ERR_LINKRANGE, /* MSG_INTL(MSG_ORD_ERR_LINKRANGE) */ 423 MSG_ORD_ERR_FLAGS, /* MSG_INTL(MSG_ORD_ERR_FLAGS) */ 424 MSG_ORD_ERR_CYCLIC, /* MSG_INTL(MSG_ORD_ERR_CYCLIC) */ 425 MSG_ORD_ERR_LINKINV /* MSG_INTL(MSG_ORD_ERR_LINKINV) */ 426 }; 427 428 void 429 Dbg_sec_order_error(Lm_list *lml, Ifl_desc *ifl, Word ndx, int error) 430 { 431 dbg_isec_name_buf_t buf; 432 char *alloc_mem; 433 434 if (DBG_NOTCLASS(DBG_C_SECTIONS)) 435 return; 436 if (DBG_NOTDETAIL()) 437 return; 438 439 if (error == 0) 440 return; 441 442 dbg_print(lml, MSG_INTL(MSG_ORD_ERR_TITLE), 443 dbg_fmt_isec_name(ifl->ifl_isdesc[ndx], buf, &alloc_mem), 444 ifl->ifl_name); 445 if (alloc_mem != NULL) 446 free(alloc_mem); 447 448 if (error) 449 dbg_print(lml, MSG_INTL(order_errors[error - 1])); 450 } 451 452 void 453 Dbg_sec_redirected(Lm_list *lml, Is_desc *isp, const char *nname) 454 { 455 dbg_isec_name_buf_t buf; 456 char *alloc_mem; 457 458 if (DBG_NOTCLASS(DBG_C_SECTIONS)) 459 return; 460 461 dbg_print(lml, MSG_INTL(MSG_SEC_REDIRECTED), 462 dbg_fmt_isec_name(isp, buf, &alloc_mem), nname); 463 if (alloc_mem != NULL) 464 free(alloc_mem); 465 } 466 467 void 468 Dbg_sec_gnu_comdat(Lm_list *lml, Is_desc *isp, uint_t comdat, uint_t relax) 469 { 470 dbg_isec_name_buf_t buf; 471 char *alloc_mem; 472 const char *fmt; 473 474 if (DBG_NOTCLASS(DBG_C_SECTIONS)) 475 return; 476 477 if (comdat && relax) 478 fmt = MSG_INTL(MSG_SEC_GNU_COMDAT_1); 479 else if (comdat) 480 fmt = MSG_INTL(MSG_SEC_GNU_COMDAT_2); 481 else 482 fmt = MSG_INTL(MSG_SEC_GNU_COMDAT_3); 483 484 dbg_print(lml, fmt, dbg_fmt_isec_name(isp, buf, &alloc_mem)); 485 if (alloc_mem != NULL) 486 free(alloc_mem); 487 } 488