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