11545Seschrock /* 21545Seschrock * CDDL HEADER START 31545Seschrock * 41545Seschrock * The contents of this file are subject to the terms of the 51545Seschrock * Common Development and Distribution License (the "License"). 61545Seschrock * You may not use this file except in compliance with the License. 71545Seschrock * 81545Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91545Seschrock * or http://www.opensolaris.org/os/licensing. 101545Seschrock * See the License for the specific language governing permissions 111545Seschrock * and limitations under the License. 121545Seschrock * 131545Seschrock * When distributing Covered Code, include this CDDL HEADER in each 141545Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151545Seschrock * If applicable, add the following below this CDDL HEADER, with the 161545Seschrock * fields enclosed by brackets "[]" replaced with your own identifying 171545Seschrock * information: Portions Copyright [yyyy] [name of copyright owner] 181545Seschrock * 191545Seschrock * CDDL HEADER END 201545Seschrock */ 211545Seschrock 221545Seschrock /* 231545Seschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 241545Seschrock * Use is subject to license terms. 251545Seschrock */ 261545Seschrock 271545Seschrock #pragma ident "%Z%%M% %I% %E% SMI" 281545Seschrock 291545Seschrock #include <libdisasm.h> 301545Seschrock #include <stdlib.h> 311545Seschrock #include <stdio.h> 321545Seschrock 331545Seschrock #include "dis_tables.h" 341545Seschrock #include "libdisasm_impl.h" 351545Seschrock 361545Seschrock struct dis_handle { 371545Seschrock void *dh_data; 381545Seschrock int dh_flags; 391545Seschrock dis_lookup_f dh_lookup; 401545Seschrock dis_read_f dh_read; 411545Seschrock int dh_mode; 421545Seschrock dis86_t dh_dis; 431545Seschrock uint64_t dh_addr; 441545Seschrock uint64_t dh_end; 451545Seschrock }; 461545Seschrock 471545Seschrock /* 481545Seschrock * Returns true if we are near the end of a function. This is a cheap hack at 491545Seschrock * detecting NULL padding between functions. If we're within a few bytes of the 501545Seschrock * next function, or past the start, then return true. 511545Seschrock */ 521545Seschrock static int 531545Seschrock check_func(void *data) 541545Seschrock { 551545Seschrock dis_handle_t *dhp = data; 561545Seschrock uint64_t start; 571545Seschrock size_t len; 581545Seschrock 591545Seschrock if (dhp->dh_lookup(dhp->dh_data, dhp->dh_addr, NULL, 0, &start, &len) 601545Seschrock != 0) 611545Seschrock return (0); 621545Seschrock 631545Seschrock if (start < dhp->dh_addr) 641545Seschrock return (dhp->dh_addr > start + len - 0x10); 651545Seschrock 661545Seschrock return (1); 671545Seschrock } 681545Seschrock 691545Seschrock static int 701545Seschrock get_byte(void *data) 711545Seschrock { 721545Seschrock uchar_t byte; 731545Seschrock dis_handle_t *dhp = data; 741545Seschrock 751545Seschrock if (dhp->dh_read(dhp->dh_data, dhp->dh_addr, &byte, 761545Seschrock sizeof (byte)) < sizeof (byte)) 771545Seschrock return (-1); 781545Seschrock 791545Seschrock dhp->dh_addr++; 801545Seschrock 811545Seschrock return ((int)byte); 821545Seschrock } 831545Seschrock 841545Seschrock static int 851545Seschrock do_lookup(void *data, uint64_t addr, char *buf, size_t buflen) 861545Seschrock { 871545Seschrock dis_handle_t *dhp = data; 881545Seschrock 891545Seschrock return (dhp->dh_lookup(dhp->dh_data, addr, buf, buflen, NULL, NULL)); 901545Seschrock } 911545Seschrock 921545Seschrock dis_handle_t * 931545Seschrock dis_handle_create(int flags, void *data, dis_lookup_f lookup_func, 941545Seschrock dis_read_f read_func) 951545Seschrock { 961545Seschrock dis_handle_t *dhp; 971545Seschrock 981545Seschrock /* 991545Seschrock * Validate architecture flags 1001545Seschrock */ 1011545Seschrock if (flags & ~(DIS_X86_SIZE16 | DIS_X86_SIZE32 | DIS_X86_SIZE64 | 1021545Seschrock DIS_OCTAL)) { 1031545Seschrock (void) dis_seterrno(E_DIS_INVALFLAG); 1041545Seschrock return (NULL); 1051545Seschrock } 1061545Seschrock 1071545Seschrock /* 1081545Seschrock * Create and initialize the internal structure 1091545Seschrock */ 1101545Seschrock if ((dhp = dis_zalloc(sizeof (struct dis_handle))) == NULL) { 1111545Seschrock (void) dis_seterrno(E_DIS_NOMEM); 1121545Seschrock return (NULL); 1131545Seschrock } 1141545Seschrock 1151545Seschrock dhp->dh_lookup = lookup_func; 1161545Seschrock dhp->dh_read = read_func; 1171545Seschrock dhp->dh_flags = flags; 1181545Seschrock dhp->dh_data = data; 1191545Seschrock 1201545Seschrock /* 1211545Seschrock * Initialize x86-specific architecture structure 1221545Seschrock */ 1231545Seschrock if (flags & DIS_X86_SIZE16) 1241545Seschrock dhp->dh_mode = SIZE16; 1251545Seschrock else if (flags & DIS_X86_SIZE64) 1261545Seschrock dhp->dh_mode = SIZE64; 1271545Seschrock else 1281545Seschrock dhp->dh_mode = SIZE32; 1291545Seschrock 1301545Seschrock if (flags & DIS_OCTAL) 1311545Seschrock dhp->dh_dis.d86_flags = DIS_OP_OCTAL; 1321545Seschrock 1331545Seschrock dhp->dh_dis.d86_sprintf_func = snprintf; 1341545Seschrock dhp->dh_dis.d86_get_byte = get_byte; 1351545Seschrock dhp->dh_dis.d86_sym_lookup = do_lookup; 1361545Seschrock dhp->dh_dis.d86_check_func = check_func; 1371545Seschrock 1381545Seschrock dhp->dh_dis.d86_data = dhp; 1391545Seschrock 1401545Seschrock return (dhp); 1411545Seschrock } 1421545Seschrock 1431545Seschrock int 1441545Seschrock dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen) 1451545Seschrock { 1461545Seschrock dhp->dh_addr = addr; 1471545Seschrock 1481545Seschrock if (dtrace_disx86(&dhp->dh_dis, dhp->dh_mode) != 0) 1491545Seschrock return (-1); 1501545Seschrock 1511545Seschrock if (buf != NULL) 1521545Seschrock dtrace_disx86_str(&dhp->dh_dis, dhp->dh_mode, addr, buf, 1531545Seschrock buflen); 1541545Seschrock 1551545Seschrock return (0); 1561545Seschrock } 1571545Seschrock 1581545Seschrock void 1591545Seschrock dis_handle_destroy(dis_handle_t *dhp) 1601545Seschrock { 1611545Seschrock dis_free(dhp, sizeof (dis_handle_t)); 1621545Seschrock } 1631545Seschrock 1641545Seschrock void 1651545Seschrock dis_set_data(dis_handle_t *dhp, void *data) 1661545Seschrock { 1671545Seschrock dhp->dh_data = data; 1681545Seschrock } 1691545Seschrock 1701545Seschrock /* ARGSUSED */ 1711545Seschrock int 1721545Seschrock dis_max_instrlen(dis_handle_t *dhp) 1731545Seschrock { 1741545Seschrock return (15); 1751545Seschrock } 1761545Seschrock 1771545Seschrock #define MIN(a, b) ((a) < (b) ? (a) : (b)) 1781545Seschrock 1791545Seschrock /* 1801545Seschrock * Return the previous instruction. On x86, we have no choice except to 1811545Seschrock * disassemble everything from the start of the symbol, and stop when we have 1821545Seschrock * reached our instruction address. If we're not in the middle of a known 1831545Seschrock * symbol, then we return the same address to indicate failure. 1841545Seschrock */ 1851545Seschrock uint64_t 1861545Seschrock dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n) 1871545Seschrock { 1881545Seschrock uint64_t *hist, addr, start; 1891545Seschrock int cur, nseen; 1901545Seschrock uint64_t res = pc; 1911545Seschrock 192*1586Seschrock if (n <= 0) 193*1586Seschrock return (pc); 194*1586Seschrock 1951545Seschrock if (dhp->dh_lookup(dhp->dh_data, pc, NULL, 0, &start, NULL) != 0 || 1961545Seschrock start == pc) 1971545Seschrock return (res); 1981545Seschrock 1991545Seschrock hist = dis_zalloc(sizeof (uint64_t) * n); 2001545Seschrock 2011545Seschrock for (cur = 0, nseen = 0, addr = start; addr < pc; addr = dhp->dh_addr) { 2021545Seschrock hist[cur] = addr; 2031545Seschrock cur = (cur + 1) % n; 2041545Seschrock nseen++; 2051545Seschrock 2061545Seschrock /* if we cannot make forward progress, give up */ 2071545Seschrock if (dis_disassemble(dhp, addr, NULL, 0) != 0) 2081545Seschrock goto done; 2091545Seschrock } 2101545Seschrock 2111545Seschrock if (addr != pc) { 2121545Seschrock /* 2131545Seschrock * We scanned past %pc, but didn't find an instruction that 2141545Seschrock * started at %pc. This means that either the caller specified 2151545Seschrock * an invalid address, or we ran into something other than code 2161545Seschrock * during our scan. Virtually any combination of bytes can be 2171545Seschrock * construed as a valid Intel instruction, so any non-code bytes 2181545Seschrock * we encounter will have thrown off the scan. 2191545Seschrock */ 2201545Seschrock goto done; 2211545Seschrock } 2221545Seschrock 2231545Seschrock res = hist[(cur + n - MIN(n, nseen)) % n]; 2241545Seschrock 2251545Seschrock done: 2261545Seschrock dis_free(hist, sizeof (uint64_t) * n); 2271545Seschrock return (res); 2281545Seschrock } 229