| /* ********************************************************** |
| * Copyright (c) 2011-2014 Google, Inc. All rights reserved. |
| * **********************************************************/ |
| |
| /* |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * * Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * * Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * * Neither the name of Google, Inc. nor the names of its contributors may be |
| * used to endorse or promote products derived from this software without |
| * specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
| * DAMAGE. |
| */ |
| |
| /* support needed to create a standalone static decoding library that |
| * includes only the decode+encode routines from DR (i#617) |
| */ |
| |
| /***************************************************************************/ |
| #ifdef STANDALONE_DECODER |
| |
| #include "../globals.h" |
| #include "instr.h" |
| |
| #ifdef UNIX |
| # include <unistd.h> |
| #endif |
| |
| /* initialize to all zeros. disassemble_set_syntax will write to it. */ |
| options_t dynamo_options; |
| |
| /* support use of STD* macros so user doesn't have to use "stdout->_fileno" */ |
| #ifdef UNIX |
| file_t our_stdout = STDOUT_FILENO; |
| file_t our_stderr = STDERR_FILENO; |
| file_t our_stdin = STDIN_FILENO; |
| #endif |
| |
| #ifdef WINDOWS |
| DR_API file_t |
| dr_get_stdout_file(void) |
| { |
| return GetStdHandle(STD_OUTPUT_HANDLE); |
| } |
| |
| DR_API file_t |
| dr_get_stderr_file(void) |
| { |
| return GetStdHandle(STD_ERROR_HANDLE); |
| } |
| |
| DR_API file_t |
| dr_get_stdin_file(void) |
| { |
| return GetStdHandle(STD_INPUT_HANDLE); |
| } |
| #endif |
| |
| static uint vendor = VENDOR_INTEL; /* default */ |
| |
| uint |
| proc_get_vendor(void) |
| { |
| return vendor; |
| } |
| |
| DR_API |
| int |
| proc_set_vendor(uint new_vendor) |
| { |
| if (new_vendor == VENDOR_INTEL || |
| new_vendor == VENDOR_AMD) { |
| uint old_vendor = vendor; |
| vendor = new_vendor; |
| return old_vendor; |
| } else |
| return -1; |
| } |
| |
| void * |
| heap_alloc(dcontext_t *dcontext, size_t size HEAPACCT(which_heap_t which)) |
| { |
| return malloc(size); |
| } |
| |
| void |
| heap_free(dcontext_t *dcontext, void *p, size_t size HEAPACCT(which_heap_t which)) |
| { |
| free(p); |
| } |
| |
| dcontext_t * |
| get_thread_private_dcontext(void) |
| { |
| return GLOBAL_DCONTEXT; |
| } |
| |
| void |
| external_error(const char *file, int line, const char *msg) |
| { |
| printf("Usage error: %s (%s, line %d)", msg, file, line); |
| abort(); |
| } |
| |
| size_t |
| proc_save_fpstate(byte *buf) |
| { |
| return 0; |
| } |
| |
| void |
| proc_restore_fpstate(byte *buf) |
| { |
| } |
| |
| /* XXX: duplicated from arch.c */ |
| priv_mcontext_t * |
| dr_mcontext_as_priv_mcontext(dr_mcontext_t *mc) |
| { |
| return (priv_mcontext_t*)(&mc->IF_X86_ELSE(xdi,r0)); |
| } |
| |
| /* XXX: duplicated from instrument.c, for convert_to_near_rel_common() */ |
| /* Inserts inst as a non-application instruction into ilist after "where" */ |
| void |
| instrlist_meta_postinsert(instrlist_t *ilist, instr_t *where, instr_t *inst) |
| { |
| instr_set_meta(inst); |
| instrlist_postinsert(ilist, where, inst); |
| } |
| |
| /* XXX: the code below is duplicated w/ only minor changes from utils.c. |
| * But it's messier to go put ifdefs througout utils.c, and there are enough |
| * changes to these that utils_shared.c might also be messy. |
| */ |
| |
| void |
| double_print(double val, uint precision, uint *top, uint *bottom, |
| const char **sign) |
| { |
| uint i, precision_multiple; |
| if (val < 0.0) { |
| val = -val; |
| *sign = "-"; |
| } else { |
| *sign = ""; |
| } |
| for (i = 0, precision_multiple = 1; i < precision; i++) |
| precision_multiple *= 10; |
| *top = (uint)val; |
| *bottom = (uint)((val - *top) * precision_multiple); |
| } |
| |
| /* For repeated appending to a buffer. The "sofar" var should be set |
| * to 0 by the caller before the first call to print_to_buffer. |
| * Returns false if there was not room for the string plus a null, |
| * but still prints the maximum that will fit plus a null. |
| */ |
| bool |
| print_to_buffer(char *buf, size_t bufsz, size_t *sofar INOUT, const char *fmt, ...) |
| { |
| /* in io.c */ |
| #undef vsnprintf |
| extern int vsnprintf(char *s, size_t max, const char *fmt, va_list ap); |
| ssize_t len; |
| va_list ap; |
| bool ok; |
| va_start(ap, fmt); |
| len = vsnprintf(buf + *sofar, bufsz - *sofar, fmt, ap); |
| va_end(ap); |
| ok = (len > 0 && len < (ssize_t)(bufsz - *sofar)); |
| #ifdef UNIX |
| /* Linux vsnprintf returns what would have been written, unlike Windows |
| * or our_vsnprintf |
| */ |
| if (len >= (ssize_t)(bufsz - *sofar)) |
| len = -1; |
| #endif |
| *sofar += (len == -1 ? (bufsz - *sofar - 1) : (len < 0 ? 0 : len)); |
| /* be paranoid: though usually many calls in a row and could delay until end */ |
| buf[bufsz-1] = '\0'; |
| return ok; |
| } |
| |
| void |
| print_file(file_t f, const char *fmt, ...) |
| { |
| va_list ap; |
| /* XXX: vfprintf operates on FILE*, but our file_t is a fd, so we go |
| * to a buffer. Only used internally for disassembly so should not |
| * get even close to 4096. |
| */ |
| #define MAX_PRINT_FILE_LEN 4096 |
| char buf[MAX_PRINT_FILE_LEN]; |
| ssize_t len; |
| |
| va_start(ap, fmt); |
| len = vsnprintf(buf, BUFFER_SIZE_ELEMENTS(buf), fmt, ap); |
| va_end(ap); |
| |
| #ifdef UNIX |
| /* Linux vsnprintf returns what would have been written, unlike Windows |
| * or our_vsnprintf |
| */ |
| if (len >= BUFFER_SIZE_ELEMENTS(buf)) |
| len = BUFFER_SIZE_ELEMENTS(buf); /* don't need NULL term */ |
| #else |
| if (len < 0) |
| len = BUFFER_SIZE_ELEMENTS(buf); /* don't need NULL term */ |
| #endif |
| os_write(f, buf, len); |
| } |
| |
| ssize_t |
| os_write(file_t f, const void *buf, size_t count) |
| { |
| # ifdef UNIX |
| return write(f, buf, count); |
| # else |
| /* file_t is HANDLE opened with CreateFile */ |
| DWORD written = 0; |
| ssize_t out = -1; |
| BOOL ok; |
| if (f == INVALID_FILE) |
| return out; |
| /* our internal calls won't overflow uint */ |
| ok = WriteFile(f, buf, (uint) count, &written, NULL); |
| if (ok) |
| out = (ssize_t)written; |
| return out; |
| # endif |
| } |
| |
| #endif /* STANDALONE_DECODER */ |
| /***************************************************************************/ |