/* Agent expression code for remote server.
- Copyright (C) 2009-2012 Free Software Foundation, Inc.
+ Copyright (C) 2009-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "server.h"
#include "ax.h"
+#include "common/format.h"
+#include "tracepoint.h"
+#include "common/rsp-low.h"
-static void ax_vdebug (const char *, ...) ATTR_FORMAT (printf, 1, 2);
+static void ax_vdebug (const char *, ...) ATTRIBUTE_PRINTF (1, 2);
#ifdef IN_PROCESS_AGENT
int debug_agent = 0;
{
#define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) \
gdb_agent_op_ ## NAME = VALUE,
-#include "ax.def"
+#include "common/ax.def"
#undef DEFOP
gdb_agent_op_last
};
{
"?undef?"
#define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) , # NAME
-#include "ax.def"
+#include "common/ax.def"
#undef DEFOP
};
+#ifndef IN_PROCESS_AGENT
static const unsigned char gdb_agent_op_sizes [gdb_agent_op_last] =
{
0
#define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) , SIZE
-#include "ax.def"
+#include "common/ax.def"
#undef DEFOP
};
+#endif
/* A wrapper for gdb_agent_op_names that does some bounds-checking. */
of bytes in expression, a comma, and then the bytes. */
struct agent_expr *
-gdb_parse_agent_expr (char **actparm)
+gdb_parse_agent_expr (const char **actparm)
{
- char *act = *actparm;
+ const char *act = *actparm;
ULONGEST xlen;
struct agent_expr *aexpr;
++act; /* skip the X */
act = unpack_varlen_hex (act, &xlen);
++act; /* skip a comma */
- aexpr = xmalloc (sizeof (struct agent_expr));
+ aexpr = XNEW (struct agent_expr);
aexpr->length = xlen;
- aexpr->bytes = xmalloc (xlen);
- convert_ascii_to_int (act, aexpr->bytes, xlen);
+ aexpr->bytes = (unsigned char *) xmalloc (xlen);
+ hex2bin (act, aexpr->bytes, xlen);
*actparm = act + (xlen * 2);
return aexpr;
}
+void
+gdb_free_agent_expr (struct agent_expr *aexpr)
+{
+ if (aexpr != NULL)
+ {
+ free (aexpr->bytes);
+ free (aexpr);
+ }
+}
+
/* Convert the bytes of an agent expression back into hex digits, so
they can be printed or uploaded. This allocates the buffer,
callers should free when they are done with it. */
{
char *rslt;
- rslt = xmalloc (2 * aexpr->length + 1);
- convert_int_to_ascii (aexpr->bytes, rslt, aexpr->length);
+ rslt = (char *) xmalloc (2 * aexpr->length + 1);
+ bin2hex (aexpr->bytes, rslt, aexpr->length);
return rslt;
}
/* Scan an agent expression for any evidence that the given PC is the
target of a jump bytecode in the expression. */
-int
+static int
is_goto_target (struct agent_expr *aexpr, int pc)
{
int i;
/* Record the compiled-code address of the bytecode, for use by
jump instructions. */
- aentry = xmalloc (sizeof (struct bytecode_address));
+ aentry = XNEW (struct bytecode_address);
aentry->pc = pc;
aentry->address = current_insn_ptr;
aentry->goto_pc = -1;
#endif
+/* Make printf-type calls using arguments supplied from the host. We
+ need to parse the format string ourselves, and call the formatting
+ function with one argument at a time, partly because there is no
+ safe portable way to construct a varargs call, and partly to serve
+ as a security barrier against bad format strings that might get
+ in. */
+
+static void
+ax_printf (CORE_ADDR fn, CORE_ADDR chan, const char *format,
+ int nargs, ULONGEST *args)
+{
+ const char *f = format;
+ int i;
+ const char *current_substring;
+ int nargs_wanted;
+
+ ax_debug ("Printf of \"%s\" with %d args", format, nargs);
+
+ format_pieces fpieces (&f);
+
+ nargs_wanted = 0;
+ for (auto &&piece : fpieces)
+ if (piece.argclass != literal_piece)
+ ++nargs_wanted;
+
+ if (nargs != nargs_wanted)
+ error (_("Wrong number of arguments for specified format-string"));
+
+ i = 0;
+ for (auto &&piece : fpieces)
+ {
+ current_substring = piece.string;
+ ax_debug ("current substring is '%s', class is %d",
+ current_substring, piece.argclass);
+ switch (piece.argclass)
+ {
+ case string_arg:
+ {
+ gdb_byte *str;
+ CORE_ADDR tem;
+ int j;
+
+ tem = args[i];
+ if (tem == 0)
+ {
+ printf (current_substring, "(null)");
+ break;
+ }
+
+ /* This is a %s argument. Find the length of the string. */
+ for (j = 0;; j++)
+ {
+ gdb_byte c;
+
+ read_inferior_memory (tem + j, &c, 1);
+ if (c == 0)
+ break;
+ }
+
+ /* Copy the string contents into a string inside GDB. */
+ str = (gdb_byte *) alloca (j + 1);
+ if (j != 0)
+ read_inferior_memory (tem, str, j);
+ str[j] = 0;
+
+ printf (current_substring, (char *) str);
+ }
+ break;
+
+ case long_long_arg:
+#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
+ {
+ long long val = args[i];
+
+ printf (current_substring, val);
+ break;
+ }
+#else
+ error (_("long long not supported in agent printf"));
+#endif
+ case int_arg:
+ {
+ int val = args[i];
+
+ printf (current_substring, val);
+ break;
+ }
+
+ case long_arg:
+ {
+ long val = args[i];
+
+ printf (current_substring, val);
+ break;
+ }
+
+ case literal_piece:
+ /* Print a portion of the format string that has no
+ directives. Note that this will not include any
+ ordinary %-specs, but it might include "%%". That is
+ why we use printf_filtered and not puts_filtered here.
+ Also, we pass a dummy argument because some platforms
+ have modified GCC to include -Wformat-security by
+ default, which will warn here if there is no
+ argument. */
+ printf (current_substring, 0);
+ break;
+
+ default:
+ error (_("Format directive in '%s' not supported in agent printf"),
+ current_substring);
+ }
+
+ /* Maybe advance to the next argument. */
+ if (piece.argclass != literal_piece)
+ ++i;
+ }
+
+ fflush (stdout);
+}
+
/* The agent expression evaluator, as specified by the GDB docs. It
returns 0 if everything went OK, and a nonzero error code
otherwise. */
enum eval_result_type
-gdb_eval_agent_expr (struct regcache *regcache,
- struct traceframe *tframe,
+gdb_eval_agent_expr (struct eval_agent_expr_context *ctx,
struct agent_expr *aexpr,
ULONGEST *rslt)
{
break;
case gdb_agent_op_trace:
- agent_mem_read (tframe,
- NULL, (CORE_ADDR) stack[--sp], (ULONGEST) top);
+ agent_mem_read (ctx, NULL, (CORE_ADDR) stack[--sp],
+ (ULONGEST) top);
if (--sp >= 0)
top = stack[sp];
break;
case gdb_agent_op_trace_quick:
arg = aexpr->bytes[pc++];
- agent_mem_read (tframe, NULL, (CORE_ADDR) top, (ULONGEST) arg);
+ agent_mem_read (ctx, NULL, (CORE_ADDR) top, (ULONGEST) arg);
break;
case gdb_agent_op_log_not:
break;
case gdb_agent_op_ref8:
- agent_mem_read (tframe, cnv.u8.bytes, (CORE_ADDR) top, 1);
+ agent_mem_read (ctx, cnv.u8.bytes, (CORE_ADDR) top, 1);
top = cnv.u8.val;
break;
case gdb_agent_op_ref16:
- agent_mem_read (tframe, cnv.u16.bytes, (CORE_ADDR) top, 2);
+ agent_mem_read (ctx, cnv.u16.bytes, (CORE_ADDR) top, 2);
top = cnv.u16.val;
break;
case gdb_agent_op_ref32:
- agent_mem_read (tframe, cnv.u32.bytes, (CORE_ADDR) top, 4);
+ agent_mem_read (ctx, cnv.u32.bytes, (CORE_ADDR) top, 4);
top = cnv.u32.val;
break;
case gdb_agent_op_ref64:
- agent_mem_read (tframe, cnv.u64.bytes, (CORE_ADDR) top, 8);
+ agent_mem_read (ctx, cnv.u64.bytes, (CORE_ADDR) top, 8);
top = cnv.u64.val;
break;
arg = (arg << 8) + aexpr->bytes[pc++];
{
int regnum = arg;
+ struct regcache *regcache = ctx->regcache;
- switch (register_size (regnum))
+ switch (register_size (regcache->tdesc, regnum))
{
case 8:
collect_register (regcache, regnum, cnv.u64.bytes);
case gdb_agent_op_tracev:
arg = aexpr->bytes[pc++];
arg = (arg << 8) + aexpr->bytes[pc++];
- agent_tsv_read (tframe, arg);
+ agent_tsv_read (ctx, arg);
break;
case gdb_agent_op_tracenz:
- agent_mem_read_string (tframe, NULL, (CORE_ADDR) stack[--sp],
+ agent_mem_read_string (ctx, NULL, (CORE_ADDR) stack[--sp],
(ULONGEST) top);
if (--sp >= 0)
top = stack[sp];
break;
+ case gdb_agent_op_printf:
+ {
+ int nargs, slen, i;
+ CORE_ADDR fn = 0, chan = 0;
+ /* Can't have more args than the entire size of the stack. */
+ ULONGEST args[STACK_MAX];
+ char *format;
+
+ nargs = aexpr->bytes[pc++];
+ slen = aexpr->bytes[pc++];
+ slen = (slen << 8) + aexpr->bytes[pc++];
+ format = (char *) &(aexpr->bytes[pc]);
+ pc += slen;
+ /* Pop function and channel. */
+ fn = top;
+ if (--sp >= 0)
+ top = stack[sp];
+ chan = top;
+ if (--sp >= 0)
+ top = stack[sp];
+ /* Pop arguments into a dedicated array. */
+ for (i = 0; i < nargs; ++i)
+ {
+ args[i] = top;
+ if (--sp >= 0)
+ top = stack[sp];
+ }
+
+ /* A bad format string means something is very wrong; give
+ up immediately. */
+ if (format[slen - 1] != '\0')
+ error (_("Unterminated format string in printf bytecode"));
+
+ ax_printf (fn, chan, format, nargs, args);
+ }
+ break;
+
/* GDB never (currently) generates any of these ops. */
case gdb_agent_op_float:
case gdb_agent_op_ref_float:
op);
/* If ever GDB generates any of these, we don't have the
option of ignoring. */
- return 1;
+ return expr_eval_unhandled_opcode;
default:
ax_debug ("Agent expression op 0x%x not recognized", op);
}
ax_debug ("Op %s -> sp=%d, top=0x%s",
- gdb_agent_op_name (op), sp, pulongest (top));
+ gdb_agent_op_name (op), sp, phex_nz (top, 0));
}
}