Home | History | Annotate | Line # | Download | only in aarch64
      1 /* $NetBSD: db_disasm.c,v 1.12 2024/02/07 04:20:26 msaitoh Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2017 Ryo Shimizu
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: db_disasm.c,v 1.12 2024/02/07 04:20:26 msaitoh Exp $");
     31 
     32 #ifdef _KERNEL_OPT
     33 #include "opt_compat_netbsd32.h"
     34 #endif
     35 
     36 #include <sys/param.h>
     37 #include <machine/db_machdep.h>
     38 #include <ddb/db_interface.h>
     39 #include <ddb/db_sym.h>
     40 #include <ddb/db_output.h>
     41 #include <ddb/db_access.h>
     42 #include <ddb/db_user.h>
     43 
     44 #include <aarch64/machdep.h>
     45 #include <arch/aarch64/aarch64/disasm.h>
     46 
     47 #include <arm/cpufunc.h>
     48 
     49 static uint32_t
     50 db_disasm_readword(uintptr_t address)
     51 {
     52 	return db_get_value(address, sizeof(uint32_t), false);
     53 }
     54 
     55 static void
     56 db_disasm_printaddr(uintptr_t address)
     57 {
     58 	db_printf("%lx <", address);
     59 	db_printsym((db_addr_t)address, DB_STGY_ANY, db_printf);
     60 	db_printf(">");
     61 }
     62 
     63 static const disasm_interface_t db_disasm_interface = {
     64 	.di_readword = db_disasm_readword,
     65 	.di_printaddr = db_disasm_printaddr,
     66 	.di_printf = db_printf
     67 };
     68 
     69 db_addr_t
     70 db_disasm(db_addr_t loc, bool altfmt)
     71 {
     72 	return disasm(&db_disasm_interface, loc);
     73 }
     74 
     75 
     76 static char *strdisasm_ptr;
     77 static char strdisasm_buf[256];
     78 
     79 static uint32_t
     80 strdisasm_readword(uintptr_t address)
     81 {
     82 #ifdef _KERNEL
     83 	/*
     84 	 * if it cannot be read due to a EFAULT etc.,
     85 	 * ignores the error and returns 0
     86 	 */
     87 	uint32_t word = 0;
     88 
     89 	switch (aarch64_addressspace((vaddr_t)address)) {
     90 	case AARCH64_ADDRSPACE_UPPER:
     91 		kcopy((void*)address, &word, sizeof(word));
     92 		break;
     93 	case AARCH64_ADDRSPACE_LOWER:
     94 		ufetch_32((uint32_t *)address, &word);
     95 		break;
     96 	default:
     97 		break;
     98 	}
     99 
    100 	return word;
    101 #else
    102 	return *(uint32_t *)address;
    103 #endif
    104 }
    105 
    106 static void __printflike(1, 2)
    107 strdisasm_printf(const char *fmt, ...)
    108 {
    109 	va_list ap;
    110 	int len;
    111 
    112 	/* calculation spaces to append a string */
    113 	len = strdisasm_buf + sizeof(strdisasm_buf) - strdisasm_ptr;
    114 
    115 	va_start(ap, fmt);
    116 	len = vsnprintf(strdisasm_ptr, len, fmt, ap);
    117 	va_end(ap);
    118 
    119 	strdisasm_ptr += len;
    120 }
    121 
    122 static void
    123 strdisasm_printaddr(uintptr_t address)
    124 {
    125 	strdisasm_printf("0x%lx", address);
    126 }
    127 
    128 static const disasm_interface_t strdisasm_interface = {
    129 	.di_readword = strdisasm_readword,
    130 	.di_printaddr = strdisasm_printaddr,
    131 	.di_printf = strdisasm_printf
    132 };
    133 
    134 const char *
    135 strdisasm(vaddr_t pc, uint64_t spsr)
    136 {
    137 #ifdef COMPAT_NETBSD32
    138 	if (spsr & SPSR_A32) {
    139 		uint32_t insn = 0;
    140 		int size;
    141 		const char *arch = (spsr & SPSR_A32_T) ? "T32" : "A32";
    142 
    143 		size = fetch_arm_insn(pc, spsr, &insn);
    144 		if (size != 2)
    145 			size = 4;
    146 		snprintf(strdisasm_buf, sizeof(strdisasm_buf),
    147 		    ".insn 0x%0*x (%s)", size * 2, insn, arch);
    148 	} else
    149 #endif /* COMPAT_NETBSD32 */
    150 	{
    151 		char *p;
    152 
    153 		/* disasm an aarch64 instruction */
    154 		strdisasm_ptr = strdisasm_buf;
    155 		disasm(&strdisasm_interface, (db_addr_t)pc);
    156 
    157 		/* replace tab to space, and chomp '\n' */
    158 		for (p = strdisasm_buf; *p != '\0'; p++) {
    159 			if (*p == '\t')
    160 				*p = ' ';
    161 		}
    162 		if ((p > strdisasm_buf) && (p[-1] == '\n'))
    163 			p[-1] = '\0';
    164 	}
    165 
    166 	return strdisasm_buf;
    167 }
    168