blob: f78d7fe0a32900c008fc944d7fbbe9a0a4022dea [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2011-2023 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 /* around whole file */
# include "../globals.h"
# include "instr.h"
# include "opnd.h"
# ifdef UNIX
# include <unistd.h>
# endif
/* initialize to all zeros. disassemble_set_syntax will write to it. */
options_t dynamo_options;
# undef STDERR
/* 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;
# define STDERR (our_stderr)
# 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);
}
# define STDERR (dr_get_stderr_file())
# 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_reachable_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);
}
void
heap_reachable_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)
{
print_file(STDERR, "Usage error: %s (%s, line %d)\n", 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->MCXT_FLD_FIRST_REG);
}
/* 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 */
extern int d_r_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 = d_r_vsnprintf(buf + *sofar, bufsz - *sofar, fmt, ap);
va_end(ap);
ok = (len > 0 && len < (ssize_t)(bufsz - *sofar));
/* XXX: Unfortunately we're duplicating core/utils.c's vprint_to_buffer.
* Could we move that into io.c to share it with decodelib?
* For now we duplicate the complex check here: see the comment in
* vprint_to_buffer on the explanation.
*/
*sofar += (len == -1 || len == (ssize_t)(bufsz - *sofar) ? (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 d_r_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 */
/***************************************************************************/