Path: blob/jdk8u272-b10-aarch32-20201026/hotspot/src/share/tools/hsdis/hsdis.c
83404 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) {152decode_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;239}240241strcpy(buf, close);242char* p = buf;243if (type) sprintf(p += strlen(p), " type='%s'", type);244if (dsize) sprintf(p += strlen(p), " dsize='%d'", dsize);245if (delays) sprintf(p += strlen(p), " delay='%d'", delays);246return buf;247}248249/* handler functions */250251static int252hsdis_read_memory_func(bfd_vma memaddr,253bfd_byte* myaddr,254unsigned int length,255struct disassemble_info* dinfo) {256DECL_APP_DATA(dinfo);257/* convert the virtual address memaddr into an address within memory buffer */258uintptr_t offset = ((uintptr_t) memaddr) - app_data->start_va;259if (offset + length > app_data->length) {260/* read is out of bounds */261return EIO;262} else {263memcpy(myaddr, (bfd_byte*) (app_data->buffer + offset), length);264return 0;265}266}267268static void269hsdis_print_address_func(bfd_vma vma, struct disassemble_info* dinfo) {270/* the actual value to print: */271void* addr_value = (void*) (uintptr_t) vma;272DECL_APP_DATA(dinfo);273DECL_EVENT_CALLBACK(app_data);274275/* issue the event: */276void* result =277(*event_callback)(event_stream, "addr/", addr_value);278if (result == NULL) {279/* event declined */280generic_print_address(vma, dinfo);281}282}283284285/* configuration */286287static void set_optional_callbacks(struct hsdis_app_data* app_data);288static void parse_caller_options(struct hsdis_app_data* app_data,289const char* caller_options);290static const char* native_arch_name();291static enum bfd_endian native_endian();292static const bfd_arch_info_type* find_arch_info(const char* arch_nane);293static bfd* get_native_bfd(const bfd_arch_info_type* arch_info,294/* to avoid malloc: */295bfd* empty_bfd, bfd_target* empty_xvec);296static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo,297void *stream,298fprintf_ftype fprintf_func,299bfd* bfd,300char* disassembler_options);301static void parse_fake_insn(disassembler_ftype dfn,302struct disassemble_info* dinfo);303304static void setup_app_data(struct hsdis_app_data* app_data,305const char* caller_options) {306/* Make reasonable defaults for null callbacks.307A non-null stream for a null callback is assumed to be a FILE* for output.308Events are rendered as XML.309*/310set_optional_callbacks(app_data);311312/* Look into caller_options for anything interesting. */313if (caller_options != NULL)314parse_caller_options(app_data, caller_options);315316/* Discover which architecture we are going to disassemble. */317app_data->arch_name = &app_data->mach_option[0];318if (app_data->arch_name[0] == '\0')319app_data->arch_name = native_arch_name();320app_data->arch_info = find_arch_info(app_data->arch_name);321322/* Make a fake bfd to hold the arch. and byteorder info. */323struct {324bfd_target empty_xvec;325bfd empty_bfd;326} buf;327bfd* native_bfd = get_native_bfd(app_data->arch_info,328/* to avoid malloc: */329&buf.empty_bfd, &buf.empty_xvec);330init_disassemble_info_from_bfd(&app_data->dinfo,331app_data->printf_stream,332app_data->printf_callback,333native_bfd,334/* On PowerPC we get warnings, if we pass empty options */335(caller_options == NULL) ? NULL : app_data->insn_options);336337/* Finish linking together the various callback blocks. */338app_data->dinfo.application_data = (void*) app_data;339app_data->dfn = disassembler(bfd_get_arch(native_bfd),340bfd_big_endian(native_bfd),341bfd_get_mach(native_bfd),342native_bfd);343app_data->dinfo.print_address_func = hsdis_print_address_func;344app_data->dinfo.read_memory_func = hsdis_read_memory_func;345346if (app_data->dfn == NULL) {347const char* bad = app_data->arch_name;348static bool complained;349if (bad == &app_data->mach_option[0])350print_help(app_data, "bad mach=%s", bad);351else if (!complained)352print_help(app_data, "bad native mach=%s; please port hsdis to this platform", bad);353complained = true;354/* must bail out */355app_data->losing = true;356return;357}358359parse_fake_insn(app_data->dfn, &app_data->dinfo);360}361362363/* ignore all events, return a null */364static void* null_event_callback(void* ignore_stream, const char* ignore_event, void* arg) {365return NULL;366}367368/* print all events as XML markup */369static void* xml_event_callback(void* stream, const char* event, void* arg) {370FILE* fp = (FILE*) stream;371#define NS_PFX "dis:"372if (event[0] != '/') {373/* issue the tag, with or without a formatted argument */374fprintf(fp, "<"NS_PFX);375fprintf(fp, event, arg);376fprintf(fp, ">");377} else {378++event; /* skip slash */379const char* argp = strchr(event, ' ');380if (argp == NULL) {381/* no arguments; just issue the closing tag */382fprintf(fp, "</"NS_PFX"%s>", event);383} else {384/* split out the closing attributes as <dis:foo_done attr='val'/> */385int event_prefix = (argp - event);386fprintf(fp, "<"NS_PFX"%.*s_done", event_prefix, event);387fprintf(fp, argp, arg);388fprintf(fp, "/></"NS_PFX"%.*s>", event_prefix, event);389}390}391return NULL;392}393394static void set_optional_callbacks(struct hsdis_app_data* app_data) {395if (app_data->printf_callback == NULL) {396int (*fprintf_callback)(FILE*, const char*, ...) = &fprintf;397FILE* fprintf_stream = stdout;398app_data->printf_callback = (printf_callback_t) fprintf_callback;399if (app_data->printf_stream == NULL)400app_data->printf_stream = (void*) fprintf_stream;401}402if (app_data->event_callback == NULL) {403if (app_data->event_stream == NULL)404app_data->event_callback = &null_event_callback;405else406app_data->event_callback = &xml_event_callback;407}408409}410411static void parse_caller_options(struct hsdis_app_data* app_data, const char* caller_options) {412char* iop_base = app_data->insn_options;413char* iop_limit = iop_base + sizeof(app_data->insn_options) - 1;414char* iop = iop_base;415const char* p;416for (p = caller_options; p != NULL; ) {417const char* q = strchr(p, ',');418size_t plen = (q == NULL) ? strlen(p) : ((q++) - p);419if (plen == 4 && strncmp(p, "help", plen) == 0) {420print_help(app_data, NULL, NULL);421} else if (plen >= 5 && strncmp(p, "mach=", 5) == 0) {422char* mach_option = app_data->mach_option;423size_t mach_size = sizeof(app_data->mach_option);424mach_size -= 1; /*leave room for the null*/425if (plen > mach_size) plen = mach_size;426strncpy(mach_option, p, plen);427mach_option[plen] = '\0';428} else if (plen > 6 && strncmp(p, "hsdis-", 6) == 0) {429// do not pass these to the next level430} else {431/* just copy it; {i386,sparc}-dis.c might like to see it */432if (iop > iop_base && iop < iop_limit) (*iop++) = ',';433if (iop + plen > iop_limit)434plen = iop_limit - iop;435strncpy(iop, p, plen);436iop += plen;437}438p = q;439}440*iop = '\0';441}442443static void print_help(struct hsdis_app_data* app_data,444const char* msg, const char* arg) {445DECL_PRINTF_CALLBACK(app_data);446if (msg != NULL) {447(*printf_callback)(printf_stream, "hsdis: ");448(*printf_callback)(printf_stream, msg, arg);449(*printf_callback)(printf_stream, "\n");450}451(*printf_callback)(printf_stream, "hsdis output options:\n");452if (printf_callback == (printf_callback_t) &fprintf)453disassembler_usage((FILE*) printf_stream);454else455disassembler_usage(stderr); /* better than nothing */456(*printf_callback)(printf_stream, " mach=<arch> select disassembly mode\n");457#if defined(LIBARCH_i386) || defined(LIBARCH_amd64)458(*printf_callback)(printf_stream, " mach=i386 select 32-bit mode\n");459(*printf_callback)(printf_stream, " mach=x86-64 select 64-bit mode\n");460(*printf_callback)(printf_stream, " suffix always print instruction suffix\n");461#endif462(*printf_callback)(printf_stream, " help print this message\n");463}464465466/* low-level bfd and arch stuff that binutils doesn't do for us */467468static const bfd_arch_info_type* find_arch_info(const char* arch_name) {469const bfd_arch_info_type* arch_info = bfd_scan_arch(arch_name);470if (arch_info == NULL) {471extern const bfd_arch_info_type bfd_default_arch_struct;472arch_info = &bfd_default_arch_struct;473}474return arch_info;475}476477static const char* native_arch_name() {478const char* res = NULL;479#ifdef LIBARCH_i386480res = "i386";481#endif482#ifdef LIBARCH_amd64483res = "i386:x86-64";484#endif485#ifdef LIBARCH_sparc486res = "sparc:v8plusb";487#endif488#ifdef LIBARCH_sparcv9489res = "sparc:v9b";490#endif491#if defined(LIBARCH_ppc64) || defined(LIBARCH_ppc64le)492res = "powerpc:common64";493#endif494#ifdef LIBARCH_aarch64495res = "aarch64";496#endif497if (res == NULL)498res = "architecture not set in Makefile!";499return res;500}501502static enum bfd_endian native_endian() {503int32_t endian_test = 'x';504if (*(const char*) &endian_test == 'x')505return BFD_ENDIAN_LITTLE;506else507return BFD_ENDIAN_BIG;508}509510static bfd* get_native_bfd(const bfd_arch_info_type* arch_info,511bfd* empty_bfd, bfd_target* empty_xvec) {512memset(empty_bfd, 0, sizeof(*empty_bfd));513memset(empty_xvec, 0, sizeof(*empty_xvec));514empty_xvec->flavour = bfd_target_unknown_flavour;515empty_xvec->byteorder = native_endian();516empty_bfd->xvec = empty_xvec;517empty_bfd->arch_info = arch_info;518return empty_bfd;519}520521static int read_zero_data_only(bfd_vma ignore_p,522bfd_byte* myaddr, unsigned int length,523struct disassemble_info *ignore_info) {524memset(myaddr, 0, length);525return 0;526}527static int print_to_dev_null(void* ignore_stream, const char* ignore_format, ...) {528return 0;529}530531/* Prime the pump by running the selected disassembler on a null input.532This forces the machine-specific disassembler to divulge invariant533information like bytes_per_line.534*/535static void parse_fake_insn(disassembler_ftype dfn,536struct disassemble_info* dinfo) {537typedef int (*read_memory_ftype)538(bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,539struct disassemble_info *info);540read_memory_ftype read_memory_func = dinfo->read_memory_func;541fprintf_ftype fprintf_func = dinfo->fprintf_func;542543dinfo->read_memory_func = &read_zero_data_only;544dinfo->fprintf_func = &print_to_dev_null;545(*dfn)(0, dinfo);546547/* put it back */548dinfo->read_memory_func = read_memory_func;549dinfo->fprintf_func = fprintf_func;550}551552static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo,553void *stream,554fprintf_ftype fprintf_func,555bfd* abfd,556char* disassembler_options) {557init_disassemble_info(dinfo, stream, fprintf_func);558559dinfo->flavour = bfd_get_flavour(abfd);560dinfo->arch = bfd_get_arch(abfd);561dinfo->mach = bfd_get_mach(abfd);562dinfo->disassembler_options = disassembler_options;563dinfo->octets_per_byte = bfd_octets_per_byte (abfd);564dinfo->skip_zeroes = sizeof(void*) * 2;565dinfo->skip_zeroes_at_end = sizeof(void*)-1;566dinfo->disassembler_needs_relocs = FALSE;567568if (bfd_big_endian(abfd))569dinfo->display_endian = dinfo->endian = BFD_ENDIAN_BIG;570else if (bfd_little_endian(abfd))571dinfo->display_endian = dinfo->endian = BFD_ENDIAN_LITTLE;572else573dinfo->endian = native_endian();574575disassemble_init_for_target(dinfo);576}577578579