Print this page
style fixes
comments; lint
unbreak dis
move fixed-size determination mostly into libdisasm
take to dis and libdisasm with an axe; does not yet compile
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/dis/dis_main.c
+++ new/usr/src/cmd/dis/dis_main.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
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
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 2007 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 *
26 26 * Copyright 2011 Jason King. All rights reserved.
27 + * Copyright 2012 Joshua M. Clulow <josh@sysmgr.org>
27 28 */
28 29
29 30 #include <ctype.h>
30 31 #include <getopt.h>
31 32 #include <stdio.h>
32 33 #include <stdlib.h>
33 34 #include <string.h>
34 35 #include <sys/sysmacros.h>
35 36 #include <sys/elf_SPARC.h>
36 37
37 38 #include <libdisasm.h>
38 39
39 40 #include "dis_target.h"
40 41 #include "dis_util.h"
41 42 #include "dis_list.h"
42 43
43 44 int g_demangle; /* Demangle C++ names */
44 45 int g_quiet; /* Quiet mode */
45 46 int g_numeric; /* Numeric mode */
46 47 int g_flags; /* libdisasm language flags */
47 48 int g_doall; /* true if no functions or sections were given */
48 49
49 50 dis_namelist_t *g_funclist; /* list of functions to disassemble, if any */
50 51 dis_namelist_t *g_seclist; /* list of sections to disassemble, if any */
51 52
52 53 /*
53 54 * Section options for -d, -D, and -s
54 55 */
55 56 #define DIS_DATA_RELATIVE 1
56 57 #define DIS_DATA_ABSOLUTE 2
57 58 #define DIS_TEXT 3
58 59
59 60 /*
60 61 * libdisasm callback data. Keeps track of current data (function or section)
61 62 * and offset within that data.
62 63 */
63 64 typedef struct dis_buffer {
64 65 dis_tgt_t *db_tgt; /* current dis target */
65 66 void *db_data; /* function or section data */
66 67 uint64_t db_addr; /* address of function start */
67 68 size_t db_size; /* size of data */
68 69 uint64_t db_nextaddr; /* next address to be read */
69 70 } dis_buffer_t;
70 71
71 72 #define MINSYMWIDTH 22 /* Minimum width of symbol portion of line */
72 73
73 74 /*
74 75 * Given a symbol+offset as returned by dis_tgt_lookup(), print an appropriately
75 76 * formatted symbol, based on the offset and current setttings.
76 77 */
77 78 void
78 79 getsymname(uint64_t addr, const char *symbol, off_t offset, char *buf,
79 80 size_t buflen)
80 81 {
81 82 if (symbol == NULL || g_numeric) {
82 83 if (g_flags & DIS_OCTAL)
83 84 (void) snprintf(buf, buflen, "0%llo", addr);
84 85 else
85 86 (void) snprintf(buf, buflen, "0x%llx", addr);
86 87 } else {
87 88 if (g_demangle)
88 89 symbol = dis_demangle(symbol);
89 90
↓ open down ↓ |
53 lines elided |
↑ open up ↑ |
90 91 if (offset == 0)
91 92 (void) snprintf(buf, buflen, "%s", symbol);
92 93 else if (g_flags & DIS_OCTAL)
93 94 (void) snprintf(buf, buflen, "%s+0%o", symbol, offset);
94 95 else
95 96 (void) snprintf(buf, buflen, "%s+0x%x", symbol, offset);
96 97 }
97 98 }
98 99
99 100 /*
101 + * Determine if we are on an architecture with fixed-size instructions,
102 + * and if so, what size they are.
103 + */
104 +static int
105 +insn_size(dis_handle_t *dhp)
106 +{
107 + int min = dis_min_instrlen(dhp);
108 + int max = dis_max_instrlen(dhp);
109 +
110 + if (min == max)
111 + return (min);
112 +
113 + return (0);
114 +}
115 +
116 +/*
100 117 * The main disassembly routine. Given a fixed-sized buffer and starting
101 118 * address, disassemble the data using the supplied target and libdisasm handle.
102 119 */
103 120 void
104 121 dis_data(dis_tgt_t *tgt, dis_handle_t *dhp, uint64_t addr, void *data,
105 122 size_t datalen)
106 123 {
107 124 dis_buffer_t db = { 0 };
108 125 char buf[BUFSIZE];
109 126 char symbuf[BUFSIZE];
110 127 const char *symbol;
111 128 const char *last_symbol;
112 129 off_t symoffset;
113 130 int i;
114 131 int bytesperline;
115 132 size_t symsize;
116 133 int isfunc;
117 134 size_t symwidth = 0;
135 + int ret;
136 + int insz = insn_size(dhp);
118 137
119 138 db.db_tgt = tgt;
120 139 db.db_data = data;
121 140 db.db_addr = addr;
122 141 db.db_size = datalen;
123 142
124 143 dis_set_data(dhp, &db);
125 144
126 145 if ((bytesperline = dis_max_instrlen(dhp)) > 6)
127 146 bytesperline = 6;
128 147
129 148 symbol = NULL;
130 149
131 150 while (addr < db.db_addr + db.db_size) {
132 151
133 - if (dis_disassemble(dhp, addr, buf, BUFSIZE) != 0) {
134 -#if defined(__sparc)
152 + ret = dis_disassemble(dhp, addr, buf, BUFSIZE);
153 + if (ret != 0 && insz > 0) {
135 154 /*
136 - * Since sparc instructions are fixed size, we
155 + * Since we know instructions are fixed size, we
137 156 * always know the address of the next instruction
138 157 */
139 158 (void) snprintf(buf, sizeof (buf),
140 159 "*** invalid opcode ***");
141 - db.db_nextaddr = addr + 4;
160 + db.db_nextaddr = addr + insz;
142 161
143 -#else
162 + } else if (ret != 0) {
144 163 off_t next;
145 164
146 165 (void) snprintf(buf, sizeof (buf),
147 166 "*** invalid opcode ***");
148 167
149 168 /*
150 169 * On architectures with variable sized instructions
151 170 * we have no way to figure out where the next
152 171 * instruction starts if we encounter an invalid
153 172 * instruction. Instead we print the rest of the
154 173 * instruction stream as hex until we reach the
155 174 * next valid symbol in the section.
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
156 175 */
157 176 if ((next = dis_tgt_next_symbol(tgt, addr)) == 0) {
158 177 db.db_nextaddr = db.db_addr + db.db_size;
159 178 } else {
160 179 if (next > db.db_size)
161 180 db.db_nextaddr = db.db_addr +
162 181 db.db_size;
163 182 else
164 183 db.db_nextaddr = addr + next;
165 184 }
166 -#endif
167 185 }
168 186
169 187 /*
170 188 * Print out the line as:
171 189 *
172 190 * address: bytes text
173 191 *
174 192 * If there are more than 6 bytes in any given instruction,
175 193 * spread the bytes across two lines. We try to get symbolic
176 194 * information for the address, but if that fails we print out
177 195 * the numeric address instead.
178 196 *
179 197 * We try to keep the address portion of the text aligned at
180 198 * MINSYMWIDTH characters. If we are disassembling a function
181 199 * with a long name, this can be annoying. So we pick a width
182 200 * based on the maximum width that the current symbol can be.
183 201 * This at least produces text aligned within each function.
184 202 */
185 203 last_symbol = symbol;
186 204 symbol = dis_tgt_lookup(tgt, addr, &symoffset, 1, &symsize,
187 205 &isfunc);
188 206 if (symbol == NULL) {
189 207 symbol = dis_find_section(tgt, addr, &symoffset);
190 208 symsize = symoffset;
191 209 }
192 210
193 211 if (symbol != last_symbol)
194 212 getsymname(addr, symbol, symsize, symbuf,
195 213 sizeof (symbuf));
196 214
197 215 symwidth = MAX(symwidth, strlen(symbuf));
198 216 getsymname(addr, symbol, symoffset, symbuf, sizeof (symbuf));
199 217
200 218 /*
201 219 * If we've crossed a new function boundary, print out the
202 220 * function name on a blank line.
203 221 */
204 222 if (!g_quiet && symoffset == 0 && symbol != NULL && isfunc)
205 223 (void) printf("%s()\n", symbol);
206 224
207 225 (void) printf(" %s:%*s ", symbuf,
208 226 symwidth - strlen(symbuf), "");
209 227
210 228 /* print bytes */
211 229 for (i = 0; i < MIN(bytesperline, (db.db_nextaddr - addr));
212 230 i++) {
213 231 int byte = *((uchar_t *)data + (addr - db.db_addr) + i);
214 232 if (g_flags & DIS_OCTAL)
215 233 (void) printf("%03o ", byte);
216 234 else
217 235 (void) printf("%02x ", byte);
218 236 }
219 237
220 238 /* trailing spaces for missing bytes */
221 239 for (; i < bytesperline; i++) {
222 240 if (g_flags & DIS_OCTAL)
223 241 (void) printf(" ");
224 242 else
225 243 (void) printf(" ");
226 244 }
227 245
228 246 /* contents of disassembly */
229 247 (void) printf(" %s", buf);
230 248
231 249 /* excess bytes that spill over onto subsequent lines */
232 250 for (; i < db.db_nextaddr - addr; i++) {
233 251 int byte = *((uchar_t *)data + (addr - db.db_addr) + i);
234 252 if (i % bytesperline == 0)
235 253 (void) printf("\n %*s ", symwidth, "");
236 254 if (g_flags & DIS_OCTAL)
237 255 (void) printf("%03o ", byte);
238 256 else
239 257 (void) printf("%02x ", byte);
240 258 }
241 259
242 260 (void) printf("\n");
243 261
244 262 addr = db.db_nextaddr;
245 263 }
246 264 }
247 265
248 266 /*
249 267 * libdisasm wrapper around symbol lookup. Invoke the target-specific lookup
250 268 * function, and convert the result using getsymname().
251 269 */
252 270 int
253 271 do_lookup(void *data, uint64_t addr, char *buf, size_t buflen, uint64_t *start,
254 272 size_t *symlen)
255 273 {
256 274 dis_buffer_t *db = data;
257 275 const char *symbol;
258 276 off_t offset;
259 277 size_t size;
260 278
261 279 /*
262 280 * If NULL symbol is returned, getsymname takes care of
263 281 * printing appropriate address in buf instead of symbol.
264 282 */
265 283 symbol = dis_tgt_lookup(db->db_tgt, addr, &offset, 0, &size, NULL);
266 284
267 285 if (buf != NULL)
268 286 getsymname(addr, symbol, offset, buf, buflen);
269 287
270 288 if (start != NULL)
271 289 *start = addr - offset;
272 290 if (symlen != NULL)
273 291 *symlen = size;
274 292
275 293 if (symbol == NULL)
276 294 return (-1);
277 295
278 296 return (0);
279 297 }
280 298
281 299 /*
282 300 * libdisasm wrapper around target reading. libdisasm will always read data
283 301 * in order, so update our current offset within the buffer appropriately.
284 302 * We only support reading from within the current object; libdisasm should
285 303 * never ask us to do otherwise.
286 304 */
287 305 int
288 306 do_read(void *data, uint64_t addr, void *buf, size_t len)
289 307 {
290 308 dis_buffer_t *db = data;
291 309 size_t offset;
292 310
293 311 if (addr < db->db_addr || addr >= db->db_addr + db->db_size)
294 312 return (-1);
295 313
296 314 offset = addr - db->db_addr;
297 315 len = MIN(len, db->db_size - offset);
298 316
299 317 (void) memcpy(buf, (char *)db->db_data + offset, len);
300 318
301 319 db->db_nextaddr = addr + len;
302 320
303 321 return (len);
304 322 }
305 323
306 324 /*
307 325 * Routine to dump raw data in a human-readable format. Used by the -d and -D
308 326 * options. We model our output after the xxd(1) program, which gives nicely
309 327 * formatted output, along with an ASCII translation of the result.
310 328 */
311 329 void
312 330 dump_data(uint64_t addr, void *data, size_t datalen)
313 331 {
314 332 uintptr_t curaddr = addr & (~0xf);
315 333 uint8_t *bytes = data;
316 334 int i;
317 335 int width;
318 336
319 337 /*
320 338 * Determine if the address given to us fits in 32-bit range, in which
321 339 * case use a 4-byte width.
322 340 */
323 341 if (((addr + datalen) & 0xffffffff00000000ULL) == 0ULL)
324 342 width = 8;
325 343 else
326 344 width = 16;
327 345
328 346 while (curaddr < addr + datalen) {
329 347 /*
330 348 * Display leading address
331 349 */
332 350 (void) printf("%0*x: ", width, curaddr);
333 351
334 352 /*
335 353 * Print out data in two-byte chunks. If the current address
336 354 * is before the starting address or after the end of the
337 355 * section, print spaces.
338 356 */
339 357 for (i = 0; i < 16; i++) {
340 358 if (curaddr + i < addr ||curaddr + i >= addr + datalen)
341 359 (void) printf(" ");
342 360 else
343 361 (void) printf("%02x",
344 362 bytes[curaddr + i - addr]);
345 363
346 364 if (i & 1)
347 365 (void) printf(" ");
348 366 }
349 367
350 368 (void) printf(" ");
351 369
352 370 /*
353 371 * Print out the ASCII representation
354 372 */
355 373 for (i = 0; i < 16; i++) {
356 374 if (curaddr + i < addr ||
357 375 curaddr + i >= addr + datalen) {
358 376 (void) printf(" ");
359 377 } else {
360 378 uint8_t byte = bytes[curaddr + i - addr];
361 379 if (isprint(byte))
362 380 (void) printf("%c", byte);
363 381 else
364 382 (void) printf(".");
365 383 }
366 384 }
367 385
368 386 (void) printf("\n");
369 387
370 388 curaddr += 16;
371 389 }
372 390 }
373 391
374 392 /*
375 393 * Disassemble a section implicitly specified as part of a file. This function
376 394 * is called for all sections when no other flags are specified. We ignore any
377 395 * data sections, and print out only those sections containing text.
378 396 */
379 397 void
380 398 dis_text_section(dis_tgt_t *tgt, dis_scn_t *scn, void *data)
381 399 {
382 400 dis_handle_t *dhp = data;
383 401
384 402 /* ignore data sections */
385 403 if (!dis_section_istext(scn))
386 404 return;
387 405
388 406 if (!g_quiet)
389 407 (void) printf("\nsection %s\n", dis_section_name(scn));
390 408
391 409 dis_data(tgt, dhp, dis_section_addr(scn), dis_section_data(scn),
392 410 dis_section_size(scn));
393 411 }
394 412
395 413 /*
396 414 * Structure passed to dis_named_{section,function} which keeps track of both
397 415 * the target and the libdisasm handle.
398 416 */
399 417 typedef struct callback_arg {
400 418 dis_tgt_t *ca_tgt;
401 419 dis_handle_t *ca_handle;
402 420 } callback_arg_t;
403 421
404 422 /*
405 423 * Disassemble a section explicitly named with -s, -d, or -D. The 'type'
406 424 * argument contains the type of argument given. Pass the data onto the
407 425 * appropriate helper routine.
408 426 */
409 427 void
410 428 dis_named_section(dis_scn_t *scn, int type, void *data)
411 429 {
412 430 callback_arg_t *ca = data;
413 431
414 432 if (!g_quiet)
415 433 (void) printf("\nsection %s\n", dis_section_name(scn));
416 434
417 435 switch (type) {
418 436 case DIS_DATA_RELATIVE:
419 437 dump_data(0, dis_section_data(scn), dis_section_size(scn));
420 438 break;
421 439 case DIS_DATA_ABSOLUTE:
422 440 dump_data(dis_section_addr(scn), dis_section_data(scn),
423 441 dis_section_size(scn));
424 442 break;
425 443 case DIS_TEXT:
426 444 dis_data(ca->ca_tgt, ca->ca_handle, dis_section_addr(scn),
427 445 dis_section_data(scn), dis_section_size(scn));
428 446 break;
429 447 }
430 448 }
431 449
432 450 /*
433 451 * Disassemble a function explicitly specified with '-F'. The 'type' argument
434 452 * is unused.
435 453 */
436 454 /* ARGSUSED */
437 455 void
438 456 dis_named_function(dis_func_t *func, int type, void *data)
439 457 {
440 458 callback_arg_t *ca = data;
441 459
442 460 dis_data(ca->ca_tgt, ca->ca_handle, dis_function_addr(func),
443 461 dis_function_data(func), dis_function_size(func));
444 462 }
445 463
446 464 /*
447 465 * Disassemble a complete file. First, we determine the type of the file based
448 466 * on the ELF machine type, and instantiate a version of the disassembler
449 467 * appropriate for the file. We then resolve any named sections or functions
450 468 * against the file, and iterate over the results (or all sections if no flags
451 469 * were specified).
452 470 */
453 471 void
454 472 dis_file(const char *filename)
455 473 {
456 474 dis_tgt_t *tgt, *current;
457 475 dis_scnlist_t *sections;
458 476 dis_funclist_t *functions;
459 477 dis_handle_t *dhp;
460 478 GElf_Ehdr ehdr;
461 479
462 480 /*
463 481 * First, initialize the target
464 482 */
465 483 if ((tgt = dis_tgt_create(filename)) == NULL)
466 484 return;
467 485
468 486 if (!g_quiet)
469 487 (void) printf("disassembly for %s\n\n", filename);
470 488
471 489 /*
472 490 * A given file may contain multiple targets (if it is an archive, for
473 491 * example). We iterate over all possible targets if this is the case.
474 492 */
↓ open down ↓ |
298 lines elided |
↑ open up ↑ |
475 493 for (current = tgt; current != NULL; current = dis_tgt_next(current)) {
476 494 dis_tgt_ehdr(current, &ehdr);
477 495
478 496 /*
479 497 * Eventually, this should probably live within libdisasm, and
480 498 * we should be able to disassemble targets from different
481 499 * architectures. For now, we only support objects as the
482 500 * native machine type.
483 501 */
484 502 switch (ehdr.e_machine) {
485 -#ifdef __sparc
486 503 case EM_SPARC:
487 504 if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 ||
488 505 ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
489 506 warn("invalid E_IDENT field for SPARC object");
490 507 return;
491 508 }
492 509 g_flags |= DIS_SPARC_V8;
493 510 break;
494 511
495 512 case EM_SPARC32PLUS:
496 513 {
497 514 uint64_t flags = ehdr.e_flags & EF_SPARC_32PLUS_MASK;
498 515
499 516 if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 ||
500 517 ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
501 518 warn("invalid E_IDENT field for SPARC object");
502 519 return;
503 520 }
504 521
505 522 if (flags != 0 &&
506 523 (flags & (EF_SPARC_32PLUS | EF_SPARC_SUN_US1 |
507 524 EF_SPARC_SUN_US3)) != EF_SPARC_32PLUS)
508 525 g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI;
509 526 else
510 527 g_flags |= DIS_SPARC_V9;
511 528 break;
512 529 }
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
513 530
514 531 case EM_SPARCV9:
515 532 if (ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
516 533 ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
517 534 warn("invalid E_IDENT field for SPARC object");
518 535 return;
519 536 }
520 537
521 538 g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI;
522 539 break;
523 -#endif /* __sparc */
524 540
525 -#if defined(__i386) || defined(__amd64)
526 541 case EM_386:
527 542 g_flags |= DIS_X86_SIZE32;
528 543 break;
529 544
530 545 case EM_AMD64:
531 546 g_flags |= DIS_X86_SIZE64;
532 547 break;
533 -#endif /* __i386 || __amd64 */
534 548
535 549 default:
536 550 die("%s: unsupported ELF machine 0x%x", filename,
537 551 ehdr.e_machine);
538 552 }
539 553
540 554 /*
541 555 * If ET_REL (.o), printing immediate symbols is likely to
542 556 * result in garbage, as symbol lookups on unrelocated
543 557 * immediates find false and useless matches.
544 558 */
545 559
546 560 if (ehdr.e_type == ET_REL)
547 561 g_flags |= DIS_NOIMMSYM;
548 562
549 563 if (!g_quiet && dis_tgt_member(current) != NULL)
550 564 (void) printf("\narchive member %s\n",
551 565 dis_tgt_member(current));
552 566
553 567 /*
554 568 * Instantiate a libdisasm handle based on the file type.
555 569 */
556 570 if ((dhp = dis_handle_create(g_flags, current, do_lookup,
557 571 do_read)) == NULL)
558 572 die("%s: failed to initialize disassembler: %s",
559 573 filename, dis_strerror(dis_errno()));
560 574
561 575 if (g_doall) {
562 576 /*
563 577 * With no arguments, iterate over all sections and
564 578 * disassemble only those that contain text.
565 579 */
566 580 dis_tgt_section_iter(current, dis_text_section, dhp);
567 581 } else {
568 582 callback_arg_t ca;
569 583
570 584 ca.ca_tgt = current;
571 585 ca.ca_handle = dhp;
572 586
573 587 /*
574 588 * If sections or functions were explicitly specified,
575 589 * resolve those names against the object, and iterate
576 590 * over just the resulting data.
577 591 */
578 592 sections = dis_namelist_resolve_sections(g_seclist,
579 593 current);
580 594 functions = dis_namelist_resolve_functions(g_funclist,
581 595 current);
582 596
583 597 dis_scnlist_iter(sections, dis_named_section, &ca);
584 598 dis_funclist_iter(functions, dis_named_function, &ca);
585 599
586 600 dis_scnlist_destroy(sections);
587 601 dis_funclist_destroy(functions);
588 602 }
589 603
590 604 dis_handle_destroy(dhp);
591 605 }
592 606
593 607 dis_tgt_destroy(tgt);
594 608 }
595 609
596 610 void
597 611 usage(void)
598 612 {
599 613 (void) fprintf(stderr, "usage: dis [-CVoqn] [-d sec] \n");
600 614 (void) fprintf(stderr, "\t[-D sec] [-F function] [-t sec] file ..\n");
601 615 exit(2);
602 616 }
603 617
604 618 typedef struct lib_node {
605 619 char *path;
606 620 struct lib_node *next;
607 621 } lib_node_t;
608 622
609 623 int
610 624 main(int argc, char **argv)
611 625 {
612 626 int optchar;
613 627 int i;
614 628 lib_node_t *libs = NULL;
615 629
616 630 g_funclist = dis_namelist_create();
617 631 g_seclist = dis_namelist_create();
618 632
619 633 while ((optchar = getopt(argc, argv, "Cd:D:F:l:Lot:Vqn")) != -1) {
620 634 switch (optchar) {
621 635 case 'C':
622 636 g_demangle = 1;
623 637 break;
624 638 case 'd':
625 639 dis_namelist_add(g_seclist, optarg, DIS_DATA_RELATIVE);
626 640 break;
627 641 case 'D':
628 642 dis_namelist_add(g_seclist, optarg, DIS_DATA_ABSOLUTE);
629 643 break;
630 644 case 'F':
631 645 dis_namelist_add(g_funclist, optarg, 0);
632 646 break;
633 647 case 'l': {
634 648 /*
635 649 * The '-l foo' option historically would attempt to
636 650 * disassemble '$LIBDIR/libfoo.a'. The $LIBDIR
637 651 * environment variable has never been supported or
638 652 * documented for our linker. However, until this
639 653 * option is formally EOLed, we have to support it.
640 654 */
641 655 char *dir;
642 656 lib_node_t *node;
643 657 size_t len;
644 658
645 659 if ((dir = getenv("LIBDIR")) == NULL ||
646 660 dir[0] == '\0')
647 661 dir = "/usr/lib";
648 662 node = safe_malloc(sizeof (lib_node_t));
649 663 len = strlen(optarg) + strlen(dir) + sizeof ("/lib.a");
650 664 node->path = safe_malloc(len);
651 665
652 666 (void) snprintf(node->path, len, "%s/lib%s.a", dir,
653 667 optarg);
654 668 node->next = libs;
655 669 libs = node;
656 670 break;
657 671 }
658 672 case 'L':
659 673 /*
660 674 * The '-L' option historically would attempt to read
661 675 * the .debug section of the target to determine source
662 676 * line information in order to annotate the output.
663 677 * No compiler has emitted these sections in many years,
664 678 * and the option has never done what it purported to
665 679 * do. We silently consume the option for
666 680 * compatibility.
667 681 */
668 682 break;
669 683 case 'n':
670 684 g_numeric = 1;
671 685 break;
672 686 case 'o':
673 687 g_flags |= DIS_OCTAL;
674 688 break;
675 689 case 'q':
676 690 g_quiet = 1;
677 691 break;
678 692 case 't':
679 693 dis_namelist_add(g_seclist, optarg, DIS_TEXT);
680 694 break;
681 695 case 'V':
682 696 (void) printf("Solaris disassembler version 1.0\n");
683 697 return (0);
684 698 default:
685 699 usage();
686 700 break;
687 701 }
688 702 }
689 703
690 704 argc -= optind;
691 705 argv += optind;
692 706
693 707 if (argc == 0 && libs == NULL) {
694 708 warn("no objects specified");
695 709 usage();
696 710 }
697 711
698 712 if (dis_namelist_empty(g_funclist) && dis_namelist_empty(g_seclist))
699 713 g_doall = 1;
700 714
701 715 /*
702 716 * See comment for 'l' option, above.
703 717 */
704 718 while (libs != NULL) {
705 719 lib_node_t *node = libs->next;
706 720
707 721 dis_file(libs->path);
708 722 free(libs->path);
709 723 free(libs);
710 724 libs = node;
711 725 }
712 726
713 727 for (i = 0; i < argc; i++)
714 728 dis_file(argv[i]);
715 729
716 730 dis_namelist_destroy(g_funclist);
717 731 dis_namelist_destroy(g_seclist);
718 732
719 733 return (g_error);
720 734 }
↓ open down ↓ |
177 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX