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