Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/tools/hsdis/hsdis.c
32285 views
/*1* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* The Universal Permissive License (UPL), Version 1.05*6* Subject to the condition set forth below, permission is hereby granted to7* any person obtaining a copy of this software, associated documentation8* and/or data (collectively the "Software"), free of charge and under any9* and all copyright rights in the Software, and any and all patent rights10* owned or freely licensable by each licensor hereunder covering either (i)11* the unmodified Software as contributed to or provided by such licensor,12* or (ii) the Larger Works (as defined below), to deal in both13*14* (a) the Software, and15*16* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file17* if one is included with the Software (each a "Larger Work" to which the18* Software is contributed by such licensors),19*20* without restriction, including without limitation the rights to copy,21* create derivative works of, display, perform, and distribute the Software22* and make, use, sell, offer for sale, import, export, have made, and have23* sold the Software and the Larger Work(s), and to sublicense the foregoing24* rights on either these or other terms.25*26* This license is subject to the following condition:27*28* The above copyright notice and either this complete permission notice or29* at a minimum a reference to the UPL must be included in all copies or30* substantial portions of the Software.31*32* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS33* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF34* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN35* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,36* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR37* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE38* USE OR OTHER DEALINGS IN THE SOFTWARE.39*40* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA41* or visit www.oracle.com if you need additional information or have any42* questions.43*44*/4546/* hsdis.c -- dump a range of addresses as native instructions47This implements the plugin protocol required by the48HotSpot PrintAssembly option.49*/5051#include <config.h> /* required by bfd.h */52#include <errno.h>53#include <inttypes.h>54#include <string.h>5556#include <libiberty.h>57#include <bfd.h>58#include <bfdver.h>59#include <dis-asm.h>6061#include "hsdis.h"6263#ifndef bool64#define bool int65#define true 166#define false 067#endif /*bool*/6869/* short names for stuff in hsdis.h */70typedef decode_instructions_event_callback_ftype event_callback_t;71typedef decode_instructions_printf_callback_ftype printf_callback_t;7273/* disassemble_info.application_data object */74struct hsdis_app_data {75/* virtual address of data */76uintptr_t start_va, end_va;77/* the instructions to be decoded */78unsigned char* buffer;79uintptr_t length;80event_callback_t event_callback; void* event_stream;81printf_callback_t printf_callback; void* printf_stream;82bool losing;83bool do_newline;8485/* the architecture being disassembled */86const char* arch_name;87const bfd_arch_info_type* arch_info;8889/* the disassembler we are going to use: */90disassembler_ftype dfn;91struct disassemble_info dinfo; /* the actual struct! */9293char mach_option[64];94char insn_options[256];95};9697static void* decode(struct hsdis_app_data* app_data, const char* options);9899#define DECL_APP_DATA(dinfo) \100struct hsdis_app_data* app_data = (struct hsdis_app_data*) (dinfo)->application_data101102#define DECL_EVENT_CALLBACK(app_data) \103event_callback_t event_callback = (app_data)->event_callback; \104void* event_stream = (app_data)->event_stream105106#define DECL_PRINTF_CALLBACK(app_data) \107printf_callback_t printf_callback = (app_data)->printf_callback; \108void* printf_stream = (app_data)->printf_stream109110111static void print_help(struct hsdis_app_data* app_data,112const char* msg, const char* arg);113static void setup_app_data(struct hsdis_app_data* app_data,114const char* options);115static const char* format_insn_close(const char* close,116disassemble_info* dinfo,117char* buf, size_t bufsize);118119void*120#ifdef DLL_ENTRY121DLL_ENTRY122#endif123decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va,124unsigned char* buffer, uintptr_t length,125event_callback_t event_callback_arg, void* event_stream_arg,126printf_callback_t printf_callback_arg, void* printf_stream_arg,127const char* options, int newline) {128struct hsdis_app_data app_data;129memset(&app_data, 0, sizeof(app_data));130app_data.start_va = start_va;131app_data.end_va = end_va;132app_data.buffer = buffer;133app_data.length = length;134app_data.event_callback = event_callback_arg;135app_data.event_stream = event_stream_arg;136app_data.printf_callback = printf_callback_arg;137app_data.printf_stream = printf_stream_arg;138app_data.do_newline = newline == 0 ? false : true;139140return decode(&app_data, options);141}142143/* This is the compatability interface for older version of hotspot */144void*145#ifdef DLL_ENTRY146DLL_ENTRY147#endif148decode_instructions(void* start_pv, void* end_pv,149event_callback_t event_callback_arg, void* event_stream_arg,150printf_callback_t printf_callback_arg, void* printf_stream_arg,151const char* options) {152return decode_instructions_virtual((uintptr_t)start_pv,153(uintptr_t)end_pv,154(unsigned char*)start_pv,155(uintptr_t)end_pv - (uintptr_t)start_pv,156event_callback_arg,157event_stream_arg,158printf_callback_arg,159printf_stream_arg,160options, false);161}162163static void* decode(struct hsdis_app_data* app_data, const char* options) {164setup_app_data(app_data, options);165char buf[128];166167{168/* now reload everything from app_data: */169DECL_EVENT_CALLBACK(app_data);170DECL_PRINTF_CALLBACK(app_data);171uintptr_t start = app_data->start_va;172uintptr_t end = app_data->end_va;173uintptr_t p = start;174175(*event_callback)(event_stream, "insns", (void*)start);176177(*event_callback)(event_stream, "mach name='%s'",178(void*) app_data->arch_info->printable_name);179if (app_data->dinfo.bytes_per_line != 0) {180(*event_callback)(event_stream, "format bytes-per-line='%p'/",181(void*)(intptr_t) app_data->dinfo.bytes_per_line);182}183184while (p < end && !app_data->losing) {185(*event_callback)(event_stream, "insn", (void*) p);186187/* reset certain state, so we can read it with confidence */188app_data->dinfo.insn_info_valid = 0;189app_data->dinfo.branch_delay_insns = 0;190app_data->dinfo.data_size = 0;191app_data->dinfo.insn_type = 0;192193int size = (*app_data->dfn)((bfd_vma) p, &app_data->dinfo);194195if (size > 0) p += size;196else app_data->losing = true;197198if (!app_data->losing) {199const char* insn_close = format_insn_close("/insn", &app_data->dinfo,200buf, sizeof(buf));201(*event_callback)(event_stream, insn_close, (void*) p);202203if (app_data->do_newline) {204/* follow each complete insn by a nice newline */205(*printf_callback)(printf_stream, "\n");206}207}208}209210if (app_data->losing) (*event_callback)(event_stream, "/insns", (void*) p);211return (void*) p;212}213}214215/* take the address of the function, for luck, and also test the typedef: */216const decode_func_vtype decode_func_virtual_address = &decode_instructions_virtual;217const decode_func_stype decode_func_address = &decode_instructions;218219static const char* format_insn_close(const char* close,220disassemble_info* dinfo,221char* buf, size_t bufsize) {222if (!dinfo->insn_info_valid)223return close;224enum dis_insn_type itype = dinfo->insn_type;225int dsize = dinfo->data_size, delays = dinfo->branch_delay_insns;226if ((itype == dis_nonbranch && (dsize | delays) == 0)227|| (strlen(close) + 3*20 > bufsize))228return close;229230const char* type = "unknown";231switch (itype) {232case dis_nonbranch: type = NULL; break;233case dis_branch: type = "branch"; break;234case dis_condbranch: type = "condbranch"; break;235case dis_jsr: type = "jsr"; break;236case dis_condjsr: type = "condjsr"; break;237case dis_dref: type = "dref"; break;238case dis_dref2: type = "dref2"; break;239case dis_noninsn: type = "noninsn"; break;240}241242strcpy(buf, close);243char* p = buf;244if (type) sprintf(p += strlen(p), " type='%s'", type);245if (dsize) sprintf(p += strlen(p), " dsize='%d'", dsize);246if (delays) sprintf(p += strlen(p), " delay='%d'", delays);247return buf;248}249250/* handler functions */251252static int253hsdis_read_memory_func(bfd_vma memaddr,254bfd_byte* myaddr,255unsigned int length,256struct disassemble_info* dinfo) {257DECL_APP_DATA(dinfo);258/* convert the virtual address memaddr into an address within memory buffer */259uintptr_t offset = ((uintptr_t) memaddr) - app_data->start_va;260if (offset + length > app_data->length) {261/* read is out of bounds */262return EIO;263} else {264memcpy(myaddr, (bfd_byte*) (app_data->buffer + offset), length);265return 0;266}267}268269static void270hsdis_print_address_func(bfd_vma vma, struct disassemble_info* dinfo) {271/* the actual value to print: */272void* addr_value = (void*) (uintptr_t) vma;273DECL_APP_DATA(dinfo);274DECL_EVENT_CALLBACK(app_data);275276/* issue the event: */277void* result =278(*event_callback)(event_stream, "addr/", addr_value);279if (result == NULL) {280/* event declined */281generic_print_address(vma, dinfo);282}283}284285286/* configuration */287288static void set_optional_callbacks(struct hsdis_app_data* app_data);289static void parse_caller_options(struct hsdis_app_data* app_data,290const char* caller_options);291static const char* native_arch_name();292static enum bfd_endian native_endian();293static const bfd_arch_info_type* find_arch_info(const char* arch_nane);294static bfd* get_native_bfd(const bfd_arch_info_type* arch_info,295/* to avoid malloc: */296bfd* empty_bfd, bfd_target* empty_xvec);297static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo,298void *stream,299fprintf_ftype fprintf_func,300bfd* bfd,301char* disassembler_options);302static void parse_fake_insn(disassembler_ftype dfn,303struct disassemble_info* dinfo);304305static void setup_app_data(struct hsdis_app_data* app_data,306const char* caller_options) {307/* Make reasonable defaults for null callbacks.308A non-null stream for a null callback is assumed to be a FILE* for output.309Events are rendered as XML.310*/311set_optional_callbacks(app_data);312313/* Look into caller_options for anything interesting. */314if (caller_options != NULL)315parse_caller_options(app_data, caller_options);316317/* Discover which architecture we are going to disassemble. */318app_data->arch_name = &app_data->mach_option[0];319if (app_data->arch_name[0] == '\0')320app_data->arch_name = native_arch_name();321app_data->arch_info = find_arch_info(app_data->arch_name);322323/* Make a fake bfd to hold the arch. and byteorder info. */324struct {325bfd_target empty_xvec;326bfd empty_bfd;327} buf;328bfd* native_bfd = get_native_bfd(app_data->arch_info,329/* to avoid malloc: */330&buf.empty_bfd, &buf.empty_xvec);331init_disassemble_info_from_bfd(&app_data->dinfo,332app_data->printf_stream,333app_data->printf_callback,334native_bfd,335/* On PowerPC we get warnings, if we pass empty options */336(caller_options == NULL) ? NULL : app_data->insn_options);337338/* Finish linking together the various callback blocks. */339app_data->dinfo.application_data = (void*) app_data;340app_data->dfn = disassembler(bfd_get_arch(native_bfd),341bfd_big_endian(native_bfd),342bfd_get_mach(native_bfd),343native_bfd);344app_data->dinfo.print_address_func = hsdis_print_address_func;345app_data->dinfo.read_memory_func = hsdis_read_memory_func;346347if (app_data->dfn == NULL) {348const char* bad = app_data->arch_name;349static bool complained;350if (bad == &app_data->mach_option[0])351print_help(app_data, "bad mach=%s", bad);352else if (!complained)353print_help(app_data, "bad native mach=%s; please port hsdis to this platform", bad);354complained = true;355/* must bail out */356app_data->losing = true;357return;358}359360parse_fake_insn(app_data->dfn, &app_data->dinfo);361}362363364/* ignore all events, return a null */365static void* null_event_callback(void* ignore_stream, const char* ignore_event, void* arg) {366return NULL;367}368369/* print all events as XML markup */370static void* xml_event_callback(void* stream, const char* event, void* arg) {371FILE* fp = (FILE*) stream;372#define NS_PFX "dis:"373if (event[0] != '/') {374/* issue the tag, with or without a formatted argument */375fprintf(fp, "<"NS_PFX);376fprintf(fp, event, arg);377fprintf(fp, ">");378} else {379++event; /* skip slash */380const char* argp = strchr(event, ' ');381if (argp == NULL) {382/* no arguments; just issue the closing tag */383fprintf(fp, "</"NS_PFX"%s>", event);384} else {385/* split out the closing attributes as <dis:foo_done attr='val'/> */386int event_prefix = (argp - event);387fprintf(fp, "<"NS_PFX"%.*s_done", event_prefix, event);388fprintf(fp, argp, arg);389fprintf(fp, "/></"NS_PFX"%.*s>", event_prefix, event);390}391}392return NULL;393}394395static void set_optional_callbacks(struct hsdis_app_data* app_data) {396if (app_data->printf_callback == NULL) {397int (*fprintf_callback)(FILE*, const char*, ...) = &fprintf;398FILE* fprintf_stream = stdout;399app_data->printf_callback = (printf_callback_t) fprintf_callback;400if (app_data->printf_stream == NULL)401app_data->printf_stream = (void*) fprintf_stream;402}403if (app_data->event_callback == NULL) {404if (app_data->event_stream == NULL)405app_data->event_callback = &null_event_callback;406else407app_data->event_callback = &xml_event_callback;408}409410}411412static void parse_caller_options(struct hsdis_app_data* app_data, const char* caller_options) {413char* iop_base = app_data->insn_options;414char* iop_limit = iop_base + sizeof(app_data->insn_options) - 1;415char* iop = iop_base;416const char* p;417for (p = caller_options; p != NULL; ) {418const char* q = strchr(p, ',');419size_t plen = (q == NULL) ? strlen(p) : ((q++) - p);420if (plen == 4 && strncmp(p, "help", plen) == 0) {421print_help(app_data, NULL, NULL);422} else if (plen >= 5 && strncmp(p, "mach=", 5) == 0) {423char* mach_option = app_data->mach_option;424size_t mach_size = sizeof(app_data->mach_option);425mach_size -= 1; /*leave room for the null*/426if (plen > mach_size) plen = mach_size;427strncpy(mach_option, p, plen);428mach_option[plen] = '\0';429} else if (plen > 6 && strncmp(p, "hsdis-", 6) == 0) {430// do not pass these to the next level431} else {432/* just copy it; {i386,sparc}-dis.c might like to see it */433if (iop > iop_base && iop < iop_limit) (*iop++) = ',';434if (iop + plen > iop_limit)435plen = iop_limit - iop;436strncpy(iop, p, plen);437iop += plen;438}439p = q;440}441*iop = '\0';442}443444static void print_help(struct hsdis_app_data* app_data,445const char* msg, const char* arg) {446DECL_PRINTF_CALLBACK(app_data);447if (msg != NULL) {448(*printf_callback)(printf_stream, "hsdis: ");449(*printf_callback)(printf_stream, msg, arg);450(*printf_callback)(printf_stream, "\n");451}452(*printf_callback)(printf_stream, "hsdis output options:\n");453if (printf_callback == (printf_callback_t) &fprintf)454disassembler_usage((FILE*) printf_stream);455else456disassembler_usage(stderr); /* better than nothing */457(*printf_callback)(printf_stream, " mach=<arch> select disassembly mode\n");458#if defined(LIBARCH_i386) || defined(LIBARCH_amd64)459(*printf_callback)(printf_stream, " mach=i386 select 32-bit mode\n");460(*printf_callback)(printf_stream, " mach=x86-64 select 64-bit mode\n");461(*printf_callback)(printf_stream, " suffix always print instruction suffix\n");462#endif463(*printf_callback)(printf_stream, " help print this message\n");464}465466467/* low-level bfd and arch stuff that binutils doesn't do for us */468469static const bfd_arch_info_type* find_arch_info(const char* arch_name) {470const bfd_arch_info_type* arch_info = bfd_scan_arch(arch_name);471if (arch_info == NULL) {472extern const bfd_arch_info_type bfd_default_arch_struct;473arch_info = &bfd_default_arch_struct;474}475return arch_info;476}477478static const char* native_arch_name() {479const char* res = NULL;480#ifdef LIBARCH_i386481res = "i386";482#endif483#ifdef LIBARCH_amd64484res = "i386:x86-64";485#endif486#ifdef LIBARCH_sparc487res = "sparc:v8plusb";488#endif489#ifdef LIBARCH_sparcv9490res = "sparc:v9b";491#endif492#if defined(LIBARCH_ppc64) || defined(LIBARCH_ppc64le)493res = "powerpc:common64";494#endif495#ifdef LIBARCH_aarch64496res = "aarch64";497#endif498if (res == NULL)499res = "architecture not set in Makefile!";500return res;501}502503static enum bfd_endian native_endian() {504int32_t endian_test = 'x';505if (*(const char*) &endian_test == 'x')506return BFD_ENDIAN_LITTLE;507else508return BFD_ENDIAN_BIG;509}510511static bfd* get_native_bfd(const bfd_arch_info_type* arch_info,512bfd* empty_bfd, bfd_target* empty_xvec) {513memset(empty_bfd, 0, sizeof(*empty_bfd));514memset(empty_xvec, 0, sizeof(*empty_xvec));515empty_xvec->flavour = bfd_target_unknown_flavour;516empty_xvec->byteorder = native_endian();517empty_bfd->xvec = empty_xvec;518empty_bfd->arch_info = arch_info;519return empty_bfd;520}521522static int read_zero_data_only(bfd_vma ignore_p,523bfd_byte* myaddr, unsigned int length,524struct disassemble_info *ignore_info) {525memset(myaddr, 0, length);526return 0;527}528static int print_to_dev_null(void* ignore_stream, const char* ignore_format, ...) {529return 0;530}531532/* Prime the pump by running the selected disassembler on a null input.533This forces the machine-specific disassembler to divulge invariant534information like bytes_per_line.535*/536static void parse_fake_insn(disassembler_ftype dfn,537struct disassemble_info* dinfo) {538typedef int (*read_memory_ftype)539(bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,540struct disassemble_info *info);541read_memory_ftype read_memory_func = dinfo->read_memory_func;542fprintf_ftype fprintf_func = dinfo->fprintf_func;543544dinfo->read_memory_func = &read_zero_data_only;545dinfo->fprintf_func = &print_to_dev_null;546(*dfn)(0, dinfo);547548/* put it back */549dinfo->read_memory_func = read_memory_func;550dinfo->fprintf_func = fprintf_func;551}552553static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo,554void *stream,555fprintf_ftype fprintf_func,556bfd* abfd,557char* disassembler_options) {558init_disassemble_info(dinfo, stream, fprintf_func);559560dinfo->flavour = bfd_get_flavour(abfd);561dinfo->arch = bfd_get_arch(abfd);562dinfo->mach = bfd_get_mach(abfd);563dinfo->disassembler_options = disassembler_options;564dinfo->octets_per_byte = bfd_octets_per_byte (abfd);565dinfo->skip_zeroes = sizeof(void*) * 2;566dinfo->skip_zeroes_at_end = sizeof(void*)-1;567dinfo->disassembler_needs_relocs = FALSE;568569if (bfd_big_endian(abfd))570dinfo->display_endian = dinfo->endian = BFD_ENDIAN_BIG;571else if (bfd_little_endian(abfd))572dinfo->display_endian = dinfo->endian = BFD_ENDIAN_LITTLE;573else574dinfo->endian = native_endian();575576disassemble_init_for_target(dinfo);577}578579580