xref: /linux/tools/objtool/disas.c (revision a4f1599672e7bf494d79928a38fd6aa873e2e50c)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com>
4  */
5 
6 #define _GNU_SOURCE
7 #include <fnmatch.h>
8 
9 #include <objtool/arch.h>
10 #include <objtool/check.h>
11 #include <objtool/disas.h>
12 #include <objtool/warn.h>
13 
14 #include <bfd.h>
15 #include <linux/string.h>
16 #include <tools/dis-asm-compat.h>
17 
18 /*
19  * Size of the buffer for storing the result of disassembling
20  * a single instruction.
21  */
22 #define DISAS_RESULT_SIZE	1024
23 
24 struct disas_context {
25 	struct objtool_file *file;
26 	struct instruction *insn;
27 	char result[DISAS_RESULT_SIZE];
28 	disassembler_ftype disassembler;
29 	struct disassemble_info info;
30 };
31 
32 /*
33  * Maximum number of alternatives
34  */
35 #define DISAS_ALT_MAX		5
36 
37 /*
38  * Maximum number of instructions per alternative
39  */
40 #define DISAS_ALT_INSN_MAX	50
41 
42 /*
43  * Information to disassemble an alternative
44  */
45 struct disas_alt {
46 	struct instruction *orig_insn;		/* original instruction */
47 	struct alternative *alt;		/* alternative or NULL if default code */
48 	char *name;				/* name for this alternative */
49 	int width;				/* formatting width */
50 	char *insn[DISAS_ALT_INSN_MAX];		/* alternative instructions */
51 };
52 
53 #define DALT_DEFAULT(dalt)	(!(dalt)->alt)
54 #define DALT_INSN(dalt)		(DALT_DEFAULT(dalt) ? (dalt)->orig_insn : (dalt)->alt->insn)
55 #define DALT_GROUP(dalt)	(DALT_INSN(dalt)->alt_group)
56 #define DALT_ALTID(dalt)	((dalt)->orig_insn->offset)
57 
58 /*
59  * Wrapper around asprintf() to allocate and format a string.
60  * Return the allocated string or NULL on error.
61  */
62 static char *strfmt(const char *fmt, ...)
63 {
64 	va_list ap;
65 	char *str;
66 	int rv;
67 
68 	va_start(ap, fmt);
69 	rv = vasprintf(&str, fmt, ap);
70 	va_end(ap);
71 
72 	return rv == -1 ? NULL : str;
73 }
74 
75 static int sprint_name(char *str, const char *name, unsigned long offset)
76 {
77 	int len;
78 
79 	if (offset)
80 		len = sprintf(str, "%s+0x%lx", name, offset);
81 	else
82 		len = sprintf(str, "%s", name);
83 
84 	return len;
85 }
86 
87 #define DINFO_FPRINTF(dinfo, ...)	\
88 	((*(dinfo)->fprintf_func)((dinfo)->stream, __VA_ARGS__))
89 
90 static int disas_result_fprintf(struct disas_context *dctx,
91 				const char *fmt, va_list ap)
92 {
93 	char *buf = dctx->result;
94 	int avail, len;
95 
96 	len = strlen(buf);
97 	if (len >= DISAS_RESULT_SIZE - 1) {
98 		WARN_FUNC(dctx->insn->sec, dctx->insn->offset,
99 			  "disassembly buffer is full");
100 		return -1;
101 	}
102 	avail = DISAS_RESULT_SIZE - len;
103 
104 	len = vsnprintf(buf + len, avail, fmt, ap);
105 	if (len < 0 || len >= avail) {
106 		WARN_FUNC(dctx->insn->sec, dctx->insn->offset,
107 			  "disassembly buffer is truncated");
108 		return -1;
109 	}
110 
111 	return 0;
112 }
113 
114 static int disas_fprintf(void *stream, const char *fmt, ...)
115 {
116 	va_list arg;
117 	int rv;
118 
119 	va_start(arg, fmt);
120 	rv = disas_result_fprintf(stream, fmt, arg);
121 	va_end(arg);
122 
123 	return rv;
124 }
125 
126 /*
127  * For init_disassemble_info_compat().
128  */
129 static int disas_fprintf_styled(void *stream,
130 				enum disassembler_style style,
131 				const char *fmt, ...)
132 {
133 	va_list arg;
134 	int rv;
135 
136 	va_start(arg, fmt);
137 	rv = disas_result_fprintf(stream, fmt, arg);
138 	va_end(arg);
139 
140 	return rv;
141 }
142 
143 static void disas_print_addr_sym(struct section *sec, struct symbol *sym,
144 				 bfd_vma addr, struct disassemble_info *dinfo)
145 {
146 	char symstr[1024];
147 	char *str;
148 
149 	if (sym) {
150 		sprint_name(symstr, sym->name, addr - sym->offset);
151 		DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, symstr);
152 	} else {
153 		str = offstr(sec, addr);
154 		DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, str);
155 		free(str);
156 	}
157 }
158 
159 static void disas_print_addr_noreloc(bfd_vma addr,
160 				     struct disassemble_info *dinfo)
161 {
162 	struct disas_context *dctx = dinfo->application_data;
163 	struct instruction *insn = dctx->insn;
164 	struct symbol *sym = NULL;
165 
166 	if (insn->sym && addr >= insn->sym->offset &&
167 	    addr < insn->sym->offset + insn->sym->len) {
168 		sym = insn->sym;
169 	}
170 
171 	disas_print_addr_sym(insn->sec, sym, addr, dinfo);
172 }
173 
174 static void disas_print_addr_reloc(bfd_vma addr, struct disassemble_info *dinfo)
175 {
176 	struct disas_context *dctx = dinfo->application_data;
177 	struct instruction *insn = dctx->insn;
178 	unsigned long offset;
179 	struct reloc *reloc;
180 	char symstr[1024];
181 	char *str;
182 
183 	reloc = find_reloc_by_dest_range(dctx->file->elf, insn->sec,
184 					 insn->offset, insn->len);
185 	if (!reloc) {
186 		/*
187 		 * There is no relocation for this instruction although
188 		 * the address to resolve points to the next instruction.
189 		 * So this is an effective reference to the next IP, for
190 		 * example: "lea 0x0(%rip),%rdi". The kernel can reference
191 		 * the next IP with _THIS_IP_ macro.
192 		 */
193 		DINFO_FPRINTF(dinfo, "0x%lx <_THIS_IP_>", addr);
194 		return;
195 	}
196 
197 	offset = arch_insn_adjusted_addend(insn, reloc);
198 
199 	/*
200 	 * If the relocation symbol is a section name (for example ".bss")
201 	 * then we try to further resolve the name.
202 	 */
203 	if (reloc->sym->type == STT_SECTION) {
204 		str = offstr(reloc->sym->sec, reloc->sym->offset + offset);
205 		DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, str);
206 		free(str);
207 	} else {
208 		sprint_name(symstr, reloc->sym->name, offset);
209 		DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, symstr);
210 	}
211 }
212 
213 /*
214  * Resolve an address into a "<symbol>+<offset>" string.
215  */
216 static void disas_print_address(bfd_vma addr, struct disassemble_info *dinfo)
217 {
218 	struct disas_context *dctx = dinfo->application_data;
219 	struct instruction *insn = dctx->insn;
220 	struct instruction *jump_dest;
221 	struct symbol *sym;
222 	bool is_reloc;
223 
224 	/*
225 	 * If the instruction is a call/jump and it references a
226 	 * destination then this is likely the address we are looking
227 	 * up. So check it first.
228 	 */
229 	jump_dest = insn->jump_dest;
230 	if (jump_dest && jump_dest->sym && jump_dest->offset == addr) {
231 		disas_print_addr_sym(jump_dest->sec, jump_dest->sym,
232 				     addr, dinfo);
233 		return;
234 	}
235 
236 	/*
237 	 * If the address points to the next instruction then there is
238 	 * probably a relocation. It can be a false positive when the
239 	 * current instruction is referencing the address of the next
240 	 * instruction. This particular case will be handled in
241 	 * disas_print_addr_reloc().
242 	 */
243 	is_reloc = (addr == insn->offset + insn->len);
244 
245 	/*
246 	 * The call destination offset can be the address we are looking
247 	 * up, or 0 if there is a relocation.
248 	 */
249 	sym = insn_call_dest(insn);
250 	if (sym && (sym->offset == addr || (sym->offset == 0 && is_reloc))) {
251 		DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, sym->name);
252 		return;
253 	}
254 
255 	if (!is_reloc)
256 		disas_print_addr_noreloc(addr, dinfo);
257 	else
258 		disas_print_addr_reloc(addr, dinfo);
259 }
260 
261 /*
262  * Initialize disassemble info arch, mach (32 or 64-bit) and options.
263  */
264 int disas_info_init(struct disassemble_info *dinfo,
265 		    int arch, int mach32, int mach64,
266 		    const char *options)
267 {
268 	struct disas_context *dctx = dinfo->application_data;
269 	struct objtool_file *file = dctx->file;
270 
271 	dinfo->arch = arch;
272 
273 	switch (file->elf->ehdr.e_ident[EI_CLASS]) {
274 	case ELFCLASS32:
275 		dinfo->mach = mach32;
276 		break;
277 	case ELFCLASS64:
278 		dinfo->mach = mach64;
279 		break;
280 	default:
281 		return -1;
282 	}
283 
284 	dinfo->disassembler_options = options;
285 
286 	return 0;
287 }
288 
289 struct disas_context *disas_context_create(struct objtool_file *file)
290 {
291 	struct disas_context *dctx;
292 	struct disassemble_info *dinfo;
293 	int err;
294 
295 	dctx = malloc(sizeof(*dctx));
296 	if (!dctx) {
297 		WARN("failed to allocate disassembly context");
298 		return NULL;
299 	}
300 
301 	dctx->file = file;
302 	dinfo = &dctx->info;
303 
304 	init_disassemble_info_compat(dinfo, dctx,
305 				     disas_fprintf, disas_fprintf_styled);
306 
307 	dinfo->read_memory_func = buffer_read_memory;
308 	dinfo->print_address_func = disas_print_address;
309 	dinfo->application_data = dctx;
310 
311 	/*
312 	 * bfd_openr() is not used to avoid doing ELF data processing
313 	 * and caching that has already being done. Here, we just need
314 	 * to identify the target file so we call an arch specific
315 	 * function to fill some disassemble info (arch, mach).
316 	 */
317 
318 	dinfo->arch = bfd_arch_unknown;
319 	dinfo->mach = 0;
320 
321 	err = arch_disas_info_init(dinfo);
322 	if (err || dinfo->arch == bfd_arch_unknown || dinfo->mach == 0) {
323 		WARN("failed to init disassembly arch");
324 		goto error;
325 	}
326 
327 	dinfo->endian = (file->elf->ehdr.e_ident[EI_DATA] == ELFDATA2MSB) ?
328 		BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
329 
330 	disassemble_init_for_target(dinfo);
331 
332 	dctx->disassembler = disassembler(dinfo->arch,
333 					  dinfo->endian == BFD_ENDIAN_BIG,
334 					  dinfo->mach, NULL);
335 	if (!dctx->disassembler) {
336 		WARN("failed to create disassembler function");
337 		goto error;
338 	}
339 
340 	return dctx;
341 
342 error:
343 	free(dctx);
344 	return NULL;
345 }
346 
347 void disas_context_destroy(struct disas_context *dctx)
348 {
349 	free(dctx);
350 }
351 
352 char *disas_result(struct disas_context *dctx)
353 {
354 	return dctx->result;
355 }
356 
357 #define DISAS_INSN_OFFSET_SPACE		10
358 #define DISAS_INSN_SPACE		60
359 
360 #define DISAS_PRINSN(dctx, insn, depth)			\
361 	disas_print_insn(stdout, dctx, insn, depth, "\n")
362 
363 /*
364  * Print a message in the instruction flow. If insn is not NULL then
365  * the instruction address is printed in addition of the message,
366  * otherwise only the message is printed. In all cases, the instruction
367  * itself is not printed.
368  */
369 static int disas_vprint(FILE *stream, struct section *sec, unsigned long offset,
370 			int depth, const char *format, va_list ap)
371 {
372 	const char *addr_str;
373 	int i, n;
374 	int len;
375 
376 	len = sym_name_max_len + DISAS_INSN_OFFSET_SPACE;
377 	if (depth < 0) {
378 		len += depth;
379 		depth = 0;
380 	}
381 
382 	n = 0;
383 
384 	if (sec) {
385 		addr_str = offstr(sec, offset);
386 		n += fprintf(stream, "%6lx:  %-*s  ", offset, len, addr_str);
387 		free((char *)addr_str);
388 	} else {
389 		len += DISAS_INSN_OFFSET_SPACE + 1;
390 		n += fprintf(stream, "%-*s", len, "");
391 	}
392 
393 	/* print vertical bars to show the code flow */
394 	for (i = 0; i < depth; i++)
395 		n += fprintf(stream, "| ");
396 
397 	if (format)
398 		n += vfprintf(stream, format, ap);
399 
400 	return n;
401 }
402 
403 static int disas_print(FILE *stream, struct section *sec, unsigned long offset,
404 			int depth, const char *format, ...)
405 {
406 	va_list args;
407 	int len;
408 
409 	va_start(args, format);
410 	len = disas_vprint(stream, sec, offset, depth, format, args);
411 	va_end(args);
412 
413 	return len;
414 }
415 
416 /*
417  * Print a message in the instruction flow. If insn is not NULL then
418  * the instruction address is printed in addition of the message,
419  * otherwise only the message is printed. In all cases, the instruction
420  * itself is not printed.
421  */
422 void disas_print_info(FILE *stream, struct instruction *insn, int depth,
423 		      const char *format, ...)
424 {
425 	struct section *sec;
426 	unsigned long off;
427 	va_list args;
428 
429 	if (insn) {
430 		sec = insn->sec;
431 		off = insn->offset;
432 	} else {
433 		sec = NULL;
434 		off = 0;
435 	}
436 
437 	va_start(args, format);
438 	disas_vprint(stream, sec, off, depth, format, args);
439 	va_end(args);
440 }
441 
442 /*
443  * Print an instruction address (offset and function), the instruction itself
444  * and an optional message.
445  */
446 void disas_print_insn(FILE *stream, struct disas_context *dctx,
447 		      struct instruction *insn, int depth,
448 		      const char *format, ...)
449 {
450 	char fake_nop_insn[32];
451 	const char *insn_str;
452 	bool fake_nop;
453 	va_list args;
454 	int len;
455 
456 	/*
457 	 * Alternative can insert a fake nop, sometimes with no
458 	 * associated section so nothing to disassemble.
459 	 */
460 	fake_nop = (!insn->sec && insn->type == INSN_NOP);
461 	if (fake_nop) {
462 		snprintf(fake_nop_insn, 32, "<fake nop> (%d bytes)", insn->len);
463 		insn_str = fake_nop_insn;
464 	} else {
465 		disas_insn(dctx, insn);
466 		insn_str = disas_result(dctx);
467 	}
468 
469 	/* print the instruction */
470 	len = (depth + 1) * 2 < DISAS_INSN_SPACE ? DISAS_INSN_SPACE - (depth+1) * 2 : 1;
471 	disas_print_info(stream, insn, depth, "%-*s", len, insn_str);
472 
473 	/* print message if any */
474 	if (!format)
475 		return;
476 
477 	if (strcmp(format, "\n") == 0) {
478 		fprintf(stream, "\n");
479 		return;
480 	}
481 
482 	fprintf(stream, " - ");
483 	va_start(args, format);
484 	vfprintf(stream, format, args);
485 	va_end(args);
486 }
487 
488 /*
489  * Disassemble a single instruction. Return the size of the instruction.
490  */
491 size_t disas_insn(struct disas_context *dctx, struct instruction *insn)
492 {
493 	disassembler_ftype disasm = dctx->disassembler;
494 	struct disassemble_info *dinfo = &dctx->info;
495 
496 	dctx->insn = insn;
497 	dctx->result[0] = '\0';
498 
499 	if (insn->type == INSN_NOP) {
500 		DINFO_FPRINTF(dinfo, "nop%d", insn->len);
501 		return insn->len;
502 	}
503 
504 	/*
505 	 * Set the disassembler buffer to read data from the section
506 	 * containing the instruction to disassemble.
507 	 */
508 	dinfo->buffer = insn->sec->data->d_buf;
509 	dinfo->buffer_vma = 0;
510 	dinfo->buffer_length = insn->sec->sh.sh_size;
511 
512 	return disasm(insn->offset, &dctx->info);
513 }
514 
515 static struct instruction *next_insn_same_alt(struct objtool_file *file,
516 					      struct alt_group *alt_grp,
517 					      struct instruction *insn)
518 {
519 	if (alt_grp->last_insn == insn || alt_grp->nop == insn)
520 		return NULL;
521 
522 	return next_insn_same_sec(file, insn);
523 }
524 
525 #define alt_for_each_insn(file, alt_grp, insn)			\
526 	for (insn = alt_grp->first_insn; 			\
527 	     insn;						\
528 	     insn = next_insn_same_alt(file, alt_grp, insn))
529 
530 /*
531  * Provide a name for the type of alternatives present at the
532  * specified instruction.
533  *
534  * An instruction can have alternatives with different types, for
535  * example alternative instructions and an exception table. In that
536  * case the name for the alternative instructions type is used.
537  *
538  * Return NULL if the instruction as no alternative.
539  */
540 const char *disas_alt_type_name(struct instruction *insn)
541 {
542 	struct alternative *alt;
543 	const char *name;
544 
545 	name = NULL;
546 	for (alt = insn->alts; alt; alt = alt->next) {
547 		if (alt->type == ALT_TYPE_INSTRUCTIONS) {
548 			name = "alternative";
549 			break;
550 		}
551 
552 		switch (alt->type) {
553 		case ALT_TYPE_EX_TABLE:
554 			name = "ex_table";
555 			break;
556 		case ALT_TYPE_JUMP_TABLE:
557 			name = "jump_table";
558 			break;
559 		default:
560 			name = "unknown";
561 			break;
562 		}
563 	}
564 
565 	return name;
566 }
567 
568 /*
569  * Provide a name for an alternative.
570  */
571 char *disas_alt_name(struct alternative *alt)
572 {
573 	char *str = NULL;
574 
575 	switch (alt->type) {
576 
577 	case ALT_TYPE_EX_TABLE:
578 		str = strdup("EXCEPTION");
579 		break;
580 
581 	case ALT_TYPE_JUMP_TABLE:
582 		str = strdup("JUMP");
583 		break;
584 
585 	case ALT_TYPE_INSTRUCTIONS:
586 		/*
587 		 * This is a non-default group alternative. Create a unique
588 		 * name using the offset of the first original and alternative
589 		 * instructions.
590 		 */
591 		asprintf(&str, "ALTERNATIVE %lx.%lx",
592 			 alt->insn->alt_group->orig_group->first_insn->offset,
593 			 alt->insn->alt_group->first_insn->offset);
594 		break;
595 	}
596 
597 	return str;
598 }
599 
600 /*
601  * Initialize an alternative. The default alternative should be initialized
602  * with alt=NULL.
603  */
604 static int disas_alt_init(struct disas_alt *dalt,
605 			  struct instruction *orig_insn,
606 			  struct alternative *alt)
607 {
608 	dalt->orig_insn = orig_insn;
609 	dalt->alt = alt;
610 	dalt->name = alt ? disas_alt_name(alt) : strdup("DEFAULT");
611 	if (!dalt->name)
612 		return -1;
613 	dalt->width = strlen(dalt->name);
614 
615 	return 0;
616 }
617 
618 static int disas_alt_add_insn(struct disas_alt *dalt, int index, char *insn_str)
619 {
620 	int len;
621 
622 	if (index >= DISAS_ALT_INSN_MAX) {
623 		WARN("Alternative %lx.%s has more instructions than supported",
624 		     DALT_ALTID(dalt), dalt->name);
625 		return -1;
626 	}
627 
628 	len = strlen(insn_str);
629 	dalt->insn[index] = insn_str;
630 	if (len > dalt->width)
631 		dalt->width = len;
632 
633 	return 0;
634 }
635 
636 /*
637  * Disassemble an alternative and store instructions in the disas_alt
638  * structure. Return the number of instructions in the alternative.
639  */
640 static int disas_alt_group(struct disas_context *dctx, struct disas_alt *dalt)
641 {
642 	struct objtool_file *file;
643 	struct instruction *insn;
644 	char *str;
645 	int count;
646 	int err;
647 
648 	file = dctx->file;
649 	count = 0;
650 
651 	alt_for_each_insn(file, DALT_GROUP(dalt), insn) {
652 
653 		disas_insn(dctx, insn);
654 		str = strdup(disas_result(dctx));
655 		if (!str)
656 			return -1;
657 
658 		err = disas_alt_add_insn(dalt, count, str);
659 		if (err)
660 			break;
661 		count++;
662 	}
663 
664 	return count;
665 }
666 
667 /*
668  * Disassemble the default alternative.
669  */
670 static int disas_alt_default(struct disas_context *dctx, struct disas_alt *dalt)
671 {
672 	char *str;
673 	int err;
674 
675 	if (DALT_GROUP(dalt))
676 		return disas_alt_group(dctx, dalt);
677 
678 	/*
679 	 * Default alternative with no alt_group: this is the default
680 	 * code associated with either a jump table or an exception
681 	 * table and no other instruction alternatives. In that case
682 	 * the default alternative is made of a single instruction.
683 	 */
684 	disas_insn(dctx, dalt->orig_insn);
685 	str = strdup(disas_result(dctx));
686 	if (!str)
687 		return -1;
688 	err = disas_alt_add_insn(dalt, 0, str);
689 	if (err)
690 		return -1;
691 
692 	return 1;
693 }
694 
695 /*
696  * Print all alternatives one above the other.
697  */
698 static void disas_alt_print_compact(char *alt_name, struct disas_alt *dalts,
699 				    int alt_count, int insn_count)
700 {
701 	struct instruction *orig_insn;
702 	int i, j;
703 	int len;
704 
705 	orig_insn = dalts[0].orig_insn;
706 
707 	len = disas_print(stdout, orig_insn->sec, orig_insn->offset, 0, NULL);
708 	printf("%s\n", alt_name);
709 
710 	for (i = 0; i < alt_count; i++) {
711 		printf("%*s= %s\n", len, "", dalts[i].name);
712 		for (j = 0; j < insn_count; j++) {
713 			if (!dalts[i].insn[j])
714 				break;
715 			printf("%*s| %s\n", len, "", dalts[i].insn[j]);
716 		}
717 		printf("%*s|\n", len, "");
718 	}
719 }
720 
721 /*
722  * Disassemble an alternative.
723  *
724  * Return the last instruction in the default alternative so that
725  * disassembly can continue with the next instruction. Return NULL
726  * on error.
727  */
728 static void *disas_alt(struct disas_context *dctx,
729 		       struct instruction *orig_insn)
730 {
731 	struct disas_alt dalts[DISAS_ALT_MAX] = { 0 };
732 	struct instruction *last_insn = NULL;
733 	struct alternative *alt;
734 	struct disas_alt *dalt;
735 	int insn_count = 0;
736 	int alt_count = 0;
737 	char *alt_name;
738 	int count;
739 	int i, j;
740 	int err;
741 
742 	alt_name = strfmt("<%s.%lx>", disas_alt_type_name(orig_insn),
743 			  orig_insn->offset);
744 	if (!alt_name) {
745 		WARN("Failed to define name for alternative at instruction 0x%lx",
746 		     orig_insn->offset);
747 		goto done;
748 	}
749 
750 	/*
751 	 * Initialize and disassemble the default alternative.
752 	 */
753 	err = disas_alt_init(&dalts[0], orig_insn, NULL);
754 	if (err) {
755 		WARN("%s: failed to initialize default alternative", alt_name);
756 		goto done;
757 	}
758 
759 	insn_count = disas_alt_default(dctx, &dalts[0]);
760 	if (insn_count < 0) {
761 		WARN("%s: failed to disassemble default alternative", alt_name);
762 		goto done;
763 	}
764 
765 	/*
766 	 * Initialize and disassemble all other alternatives.
767 	 */
768 	i = 1;
769 	for (alt = orig_insn->alts; alt; alt = alt->next) {
770 		if (i >= DISAS_ALT_MAX) {
771 			WARN("%s has more alternatives than supported", alt_name);
772 			break;
773 		}
774 		dalt = &dalts[i];
775 		err = disas_alt_init(dalt, orig_insn, alt);
776 		if (err) {
777 			WARN("%s: failed to disassemble alternative", alt_name);
778 			goto done;
779 		}
780 
781 		/*
782 		 * Only group alternatives are supported at the moment.
783 		 */
784 		switch (dalt->alt->type) {
785 		case ALT_TYPE_INSTRUCTIONS:
786 			count = disas_alt_group(dctx, dalt);
787 			break;
788 		default:
789 			count = 0;
790 		}
791 		if (count < 0) {
792 			WARN("%s: failed to disassemble alternative %s",
793 			     alt_name, dalt->name);
794 			goto done;
795 		}
796 
797 		insn_count = count > insn_count ? count : insn_count;
798 		i++;
799 	}
800 	alt_count = i;
801 
802 	/*
803 	 * Print default and non-default alternatives.
804 	 */
805 	disas_alt_print_compact(alt_name, dalts, alt_count, insn_count);
806 
807 	last_insn = orig_insn->alt_group ? orig_insn->alt_group->last_insn :
808 		orig_insn;
809 
810 done:
811 	for (i = 0; i < alt_count; i++) {
812 		free(dalts[i].name);
813 		for (j = 0; j < insn_count; j++)
814 			free(dalts[i].insn[j]);
815 	}
816 
817 	free(alt_name);
818 
819 	return last_insn;
820 }
821 
822 /*
823  * Disassemble a function.
824  */
825 static void disas_func(struct disas_context *dctx, struct symbol *func)
826 {
827 	struct instruction *insn_start;
828 	struct instruction *insn;
829 
830 	printf("%s:\n", func->name);
831 	sym_for_each_insn(dctx->file, func, insn) {
832 		if (insn->alts) {
833 			insn_start = insn;
834 			insn = disas_alt(dctx, insn);
835 			if (insn)
836 				continue;
837 			/*
838 			 * There was an error with disassembling
839 			 * the alternative. Resume disassembling
840 			 * at the current instruction, this will
841 			 * disassemble the default alternative
842 			 * only and continue with the code after
843 			 * the alternative.
844 			 */
845 			insn = insn_start;
846 		}
847 
848 		DISAS_PRINSN(dctx, insn, 0);
849 	}
850 	printf("\n");
851 }
852 
853 /*
854  * Disassemble all warned functions.
855  */
856 void disas_warned_funcs(struct disas_context *dctx)
857 {
858 	struct symbol *sym;
859 
860 	if (!dctx)
861 		return;
862 
863 	for_each_sym(dctx->file->elf, sym) {
864 		if (sym->warned)
865 			disas_func(dctx, sym);
866 	}
867 }
868 
869 void disas_funcs(struct disas_context *dctx)
870 {
871 	bool disas_all = !strcmp(opts.disas, "*");
872 	struct section *sec;
873 	struct symbol *sym;
874 
875 	for_each_sec(dctx->file->elf, sec) {
876 
877 		if (!(sec->sh.sh_flags & SHF_EXECINSTR))
878 			continue;
879 
880 		sec_for_each_sym(sec, sym) {
881 			/*
882 			 * If the function had a warning and the verbose
883 			 * option is used then the function was already
884 			 * disassemble.
885 			 */
886 			if (opts.verbose && sym->warned)
887 				continue;
888 
889 			if (disas_all || fnmatch(opts.disas, sym->name, 0) == 0)
890 				disas_func(dctx, sym);
891 		}
892 	}
893 }
894