1*1545Seschrock /* 2*1545Seschrock * CDDL HEADER START 3*1545Seschrock * 4*1545Seschrock * The contents of this file are subject to the terms of the 5*1545Seschrock * Common Development and Distribution License (the "License"). 6*1545Seschrock * You may not use this file except in compliance with the License. 7*1545Seschrock * 8*1545Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1545Seschrock * or http://www.opensolaris.org/os/licensing. 10*1545Seschrock * See the License for the specific language governing permissions 11*1545Seschrock * and limitations under the License. 12*1545Seschrock * 13*1545Seschrock * When distributing Covered Code, include this CDDL HEADER in each 14*1545Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1545Seschrock * If applicable, add the following below this CDDL HEADER, with the 16*1545Seschrock * fields enclosed by brackets "[]" replaced with your own identifying 17*1545Seschrock * information: Portions Copyright [yyyy] [name of copyright owner] 18*1545Seschrock * 19*1545Seschrock * CDDL HEADER END 20*1545Seschrock */ 21*1545Seschrock 22*1545Seschrock /* 23*1545Seschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*1545Seschrock * Use is subject to license terms. 25*1545Seschrock */ 26*1545Seschrock 27*1545Seschrock #pragma ident "%Z%%M% %I% %E% SMI" 28*1545Seschrock 29*1545Seschrock #include <libdisasm.h> 30*1545Seschrock #include <stdlib.h> 31*1545Seschrock #include <stdio.h> 32*1545Seschrock 33*1545Seschrock #include "dis_tables.h" 34*1545Seschrock #include "libdisasm_impl.h" 35*1545Seschrock 36*1545Seschrock struct dis_handle { 37*1545Seschrock void *dh_data; 38*1545Seschrock int dh_flags; 39*1545Seschrock dis_lookup_f dh_lookup; 40*1545Seschrock dis_read_f dh_read; 41*1545Seschrock int dh_mode; 42*1545Seschrock dis86_t dh_dis; 43*1545Seschrock uint64_t dh_addr; 44*1545Seschrock uint64_t dh_end; 45*1545Seschrock }; 46*1545Seschrock 47*1545Seschrock /* 48*1545Seschrock * Returns true if we are near the end of a function. This is a cheap hack at 49*1545Seschrock * detecting NULL padding between functions. If we're within a few bytes of the 50*1545Seschrock * next function, or past the start, then return true. 51*1545Seschrock */ 52*1545Seschrock static int 53*1545Seschrock check_func(void *data) 54*1545Seschrock { 55*1545Seschrock dis_handle_t *dhp = data; 56*1545Seschrock uint64_t start; 57*1545Seschrock size_t len; 58*1545Seschrock 59*1545Seschrock if (dhp->dh_lookup(dhp->dh_data, dhp->dh_addr, NULL, 0, &start, &len) 60*1545Seschrock != 0) 61*1545Seschrock return (0); 62*1545Seschrock 63*1545Seschrock if (start < dhp->dh_addr) 64*1545Seschrock return (dhp->dh_addr > start + len - 0x10); 65*1545Seschrock 66*1545Seschrock return (1); 67*1545Seschrock } 68*1545Seschrock 69*1545Seschrock static int 70*1545Seschrock get_byte(void *data) 71*1545Seschrock { 72*1545Seschrock uchar_t byte; 73*1545Seschrock dis_handle_t *dhp = data; 74*1545Seschrock 75*1545Seschrock if (dhp->dh_read(dhp->dh_data, dhp->dh_addr, &byte, 76*1545Seschrock sizeof (byte)) < sizeof (byte)) 77*1545Seschrock return (-1); 78*1545Seschrock 79*1545Seschrock dhp->dh_addr++; 80*1545Seschrock 81*1545Seschrock return ((int)byte); 82*1545Seschrock } 83*1545Seschrock 84*1545Seschrock static int 85*1545Seschrock do_lookup(void *data, uint64_t addr, char *buf, size_t buflen) 86*1545Seschrock { 87*1545Seschrock dis_handle_t *dhp = data; 88*1545Seschrock 89*1545Seschrock return (dhp->dh_lookup(dhp->dh_data, addr, buf, buflen, NULL, NULL)); 90*1545Seschrock } 91*1545Seschrock 92*1545Seschrock dis_handle_t * 93*1545Seschrock dis_handle_create(int flags, void *data, dis_lookup_f lookup_func, 94*1545Seschrock dis_read_f read_func) 95*1545Seschrock { 96*1545Seschrock dis_handle_t *dhp; 97*1545Seschrock 98*1545Seschrock /* 99*1545Seschrock * Validate architecture flags 100*1545Seschrock */ 101*1545Seschrock if (flags & ~(DIS_X86_SIZE16 | DIS_X86_SIZE32 | DIS_X86_SIZE64 | 102*1545Seschrock DIS_OCTAL)) { 103*1545Seschrock (void) dis_seterrno(E_DIS_INVALFLAG); 104*1545Seschrock return (NULL); 105*1545Seschrock } 106*1545Seschrock 107*1545Seschrock /* 108*1545Seschrock * Create and initialize the internal structure 109*1545Seschrock */ 110*1545Seschrock if ((dhp = dis_zalloc(sizeof (struct dis_handle))) == NULL) { 111*1545Seschrock (void) dis_seterrno(E_DIS_NOMEM); 112*1545Seschrock return (NULL); 113*1545Seschrock } 114*1545Seschrock 115*1545Seschrock dhp->dh_lookup = lookup_func; 116*1545Seschrock dhp->dh_read = read_func; 117*1545Seschrock dhp->dh_flags = flags; 118*1545Seschrock dhp->dh_data = data; 119*1545Seschrock 120*1545Seschrock /* 121*1545Seschrock * Initialize x86-specific architecture structure 122*1545Seschrock */ 123*1545Seschrock if (flags & DIS_X86_SIZE16) 124*1545Seschrock dhp->dh_mode = SIZE16; 125*1545Seschrock else if (flags & DIS_X86_SIZE64) 126*1545Seschrock dhp->dh_mode = SIZE64; 127*1545Seschrock else 128*1545Seschrock dhp->dh_mode = SIZE32; 129*1545Seschrock 130*1545Seschrock if (flags & DIS_OCTAL) 131*1545Seschrock dhp->dh_dis.d86_flags = DIS_OP_OCTAL; 132*1545Seschrock 133*1545Seschrock dhp->dh_dis.d86_sprintf_func = snprintf; 134*1545Seschrock dhp->dh_dis.d86_get_byte = get_byte; 135*1545Seschrock dhp->dh_dis.d86_sym_lookup = do_lookup; 136*1545Seschrock dhp->dh_dis.d86_check_func = check_func; 137*1545Seschrock 138*1545Seschrock dhp->dh_dis.d86_data = dhp; 139*1545Seschrock 140*1545Seschrock return (dhp); 141*1545Seschrock } 142*1545Seschrock 143*1545Seschrock int 144*1545Seschrock dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen) 145*1545Seschrock { 146*1545Seschrock dhp->dh_addr = addr; 147*1545Seschrock 148*1545Seschrock if (dtrace_disx86(&dhp->dh_dis, dhp->dh_mode) != 0) 149*1545Seschrock return (-1); 150*1545Seschrock 151*1545Seschrock if (buf != NULL) 152*1545Seschrock dtrace_disx86_str(&dhp->dh_dis, dhp->dh_mode, addr, buf, 153*1545Seschrock buflen); 154*1545Seschrock 155*1545Seschrock return (0); 156*1545Seschrock } 157*1545Seschrock 158*1545Seschrock void 159*1545Seschrock dis_handle_destroy(dis_handle_t *dhp) 160*1545Seschrock { 161*1545Seschrock dis_free(dhp, sizeof (dis_handle_t)); 162*1545Seschrock } 163*1545Seschrock 164*1545Seschrock void 165*1545Seschrock dis_set_data(dis_handle_t *dhp, void *data) 166*1545Seschrock { 167*1545Seschrock dhp->dh_data = data; 168*1545Seschrock } 169*1545Seschrock 170*1545Seschrock /* ARGSUSED */ 171*1545Seschrock int 172*1545Seschrock dis_max_instrlen(dis_handle_t *dhp) 173*1545Seschrock { 174*1545Seschrock return (15); 175*1545Seschrock } 176*1545Seschrock 177*1545Seschrock #define MIN(a, b) ((a) < (b) ? (a) : (b)) 178*1545Seschrock 179*1545Seschrock /* 180*1545Seschrock * Return the previous instruction. On x86, we have no choice except to 181*1545Seschrock * disassemble everything from the start of the symbol, and stop when we have 182*1545Seschrock * reached our instruction address. If we're not in the middle of a known 183*1545Seschrock * symbol, then we return the same address to indicate failure. 184*1545Seschrock */ 185*1545Seschrock uint64_t 186*1545Seschrock dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n) 187*1545Seschrock { 188*1545Seschrock uint64_t *hist, addr, start; 189*1545Seschrock int cur, nseen; 190*1545Seschrock uint64_t res = pc; 191*1545Seschrock 192*1545Seschrock if (dhp->dh_lookup(dhp->dh_data, pc, NULL, 0, &start, NULL) != 0 || 193*1545Seschrock start == pc) 194*1545Seschrock return (res); 195*1545Seschrock 196*1545Seschrock hist = dis_zalloc(sizeof (uint64_t) * n); 197*1545Seschrock 198*1545Seschrock for (cur = 0, nseen = 0, addr = start; addr < pc; addr = dhp->dh_addr) { 199*1545Seschrock hist[cur] = addr; 200*1545Seschrock cur = (cur + 1) % n; 201*1545Seschrock nseen++; 202*1545Seschrock 203*1545Seschrock /* if we cannot make forward progress, give up */ 204*1545Seschrock if (dis_disassemble(dhp, addr, NULL, 0) != 0) 205*1545Seschrock goto done; 206*1545Seschrock } 207*1545Seschrock 208*1545Seschrock if (addr != pc) { 209*1545Seschrock /* 210*1545Seschrock * We scanned past %pc, but didn't find an instruction that 211*1545Seschrock * started at %pc. This means that either the caller specified 212*1545Seschrock * an invalid address, or we ran into something other than code 213*1545Seschrock * during our scan. Virtually any combination of bytes can be 214*1545Seschrock * construed as a valid Intel instruction, so any non-code bytes 215*1545Seschrock * we encounter will have thrown off the scan. 216*1545Seschrock */ 217*1545Seschrock goto done; 218*1545Seschrock } 219*1545Seschrock 220*1545Seschrock res = hist[(cur + n - MIN(n, nseen)) % n]; 221*1545Seschrock 222*1545Seschrock done: 223*1545Seschrock dis_free(hist, sizeof (uint64_t) * n); 224*1545Seschrock return (res); 225*1545Seschrock } 226