Print this page
4000 pvs can't deal with extended sections
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/sgs/pvs/common/pvs.c
+++ new/usr/src/cmd/sgs/pvs/common/pvs.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * Analyze the versioning information within a file.
29 29 *
30 30 * -C demangle C++ symbol names.
31 31 *
32 32 * -d dump version definitions.
33 33 *
34 34 * -l print reduced (local) symbols. Implies -s.
35 35 *
36 36 * -n normalize any version definitions.
37 37 *
38 38 * -o dump output in one-line fashion (more suitable for grep'ing
39 39 * and diff'ing).
40 40 *
41 41 * -r dump the version requirements on library dependencies
42 42 *
43 43 * -s display the symbols associated with each version definition.
44 44 *
45 45 * -v verbose output. With the -r and -d options any WEAK attribute
46 46 * is displayed. With the -d option, any version inheritance,
47 47 * and the base version are displayed. With the -r option,
48 48 * WEAK and INFO attributes are displayed. With the -s option
49 49 * the version symbol is displayed.
50 50 *
51 51 * -I index only print the specifed version index, or index range.
52 52 *
53 53 * -N name only print the specifed `name'.
54 54 */
55 55 #include <fcntl.h>
56 56 #include <stdio.h>
57 57 #include <libelf.h>
58 58 #include <link.h>
59 59 #include <stdlib.h>
60 60 #include <string.h>
61 61 #include <unistd.h>
62 62 #include <locale.h>
63 63 #include <errno.h>
64 64 #include <sgs.h>
65 65 #include <conv.h>
66 66 #include <gelf.h>
67 67 #include <debug.h>
68 68 #include <ctype.h>
69 69 #include <alist.h>
70 70 #include "msg.h"
71 71
72 72 /*
73 73 * Define Alist initialization sizes.
74 74 */
75 75 #define AL_CNT_MATCH_LIST 5 /* match_list initial alist count */
76 76 #define AL_CNT_GVER_DESC 25 /* version tracking descriptors */
77 77
78 78 typedef struct cache {
79 79 Elf_Scn *c_scn;
80 80 Elf_Data *c_data;
81 81 char *c_name;
82 82 } Cache;
83 83
84 84 typedef struct gver_desc {
85 85 const char *vd_name;
86 86 unsigned long vd_hash;
87 87 GElf_Half vd_ndx;
88 88 GElf_Half vd_flags;
89 89 APlist *vd_deps;
90 90 } GVer_desc;
91 91
92 92 /* Versym related data used by gvers_syms() */
93 93 typedef struct {
94 94 GElf_Versym *vsd_vsp; /* ptr to versym data */
95 95 Elf_Data *vsd_sym_data; /* ptr to symtab data */
96 96 Word vsd_symn; /* # of symbols in symtab */
97 97 const char *vsd_strs; /* string table data */
98 98 } Gver_sym_data;
99 99
100 100 /*
101 101 * Type used to manage -I and -N options:
102 102 *
103 103 * The -I option specifies a VERSYM index, or index range. The
104 104 * result is to select the VERDEF or VERNEED records with
105 105 * indexes that match those given.
106 106 *
107 107 * -N options come in two forms:
108 108 *
109 109 * 1) name
110 110 * 2) needobj (version)
111 111 *
112 112 * The meaning of the first case depends on the type of
113 113 * version record being matched:
114 114 *
115 115 * VERDEF - name is the name of a version defined
116 116 * by the object being processed (i.e. SUNW_1.1).
117 117 *
118 118 * VERNEED - name is the name of the object file
119 119 * on which the dependency exists (i.e. libc.so.1).
120 120 *
121 121 * -N options of the second form only apply to VERNEED records.
122 122 * They are used to specify a version from a needed object.
123 123 */
124 124 /* match_opt_t is used to note which match option was used */
125 125 typedef enum {
126 126 MATCH_OPT_NAME, /* Record contains a name */
127 127 MATCH_OPT_NEED_VER, /* Record contains needed object and version */
128 128 MATCH_OPT_NDX, /* Record contains a single index */
129 129 MATCH_OPT_RANGE, /* Record contains an index range */
130 130 } match_opt_t;
131 131
132 132 typedef struct {
133 133 match_opt_t opt_type;
134 134 union {
135 135 struct {
136 136 const char *version; /* MATCH_OPT_{NAME|NEED_VER} */
137 137 const char *needobj; /* MATCH_OPT_NEED_VER only */
138 138 } name;
139 139 struct {
140 140 int start; /* MATCH_OPT_{NDX|RANGE} */
141 141 int end; /* MATCH_OPT_RANGE only) */
142 142 } ndx;
143 143 } value;
144 144 } match_rec_t;
145 145
146 146
147 147
148 148 static const char *cname;
149 149 static int Cflag, dflag, lflag, nflag, oflag, rflag, sflag, vflag;
150 150 static Alist *match_list;
151 151
152 152 /* Used to track whether an option defaulted to on, or was explicitly set */
153 153 #define DEF_DEFINED 1
154 154 #define USR_DEFINED 2
155 155
156 156 /*
157 157 * Determine whether a symbol name should be demangled.
158 158 */
159 159 static const char *
160 160 demangle(const char *name)
161 161 {
162 162 if (Cflag)
163 163 return (Elf_demangle_name(name));
164 164 else
165 165 return (name);
166 166 }
167 167
168 168 /*
169 169 * Append an item to the specified list, and return a pointer to the list
170 170 * node created.
171 171 *
172 172 * exit:
173 173 * On success, a new list node is created and the item is
174 174 * added to the list. On failure, a fatal error is issued
175 175 * and the process exits.
176 176 */
177 177 static void
178 178 pvs_aplist_append(APlist **lst, const void *item, const char *file)
179 179 {
180 180 if (aplist_append(lst, item, AL_CNT_GVER_DESC) == NULL) {
181 181 int err = errno;
182 182 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, file,
183 183 strerror(err));
184 184 exit(1);
185 185 }
186 186 }
187 187
188 188 /*
189 189 * Add an entry to match_list for use by match(). This routine is for
190 190 * use during getopt() processing.
191 191 *
192 192 * entry:
193 193 * opt - One of 'N' or 'I', indicating the option
194 194 * str - Value string corresponding to opt
195 195 *
196 196 * exit:
197 197 * The new match record has been added. On error, a fatal
198 198 * error is issued and and the process exits.
199 199 */
200 200 static void
201 201 add_match_record(int opt, const char *str)
202 202 {
203 203 /*
204 204 * Macros for removing leading and trailing whitespace:
205 205 * WS_SKIP - Advance _str without passing the NULL termination,
206 206 * until the first character is not whitespace.
207 207 * WS_SKIP_LIMIT - Advance _str without passing _limit,
208 208 * until the first character is not whitespace.
209 209 * WS_RSKIP_LIMIT - Move _tail back without passing _str,
210 210 * until the character before it is not whitespace.
211 211 * Write a NULL termination at that point.
212 212 */
213 213 #define WS_SKIP(_str) for (; *(_str) && isspace(*(_str)); (_str)++)
214 214 #define WS_SKIP_LIMIT(_str, _limit) \
215 215 while (((_str) < s2) && isspace(*(_str))) \
216 216 (_str)++
217 217 #define WS_RSKIP_LIMIT(_str, _tail) \
218 218 while (((_tail) > (_str)) && isspace(*((_tail) - 1))) \
219 219 (_tail)--; \
220 220 *(_tail) = '\0'
221 221
222 222
223 223 match_rec_t *rec;
224 224 char *lstr, *s1, *s2;
225 225
226 226 rec = alist_append(&match_list, NULL, sizeof (match_rec_t),
227 227 AL_CNT_MATCH_LIST);
228 228 if (rec == NULL) {
229 229 int err = errno;
230 230 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname,
231 231 MSG_INTL(MSG_STR_MATCH_RECORD), strerror(err));
232 232 exit(1);
233 233 }
234 234
235 235 if (opt == 'N') {
236 236 if ((lstr = strdup(str)) == NULL) {
237 237 int err = errno;
238 238 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
239 239 cname, MSG_INTL(MSG_STR_MATCH_RECORD),
240 240 strerror(err));
241 241 exit(1);
242 242 }
243 243
244 244 /* Strip leading/trailing whitespace */
245 245 s2 = lstr + strlen(lstr);
246 246 WS_SKIP_LIMIT(lstr, s2);
247 247 WS_RSKIP_LIMIT(lstr, s2);
248 248
249 249 /* Assume this is a plain string */
250 250 rec->opt_type = MATCH_OPT_NAME;
251 251 rec->value.name.version = lstr;
252 252
253 253 /*
254 254 * If s2 points at a closing paren, then this might
255 255 * be a MATCH_OPT_NEED_VER case. Otherwise we're done.
256 256 */
257 257 if ((s2 == lstr) || (*(s2 - 1) != ')'))
258 258 return;
259 259
260 260 /* We have a closing paren. Locate the opening one. */
261 261 for (s1 = lstr; *s1 && (*s1 != '('); s1++)
262 262 ;
263 263 if (*s1 != '(')
264 264 return;
265 265
266 266 rec->opt_type = MATCH_OPT_NEED_VER;
267 267 rec->value.name.needobj = lstr;
268 268 rec->value.name.version = s1 + 1;
269 269 s2--; /* Points at closing paren */
270 270
271 271 /* Remove whitespace from head/tail of version */
272 272 WS_SKIP_LIMIT(rec->value.name.version, s2);
273 273 WS_RSKIP_LIMIT(rec->value.name.version, s2);
274 274
275 275 /* Terminate needobj, skipping trailing whitespace */
276 276 WS_RSKIP_LIMIT(rec->value.name.needobj, s1);
277 277
278 278 return;
279 279 }
280 280
281 281
282 282 /* If we get here, we are looking at a -I index option */
283 283 rec->value.ndx.start = strtol(str, &s2, 10);
284 284 /* Value must use some of the input, and be positive */
285 285 if ((str == s2) || (rec->value.ndx.start < 1))
286 286 goto syntax_error;
287 287 str = s2;
288 288
289 289 WS_SKIP(str);
290 290 if (*str != ':') {
291 291 rec->opt_type = MATCH_OPT_NDX;
292 292 } else {
293 293 str++; /* Skip the ':' */
294 294 rec->opt_type = MATCH_OPT_RANGE;
295 295 WS_SKIP(str);
296 296 if (*str == '\0') {
297 297 rec->value.ndx.end = -1; /* Indicates "to end" */
298 298 } else {
299 299 rec->value.ndx.end = strtol(str, &s2, 10);
300 300 if ((str == s2) || (rec->value.ndx.end < 0))
301 301 goto syntax_error;
302 302 str = s2;
303 303 WS_SKIP(str);
304 304 }
305 305 }
306 306
307 307 /* If we are successful, there is nothing left to parse */
308 308 if (*str == '\0')
309 309 return;
310 310
311 311 /*
312 312 * If we get here, there is leftover input. Fall through
313 313 * to issue a syntax error.
314 314 */
315 315 syntax_error:
316 316 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), cname);
317 317 exit(1);
318 318
319 319 #undef WS_SKIP
320 320 #undef WS_SKIP_LIMIT
321 321 #undef WS_RSKIP_LIMIT
322 322 }
323 323
324 324 /*
325 325 * Returns True (1) if the version with the given name or index should
326 326 * be displayed, and False (0) if it should not be.
327 327 *
328 328 * entry:
329 329 * needobj - NULL for VERDEF records, the name of the
330 330 * needed object for VERNEED.
331 331 * version - NULL, or needed version
332 332 * ndx - Versym index of version under consideration, or a value less
333 333 * than 1 to indicate that no valid index is given.
334 334 *
335 335 * exit:
336 336 * True will be returned if the given name/index matches those given
337 337 * by one of the -I or -N command line options, or if no such option
338 338 * was used in the command invocation.
339 339 */
340 340 int
341 341 match(const char *needobj, const char *version, int ndx)
342 342 {
343 343 Aliste _idx;
344 344 match_rec_t *rec;
345 345 const char *str;
346 346
347 347 /* If there is no match list, then we approve everything */
348 348 if (alist_nitems(match_list) == 0)
349 349 return (1);
350 350
351 351 /* Run through the match records and check for a hit */
352 352 for (ALIST_TRAVERSE(match_list, _idx, rec)) {
353 353 switch (rec->opt_type) {
354 354 case MATCH_OPT_NAME:
355 355 if (needobj)
356 356 str = needobj;
357 357 else if (version)
358 358 str = version;
359 359 else
360 360 break;
361 361 if (strcmp(rec->value.name.version, str) == 0)
362 362 return (1);
363 363 break;
364 364 case MATCH_OPT_NEED_VER:
365 365 if (needobj && version &&
366 366 (strcmp(rec->value.name.needobj, needobj) == 0) &&
367 367 (strcmp(rec->value.name.version, version) == 0))
368 368 return (1);
369 369 break;
370 370 case MATCH_OPT_NDX:
371 371 if ((ndx > 0) && (ndx == rec->value.ndx.start))
372 372 return (1);
373 373 break;
374 374 case MATCH_OPT_RANGE:
375 375 /*
376 376 * A range end value less than 0 means that any value
377 377 * above the start is acceptible.
378 378 */
379 379 if ((ndx > 0) &&
380 380 (ndx >= rec->value.ndx.start) &&
381 381 ((rec->value.ndx.end < 0) ||
382 382 (ndx <= rec->value.ndx.end)))
383 383 return (1);
384 384 break;
385 385 }
386 386 }
387 387
388 388 /* Nothing matched */
389 389 return (0);
390 390 }
391 391
392 392 /*
393 393 * List the symbols that belong to a specified version
394 394 *
395 395 * entry:
396 396 * vsdata - VERSYM related data from the object
397 397 * vd_ndx - The VERSYM index for symbols to display
398 398 * vd_name - Version name
399 399 * needobj - NULL for symbols corresponding to a VERDEF
400 400 * record. Name of the needed object in the case
401 401 * of a VERNEED record.
402 402 * file - Object file
403 403 */
404 404 static void
405 405 gvers_syms(const Gver_sym_data *vsdata, GElf_Half vd_ndx,
406 406 const char *vd_name, const char *needobj, const char *file)
407 407 {
408 408 GElf_Sym sym;
409 409 int _symn;
410 410
411 411 for (_symn = 0; _symn < vsdata->vsd_symn; _symn++) {
412 412 size_t size = 0;
413 413 const char *name;
414 414
415 415 if (vsdata->vsd_vsp[_symn] != vd_ndx)
416 416 continue;
417 417
418 418 (void) gelf_getsym(vsdata->vsd_sym_data, _symn, &sym);
419 419 name = demangle(vsdata->vsd_strs + sym.st_name);
420 420
421 421 /*
422 422 * Symbols that reference a VERDEF record
423 423 * have some extra details to handle.
424 424 */
425 425 if (needobj == NULL) {
426 426 /*
427 427 * For data symbols defined by this object,
428 428 * determine the size.
429 429 */
430 430 if ((GELF_ST_TYPE(sym.st_info) == STT_OBJECT) ||
431 431 (GELF_ST_TYPE(sym.st_info) == STT_COMMON) ||
432 432 (GELF_ST_TYPE(sym.st_info) == STT_TLS))
433 433 size = (size_t)sym.st_size;
434 434
435 435 /*
436 436 * Only output the version symbol when the verbose
437 437 * flag is used.
438 438 */
439 439 if (!vflag && (sym.st_shndx == SHN_ABS) &&
440 440 (strcmp(name, vd_name) == 0))
441 441 continue;
442 442 }
443 443
444 444 if (oflag) {
445 445 if (needobj == NULL)
446 446 (void) printf(MSG_ORIG(MSG_FMT_SYM_OFIL),
447 447 file, vd_name);
448 448 else
449 449 (void) printf(MSG_ORIG(MSG_FMT_SYM_NEED_OFIL),
450 450 file, needobj, vd_name);
451 451
452 452 if (size)
453 453 (void) printf(MSG_ORIG(MSG_FMT_SYM_SZ_OFLG),
454 454 name, (ulong_t)size);
455 455 else
456 456 (void) printf(MSG_ORIG(MSG_FMT_SYM_OFLG), name);
457 457 } else {
458 458 if (size)
459 459 (void) printf(MSG_ORIG(MSG_FMT_SYM_SZ), name,
460 460 (ulong_t)size);
461 461 else
462 462 (void) printf(MSG_ORIG(MSG_FMT_SYM), name);
463 463 }
464 464 }
465 465 }
466 466
467 467 /*
468 468 * Print any reduced symbols. The convention is that reduced symbols exist as
469 469 * LOCL entries in the .symtab, between the FILE symbol for the output file and
470 470 * the first FILE symbol for any input file used to build the output file.
471 471 */
472 472 static void
473 473 sym_local(Cache *cache, Cache *csym, const char *file)
474 474 {
475 475 int symn, _symn, found = 0;
476 476 GElf_Shdr shdr;
477 477 GElf_Sym sym;
478 478 char *strs;
479 479
480 480 (void) gelf_getshdr(csym->c_scn, &shdr);
481 481 strs = (char *)cache[shdr.sh_link].c_data->d_buf;
482 482 /* LINTED */
483 483 symn = shdr.sh_info;
484 484
485 485 /*
486 486 * Verify symtab[1] is the output file symbol.
487 487 */
488 488 (void) gelf_getsym(csym->c_data, 1, &sym);
489 489 if (GELF_ST_TYPE(sym.st_info) != STT_FILE) {
490 490 (void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS), cname,
491 491 file);
492 492 (void) fprintf(stderr, MSG_INTL(MSG_VER_NOTSTTFILE),
493 493 csym->c_name);
494 494 return;
495 495 }
496 496
497 497 /*
498 498 * Scan the remaining symbols until the next file symbol is found.
499 499 */
500 500 for (_symn = 2; _symn < symn; _symn++) {
501 501 const char *name;
502 502
503 503 (void) gelf_getsym(csym->c_data, _symn, &sym);
504 504 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION)
505 505 continue;
506 506 if (GELF_ST_TYPE(sym.st_info) == STT_FILE)
507 507 break;
508 508
509 509 /*
510 510 * Its possible that section symbols are followed immediately
511 511 * by globals. This is the case if an object (filter) is
512 512 * generated exclusively from mapfile symbol definitions.
513 513 */
514 514 if (GELF_ST_BIND(sym.st_info) != STB_LOCAL)
515 515 break;
516 516
517 517 name = demangle(strs + sym.st_name);
518 518
519 519 if (oflag) {
520 520 (void) printf(MSG_ORIG(MSG_FMT_LOCSYM_OFLG),
521 521 file, name);
522 522 } else {
523 523 if (found == 0) {
524 524 found = 1;
525 525 (void) printf(MSG_ORIG(MSG_FMT_LOCSYM_HDR));
526 526 }
527 527 (void) printf(MSG_ORIG(MSG_FMT_LOCSYM), name);
528 528 }
529 529 }
530 530 }
531 531
532 532 /*
533 533 * Print data from the files VERNEED section.
534 534 *
535 535 * If we have been asked to display symbols, then the
536 536 * output format follows that used for verdef sections,
537 537 * with each version displayed separately. For instance:
538 538 *
539 539 * libc.so.1 (SUNW_1.7):
540 540 * sym1;
541 541 * sym2;
542 542 * libc.so.1 (SUNW_1.9):
543 543 * sym3;
544 544 *
545 545 * If we are not displaying symbols, then a terse format
546 546 * is used, which combines all the needed versions from
547 547 * a given object into a single line. In this case, the
548 548 * versions are shown whether or not they contribute symbols.
549 549 *
550 550 * libc.so.1 (SUNW_1.7, SUNW_1.9);
551 551 */
552 552 static int
553 553 gvers_need(Cache *cache, Cache *need, const Gver_sym_data *vsdata,
554 554 const char *file)
555 555 {
556 556 unsigned int num, _num;
557 557 char *strs;
558 558 GElf_Verneed *vnd = need->c_data->d_buf;
559 559 GElf_Shdr shdr;
560 560 int error = 0;
561 561 int show = vflag || (vsdata == NULL) || !oflag;
562 562
563 563
564 564 (void) gelf_getshdr(need->c_scn, &shdr);
565 565
566 566 /*
567 567 * Verify the version revision. We only check the first version
568 568 * structure as it is assumed all other version structures in this
569 569 * data section will be of the same revision.
570 570 */
571 571 if (vnd->vn_version > VER_DEF_CURRENT)
572 572 (void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file,
573 573 vnd->vn_version, VER_DEF_CURRENT);
574 574
575 575 /*
576 576 * Get the data buffer for the associated string table.
577 577 */
578 578 strs = (char *)cache[shdr.sh_link].c_data->d_buf;
579 579 num = shdr.sh_info;
580 580
581 581 for (_num = 1; _num <= num; _num++,
582 582 vnd = (GElf_Verneed *)((uintptr_t)vnd + vnd->vn_next)) {
583 583 GElf_Vernaux *vnap;
584 584 Word ndx;
585 585 const char *needobj, *dep;
586 586 int started = 0, listcnt = 0;
587 587
588 588 vnap = (GElf_Vernaux *) ((uintptr_t)vnd + vnd->vn_aux);
589 589
590 590 /* Obtain the needed object file name */
591 591 needobj = (char *)(strs + vnd->vn_file);
592 592
593 593 error = 1;
594 594
595 595 /* Process the versions needed from this object */
596 596 for (ndx = 0; ndx < vnd->vn_cnt; ndx++,
597 597 vnap = (GElf_Vernaux *)((uintptr_t)vnap + vnap->vna_next)) {
598 598 Conv_ver_flags_buf_t ver_flags_buf;
599 599
600 600 dep = (char *)(strs + vnap->vna_name);
601 601
602 602 if (!match(needobj, dep, vnap->vna_other))
603 603 continue;
604 604
605 605 if (show) {
606 606 if ((started == 0) || (vsdata != NULL)) {
607 607 /*
608 608 * If one-line ouput is called for
609 609 * display the filename being processed.
610 610 */
611 611 if (oflag && show)
612 612 (void) printf(
613 613 MSG_ORIG(MSG_FMT_OFIL),
614 614 file);
615 615
616 616 (void) printf(
617 617 MSG_ORIG(MSG_FMT_LIST_BEGIN),
618 618 needobj);
619 619 started = 1;
620 620 }
621 621
622 622 /*
623 623 * If not showing symbols, only show INFO
624 624 * versions in verbose mode. They don't
625 625 * actually contribute to the version
626 626 * interface as seen by rtld, so listing them
627 627 * without qualification can be misleading.
628 628 */
629 629 if (vflag || (vsdata != NULL) ||
630 630 (alist_nitems(match_list) != 0) ||
631 631 !(vnap->vna_flags & VER_FLG_INFO)) {
632 632 const char *fmt = (listcnt == 0) ?
633 633 MSG_ORIG(MSG_FMT_LIST_FIRST) :
634 634 MSG_ORIG(MSG_FMT_LIST_NEXT);
635 635
636 636 if (vsdata == NULL)
637 637 listcnt++;
638 638 (void) printf(fmt, dep);
639 639
640 640 /* Show non-zero flags */
641 641 if (vflag && (vnap->vna_flags != 0))
642 642 (void) printf(
643 643 MSG_ORIG(MSG_FMT_VER_FLG),
644 644 conv_ver_flags(
645 645 vnap->vna_flags,
646 646 CONV_FMT_NOBKT,
647 647 &ver_flags_buf));
648 648 }
649 649 if (vsdata != NULL)
650 650 (void) printf(oflag ?
651 651 MSG_ORIG(MSG_FMT_LIST_END_SEM) :
652 652 MSG_ORIG(MSG_FMT_LIST_END_COL));
653 653 }
654 654
655 655 /*
656 656 * If we are showing symbols, and vna_other is
657 657 * non-zero, list them here.
658 658 *
659 659 * A value of 0 means that this object uses
660 660 * traditional Solaris versioning rules, under
661 661 * which VERSYM does not contain indexes to VERNEED
662 662 * records. In this case, there is nothing to show.
663 663 */
664 664 if (vsdata && (vnap->vna_other > 0))
665 665 gvers_syms(vsdata, vnap->vna_other,
666 666 dep, needobj, file);
667 667 }
668 668 if (show && started && (vsdata == NULL))
669 669 (void) printf(MSG_ORIG(MSG_FMT_LIST_END_SEM));
670 670 }
671 671 return (error);
672 672 }
673 673
674 674 /*
675 675 * Return a GVer_desc descriptor for the given version if one
676 676 * exists.
677 677 *
678 678 * entry:
679 679 * name - Version name
680 680 * hash - ELF hash of name
681 681 * lst - APlist of existing descriptors.
682 682 * file - Object file containing the version
683 683 *
684 684 * exit:
685 685 * Return the corresponding GVer_desc struct if it
686 686 * exists, and NULL otherwise.
687 687 */
688 688 static GVer_desc *
689 689 gvers_find(const char *name, unsigned long hash, APlist *lst)
690 690 {
691 691 Aliste idx;
692 692 GVer_desc *vdp;
693 693
694 694 for (APLIST_TRAVERSE(lst, idx, vdp))
695 695 if ((vdp->vd_hash == hash) &&
696 696 (strcmp(vdp->vd_name, name) == 0))
697 697 return (vdp);
698 698
699 699 return (NULL);
700 700 }
701 701
702 702 /*
703 703 * Return a GVer_desc descriptor for the given version.
704 704 *
705 705 * entry:
706 706 * name - Version name
707 707 * hash - ELF hash of name
708 708 * lst - List of existing descriptors.
709 709 * file - Object file containing the version
710 710 *
711 711 * exit:
712 712 * Return the corresponding GVer_desc struct. If the
713 713 * descriptor does not already exist, it is created.
714 714 * On error, a fatal error is issued and the process exits.
715 715 */
716 716 static GVer_desc *
717 717 gvers_desc(const char *name, unsigned long hash, APlist **lst, const char *file)
718 718 {
719 719 GVer_desc *vdp;
720 720
721 721 if ((vdp = gvers_find(name, hash, *lst)) == NULL) {
722 722 if ((vdp = calloc(sizeof (GVer_desc), 1)) == NULL) {
723 723 int err = errno;
724 724 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname,
725 725 file, strerror(err));
726 726 exit(1);
727 727 }
728 728
729 729 vdp->vd_name = name;
730 730 vdp->vd_hash = hash;
731 731
732 732 pvs_aplist_append(lst, vdp, file);
733 733 }
734 734 return (vdp);
735 735 }
736 736
737 737 /*
738 738 * Insert a version dependency for the given GVer_desc descriptor.
739 739 *
740 740 * entry:
741 741 * name - Dependency version name
742 742 * hash - ELF hash of name
743 743 * lst - List of existing descriptors.
744 744 * vdp - Existing version descriptor to which the dependency
745 745 * is to be added.
746 746 * file - Object file containing the version
747 747 *
748 748 * exit:
749 749 * A descriptor for the dependency version is looked up
750 750 * (created if necessary), and then added to the dependency
751 751 * list for vdp. Returns the dependency descriptor. On error,
752 752 * a fatal error is issued and the process exits.
753 753 */
754 754 static GVer_desc *
755 755 gvers_depend(const char *name, unsigned long hash, GVer_desc *vdp, APlist **lst,
756 756 const char *file)
757 757 {
758 758 GVer_desc *_vdp;
759 759
760 760 _vdp = gvers_desc(name, hash, lst, file);
761 761 pvs_aplist_append(&vdp->vd_deps, _vdp, file);
762 762 return (vdp);
763 763 }
764 764
765 765 static void
766 766 gvers_derefer(GVer_desc *vdp, int weak)
767 767 {
768 768 Aliste idx;
769 769 GVer_desc *_vdp;
770 770
771 771 /*
772 772 * If the head of the list was a weak then we only clear out
773 773 * weak dependencies, but if the head of the list was 'strong'
774 774 * we clear the REFER bit on all dependencies.
775 775 */
776 776 if ((weak && (vdp->vd_flags & VER_FLG_WEAK)) || (!weak))
777 777 vdp->vd_flags &= ~FLG_VER_AVAIL;
778 778
779 779 for (APLIST_TRAVERSE(vdp->vd_deps, idx, _vdp))
780 780 gvers_derefer(_vdp, weak);
781 781 }
782 782
783 783
784 784 static void
785 785 recurse_syms(const Gver_sym_data *vsdata, GVer_desc *vdp, const char *file)
786 786 {
787 787 Aliste idx;
788 788 GVer_desc *_vdp;
789 789
790 790 for (APLIST_TRAVERSE(vdp->vd_deps, idx, _vdp)) {
791 791 if (!oflag)
792 792 (void) printf(MSG_ORIG(MSG_FMT_TNCO), _vdp->vd_name);
793 793 gvers_syms(vsdata, _vdp->vd_ndx, _vdp->vd_name, NULL, file);
794 794 if (aplist_nitems(_vdp->vd_deps) != 0)
795 795 recurse_syms(vsdata, _vdp, file);
796 796 }
797 797 }
798 798
799 799
800 800 /*
801 801 * Print the files version definition sections.
802 802 */
803 803 static int
804 804 gvers_def(Cache *cache, Cache *def, const Gver_sym_data *vsdata,
805 805 const char *file)
806 806 {
807 807 unsigned int num, _num;
808 808 char *strs;
809 809 GElf_Verdef *vdf = def->c_data->d_buf;
810 810 GElf_Shdr shdr;
811 811 GVer_desc *vdp, *bvdp = NULL;
812 812 Aliste idx1;
813 813 APlist *verdefs = NULL;
814 814 int error = 0;
815 815
816 816 /*
817 817 * Verify the version revision. We only check the first version
818 818 * structure as it is assumed all other version structures in this
819 819 * data section will be of the same revision.
820 820 */
821 821 if (vdf->vd_version > VER_DEF_CURRENT) {
822 822 (void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file,
823 823 vdf->vd_version, VER_DEF_CURRENT);
824 824 }
825 825
826 826 /*
827 827 * Get the data buffer for the associated string table.
828 828 */
829 829 (void) gelf_getshdr(def->c_scn, &shdr);
830 830 strs = (char *)cache[shdr.sh_link].c_data->d_buf;
831 831 num = shdr.sh_info;
832 832
833 833 /*
834 834 * Process the version definitions placing each on a version dependency
835 835 * list.
836 836 */
837 837 for (_num = 1; _num <= num; _num++,
838 838 vdf = (GElf_Verdef *)((uintptr_t)vdf + vdf->vd_next)) {
839 839 GElf_Half cnt = vdf->vd_cnt;
840 840 GElf_Half ndx = vdf->vd_ndx;
841 841 GElf_Verdaux *vdap;
842 842 const char *_name;
843 843
844 844 vdap = (GElf_Verdaux *)((uintptr_t)vdf + vdf->vd_aux);
845 845
846 846 /*
847 847 * Determine the version name and any dependencies.
848 848 */
849 849 _name = (char *)(strs + vdap->vda_name);
850 850
851 851 vdp = gvers_desc(_name, elf_hash(_name), &verdefs, file);
852 852 vdp->vd_ndx = ndx;
853 853 vdp->vd_flags = vdf->vd_flags | FLG_VER_AVAIL;
854 854
855 855 vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next);
856 856 for (cnt--; cnt; cnt--,
857 857 vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next)) {
858 858 _name = (char *)(strs + vdap->vda_name);
859 859 if (gvers_depend(_name, elf_hash(_name), vdp,
860 860 &verdefs, file) == NULL)
861 861 return (0);
862 862 }
863 863
864 864 /*
865 865 * Remember the base version for possible later use.
866 866 */
867 867 if (ndx == VER_NDX_GLOBAL)
868 868 bvdp = vdp;
869 869 }
870 870
871 871 /*
872 872 * Normalize the dependency list if required.
873 873 */
874 874 if (nflag) {
875 875 for (APLIST_TRAVERSE(verdefs, idx1, vdp)) {
876 876 Aliste idx2;
877 877 GVer_desc *_vdp;
878 878 int type = vdp->vd_flags & VER_FLG_WEAK;
879 879
880 880 for (APLIST_TRAVERSE(vdp->vd_deps, idx2, _vdp))
881 881 gvers_derefer(_vdp, type);
882 882 }
883 883
884 884 /*
885 885 * Always dereference the base version.
886 886 */
887 887 if (bvdp)
888 888 bvdp->vd_flags &= ~FLG_VER_AVAIL;
889 889 }
890 890
891 891
892 892 /*
893 893 * Traverse the dependency list and print out the appropriate
894 894 * information.
895 895 */
896 896 for (APLIST_TRAVERSE(verdefs, idx1, vdp)) {
897 897 Aliste idx2;
898 898 GVer_desc *_vdp;
899 899 int count;
900 900
901 901 if (!match(NULL, vdp->vd_name, vdp->vd_ndx))
902 902 continue;
903 903 if ((alist_nitems(match_list) == 0) &&
904 904 !(vdp->vd_flags & FLG_VER_AVAIL))
905 905 continue;
906 906
907 907 error = 1;
908 908
909 909 if (vflag) {
910 910 /*
911 911 * If the verbose flag is set determine if this version
912 912 * has a `weak' attribute, and print any version
913 913 * dependencies this version inherits.
914 914 */
915 915 if (oflag)
916 916 (void) printf(MSG_ORIG(MSG_FMT_OFIL), file);
917 917 (void) printf(MSG_ORIG(MSG_FMT_VER_NAME), vdp->vd_name);
918 918 if ((vdp->vd_flags & MSK_VER_USER) != 0) {
919 919 Conv_ver_flags_buf_t ver_flags_buf;
920 920
921 921 (void) printf(MSG_ORIG(MSG_FMT_VER_FLG),
922 922 conv_ver_flags(
923 923 vdp->vd_flags & MSK_VER_USER,
924 924 CONV_FMT_NOBKT, &ver_flags_buf));
925 925 }
926 926
927 927 count = 1;
928 928 for (APLIST_TRAVERSE(vdp->vd_deps, idx2, _vdp)) {
929 929 const char *_name = _vdp->vd_name;
930 930
931 931 if (count++ == 1) {
932 932
933 933 if (oflag)
934 934 (void) printf(
935 935 MSG_ORIG(MSG_FMT_IN_OFLG),
936 936 _name);
937 937 else if (vdp->vd_flags & VER_FLG_WEAK)
938 938 (void) printf(
939 939 MSG_ORIG(MSG_FMT_IN_WEAK),
940 940 _name);
941 941 else
942 942 (void) printf(
943 943 MSG_ORIG(MSG_FMT_IN),
944 944 _name);
945 945 } else
946 946 (void) printf(
947 947 MSG_ORIG(MSG_FMT_LIST_NEXT), _name);
948 948 }
949 949
950 950 if (count != 1)
951 951 (void) printf(MSG_ORIG(MSG_FMT_IN_END));
952 952
953 953 if (vsdata && !oflag)
954 954 (void) printf(MSG_ORIG(MSG_FMT_COL_NL));
955 955 else
956 956 (void) printf(MSG_ORIG(MSG_FMT_SEM_NL));
957 957 } else {
958 958 if (vsdata && !oflag)
959 959 (void) printf(MSG_ORIG(MSG_FMT_TNCO),
960 960 vdp->vd_name);
961 961 else if (!vsdata) {
962 962 if (oflag)
963 963 (void) printf(MSG_ORIG(MSG_FMT_OFIL),
964 964 file);
965 965 (void) printf(MSG_ORIG(MSG_FMT_TNSE),
966 966 vdp->vd_name);
967 967 }
968 968 }
969 969
970 970 /* If we are not printing symbols, we're done */
971 971 if (vsdata == NULL)
972 972 continue;
973 973
974 974 /*
975 975 * If a specific version to match has been specified then
976 976 * display any of its own symbols plus any inherited from
977 977 * other versions. Otherwise simply print out the symbols
978 978 * for this version.
979 979 */
980 980 gvers_syms(vsdata, vdp->vd_ndx, vdp->vd_name, NULL, file);
981 981 if (alist_nitems(match_list) != 0) {
982 982 recurse_syms(vsdata, vdp, file);
983 983
984 984 /*
985 985 * If the verbose flag is set, and this is not
986 986 * the base version, then add the base version as a
987 987 * dependency.
988 988 */
989 989 if (vflag && bvdp &&
990 990 !match(NULL, bvdp->vd_name, bvdp->vd_ndx)) {
991 991 if (!oflag)
992 992 (void) printf(MSG_ORIG(MSG_FMT_TNCO),
993 993 bvdp->vd_name);
994 994 gvers_syms(vsdata, bvdp->vd_ndx,
995 995 bvdp->vd_name, NULL, file);
996 996 }
997 997 }
998 998 }
999 999 return (error);
1000 1000 }
1001 1001
1002 1002 int
1003 1003 main(int argc, char **argv, char **envp)
1004 1004 {
1005 1005 GElf_Shdr shdr;
1006 1006 Elf *elf;
1007 1007 Elf_Scn *scn;
1008 1008 Elf_Data *data;
1009 1009 GElf_Ehdr ehdr;
1010 1010 int nfile, var;
1011 1011 char *names;
1012 1012 Cache *cache, *_cache;
1013 1013 Cache *_cache_def, *_cache_need, *_cache_sym, *_cache_loc;
1014 1014 int error = 0;
1015 1015 Gver_sym_data vsdata_s;
1016 1016 const Gver_sym_data *vsdata = NULL;
1017 1017
1018 1018 /*
1019 1019 * Check for a binary that better fits this architecture.
1020 1020 */
1021 1021 (void) conv_check_native(argv, envp);
1022 1022
1023 1023 /*
1024 1024 * Establish locale.
1025 1025 */
1026 1026 (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
1027 1027 (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
1028 1028
1029 1029 cname = argv[0];
1030 1030 Cflag = dflag = lflag = nflag = oflag = rflag = sflag = vflag = 0;
1031 1031
1032 1032 opterr = 0;
1033 1033 while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
1034 1034 switch (var) {
1035 1035 case 'C':
1036 1036 Cflag = USR_DEFINED;
1037 1037 break;
1038 1038 case 'd':
1039 1039 dflag = USR_DEFINED;
1040 1040 break;
1041 1041 case 'l':
1042 1042 lflag = sflag = USR_DEFINED;
1043 1043 break;
1044 1044 case 'n':
1045 1045 nflag = USR_DEFINED;
1046 1046 break;
1047 1047 case 'o':
1048 1048 oflag = USR_DEFINED;
1049 1049 break;
1050 1050 case 'r':
1051 1051 rflag = USR_DEFINED;
1052 1052 break;
1053 1053 case 's':
1054 1054 sflag = USR_DEFINED;
1055 1055 break;
1056 1056 case 'v':
1057 1057 vflag = USR_DEFINED;
1058 1058 break;
1059 1059 case 'I':
1060 1060 case 'N':
1061 1061 add_match_record(var, optarg);
1062 1062 break;
1063 1063 case '?':
1064 1064 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
1065 1065 cname);
1066 1066 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL));
1067 1067 exit(1);
1068 1068 default:
1069 1069 break;
1070 1070 }
1071 1071 }
1072 1072
1073 1073 /*
1074 1074 * No files specified on the command line?
1075 1075 */
1076 1076 if ((nfile = argc - optind) == 0) {
1077 1077 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), cname);
1078 1078 exit(1);
1079 1079 }
1080 1080
1081 1081 /*
1082 1082 * By default print both version definitions and needed dependencies.
↓ open down ↓ |
1082 lines elided |
↑ open up ↑ |
1083 1083 */
1084 1084 if ((dflag == 0) && (rflag == 0) && (lflag == 0))
1085 1085 dflag = rflag = DEF_DEFINED;
1086 1086
1087 1087 /*
1088 1088 * Open the input file and initialize the elf interface.
1089 1089 */
1090 1090 for (; optind < argc; optind++) {
1091 1091 int derror = 0, nerror = 0, err;
1092 1092 const char *file = argv[optind];
1093 + size_t shnum = 0;
1093 1094
1094 1095 if ((var = open(file, O_RDONLY)) == -1) {
1095 1096 err = errno;
1096 1097 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
1097 1098 cname, file, strerror(err));
1098 1099 error = 1;
1099 1100 continue;
1100 1101 }
1101 1102 (void) elf_version(EV_CURRENT);
1102 1103 if ((elf = elf_begin(var, ELF_C_READ, NULL)) == NULL) {
1103 1104 (void) fprintf(stderr, MSG_ORIG(MSG_ELF_BEGIN), cname,
1104 1105 file, elf_errmsg(elf_errno()));
1105 1106 error = 1;
1106 1107 (void) close(var);
1107 1108 continue;
1108 1109 }
1109 1110 if (elf_kind(elf) != ELF_K_ELF) {
1110 1111 (void) fprintf(stderr, MSG_INTL(MSG_ELF_NOTELF), cname,
1111 1112 file);
1112 1113 error = 1;
1113 1114 (void) close(var);
1114 1115 (void) elf_end(elf);
1115 1116 continue;
1116 1117 }
1117 1118 if (gelf_getehdr(elf, &ehdr) == NULL) {
1118 1119 (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETEHDR), cname,
1119 1120 file, elf_errmsg(elf_errno()));
1120 1121 error = 1;
1121 1122 (void) close(var);
1122 1123 (void) elf_end(elf);
1123 1124 continue;
1124 1125 }
1125 1126
1126 1127 /*
1127 1128 * Obtain the .shstrtab data buffer to provide the required
1128 1129 * section name strings.
1129 1130 */
1130 1131 if ((scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL) {
1131 1132 (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETSCN), cname,
1132 1133 file, elf_errmsg(elf_errno()));
1133 1134 error = 1;
1134 1135 (void) close(var);
1135 1136 (void) elf_end(elf);
1136 1137 continue;
1137 1138 }
1138 1139 if ((data = elf_getdata(scn, NULL)) == NULL) {
1139 1140 (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETDATA), cname,
1140 1141 file, elf_errmsg(elf_errno()));
1141 1142 error = 1;
1142 1143 (void) close(var);
1143 1144 (void) elf_end(elf);
1144 1145 continue;
1145 1146 }
1146 1147 names = data->d_buf;
↓ open down ↓ |
44 lines elided |
↑ open up ↑ |
1147 1148
1148 1149 /*
1149 1150 * Fill in the cache descriptor with information for each
1150 1151 * section we might need. We probably only need to save
1151 1152 * read-only allocable sections as this is where the version
1152 1153 * structures and their associated symbols and strings live.
1153 1154 * However, God knows what someone can do with a mapfile, and
1154 1155 * as elf_begin has already gone through all the overhead we
1155 1156 * might as well set up the cache for every section.
1156 1157 */
1157 - if ((cache = calloc(ehdr.e_shnum, sizeof (Cache))) == NULL) {
1158 + if (elf_getshdrnum(elf, &shnum) == -1) {
1159 + (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETSHDRNUM),
1160 + cname, file, elf_errmsg(elf_errno()));
1161 + exit(1);
1162 + }
1163 +
1164 + if ((cache = calloc(shnum, sizeof (Cache))) == NULL) {
1158 1165 int err = errno;
1159 1166 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname,
1160 1167 file, strerror(err));
1161 1168 exit(1);
1162 1169 }
1163 1170
1164 1171 _cache_def = _cache_need = _cache_sym = _cache_loc = NULL;
1165 1172 _cache = cache;
1166 1173 _cache++;
1167 1174 for (scn = NULL; scn = elf_nextscn(elf, scn); _cache++) {
1168 1175 if (gelf_getshdr(scn, &shdr) == NULL) {
1169 1176 (void) fprintf(stderr,
1170 1177 MSG_ORIG(MSG_ELF_GETSHDR), cname, file,
1171 1178 elf_errmsg(elf_errno()));
1172 1179 error = 1;
1173 1180 continue;
1174 1181 }
1175 1182 if ((_cache->c_data = elf_getdata(scn, NULL)) ==
1176 1183 NULL) {
1177 1184 (void) fprintf(stderr,
1178 1185 MSG_ORIG(MSG_ELF_GETDATA), cname, file,
1179 1186 elf_errmsg(elf_errno()));
1180 1187 error = 1;
1181 1188 continue;
1182 1189 }
1183 1190 _cache->c_scn = scn;
1184 1191 _cache->c_name = names + shdr.sh_name;
1185 1192
1186 1193 /*
1187 1194 * Remember the version sections and symbol table.
1188 1195 */
1189 1196 switch (shdr.sh_type) {
1190 1197 case SHT_SUNW_verdef:
1191 1198 if (dflag)
1192 1199 _cache_def = _cache;
1193 1200 break;
1194 1201 case SHT_SUNW_verneed:
1195 1202 if (rflag)
1196 1203 _cache_need = _cache;
1197 1204 break;
1198 1205 case SHT_SUNW_versym:
1199 1206 if (sflag)
1200 1207 _cache_sym = _cache;
1201 1208 break;
1202 1209 case SHT_SYMTAB:
1203 1210 if (lflag)
1204 1211 _cache_loc = _cache;
1205 1212 break;
1206 1213 }
1207 1214 }
1208 1215
1209 1216 /*
1210 1217 * Before printing anything out determine if any warnings are
1211 1218 * necessary.
1212 1219 */
1213 1220 if (lflag && (_cache_loc == NULL)) {
1214 1221 (void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS),
1215 1222 cname, file);
1216 1223 (void) fprintf(stderr, MSG_INTL(MSG_VER_NOSYMTAB));
1217 1224 }
1218 1225
1219 1226 /*
1220 1227 * If there is more than one input file, and we're not printing
1221 1228 * one-line output, display the filename being processed.
1222 1229 */
1223 1230 if ((nfile > 1) && !oflag)
1224 1231 (void) printf(MSG_ORIG(MSG_FMT_FILE), file);
1225 1232
1226 1233 /*
1227 1234 * If we're printing symbols, then collect the data
1228 1235 * necessary to do that.
1229 1236 */
1230 1237 if (_cache_sym != NULL) {
1231 1238 vsdata = &vsdata_s;
1232 1239 (void) gelf_getshdr(_cache_sym->c_scn, &shdr);
1233 1240 vsdata_s.vsd_vsp =
1234 1241 (GElf_Versym *)_cache_sym->c_data->d_buf;
1235 1242 vsdata_s.vsd_sym_data = cache[shdr.sh_link].c_data;
1236 1243 (void) gelf_getshdr(cache[shdr.sh_link].c_scn, &shdr);
1237 1244 vsdata_s.vsd_symn = shdr.sh_size / shdr.sh_entsize;
1238 1245 vsdata_s.vsd_strs =
1239 1246 (const char *)cache[shdr.sh_link].c_data->d_buf;
1240 1247 }
1241 1248
1242 1249
1243 1250 /*
1244 1251 * Print the files version needed sections.
1245 1252 */
1246 1253 if (_cache_need)
1247 1254 nerror = gvers_need(cache, _cache_need, vsdata, file);
1248 1255
1249 1256 /*
1250 1257 * Print the files version definition sections.
1251 1258 */
1252 1259 if (_cache_def)
1253 1260 derror = gvers_def(cache, _cache_def, vsdata, file);
1254 1261
1255 1262 /*
1256 1263 * Print any local symbol reductions.
1257 1264 */
1258 1265 if (_cache_loc)
1259 1266 sym_local(cache, _cache_loc, file);
1260 1267
1261 1268 /*
1262 1269 * Determine the error return. There are three conditions that
1263 1270 * may produce an error (a non-zero return):
1264 1271 *
1265 1272 * o if the user specified -d and no version definitions
1266 1273 * were found.
1267 1274 *
1268 1275 * o if the user specified -r and no version requirements
1269 1276 * were found.
1270 1277 *
1271 1278 * o if the user specified neither -d or -r, (thus both are
1272 1279 * enabled by default), and no version definitions or
1273 1280 * version dependencies were found.
1274 1281 */
1275 1282 if (((dflag == USR_DEFINED) && (derror == 0)) ||
1276 1283 ((rflag == USR_DEFINED) && (nerror == 0)) ||
1277 1284 (rflag && dflag && (derror == 0) && (nerror == 0)))
1278 1285 error = 1;
1279 1286
1280 1287 (void) close(var);
1281 1288 (void) elf_end(elf);
1282 1289 free(cache);
1283 1290 }
1284 1291 return (error);
1285 1292 }
1286 1293
1287 1294 const char *
1288 1295 _pvs_msg(Msg mid)
1289 1296 {
1290 1297 return (gettext(MSG_ORIG(mid)));
1291 1298 }
↓ open down ↓ |
124 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX