12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373 |
- /* Agent expression code for remote server.
- Copyright (C) 2009-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "server.h"
- #include "ax.h"
- #include "gdbsupport/format.h"
- #include "tracepoint.h"
- #include "gdbsupport/rsp-low.h"
- static void ax_vdebug (const char *, ...) ATTRIBUTE_PRINTF (1, 2);
- #ifdef IN_PROCESS_AGENT
- bool debug_agent = 0;
- #endif
- static void
- ax_vdebug (const char *fmt, ...)
- {
- char buf[1024];
- va_list ap;
- va_start (ap, fmt);
- vsprintf (buf, fmt, ap);
- #ifdef IN_PROCESS_AGENT
- fprintf (stderr, PROG "/ax: %s\n", buf);
- #else
- threads_debug_printf (PROG "/ax: %s", buf);
- #endif
- va_end (ap);
- }
- #define ax_debug(fmt, args...) \
- do { \
- if (debug_threads) \
- ax_vdebug ((fmt), ##args); \
- } while (0)
- /* This enum must exactly match what is documented in
- gdb/doc/agentexpr.texi, including all the numerical values. */
- enum gdb_agent_op
- {
- #define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) \
- gdb_agent_op_ ## NAME = VALUE,
- #include "gdbsupport/ax.def"
- #undef DEFOP
- gdb_agent_op_last
- };
- static const char * const gdb_agent_op_names [gdb_agent_op_last] =
- {
- "?undef?"
- #define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) , # NAME
- #include "gdbsupport/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 "gdbsupport/ax.def"
- #undef DEFOP
- };
- #endif
- /* A wrapper for gdb_agent_op_names that does some bounds-checking. */
- static const char *
- gdb_agent_op_name (int op)
- {
- if (op < 0 || op >= gdb_agent_op_last || gdb_agent_op_names[op] == NULL)
- return "?undef?";
- return gdb_agent_op_names[op];
- }
- #ifndef IN_PROCESS_AGENT
- /* The packet form of an agent expression consists of an 'X', number
- of bytes in expression, a comma, and then the bytes. */
- struct agent_expr *
- gdb_parse_agent_expr (const char **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 = XNEW (struct agent_expr);
- aexpr->length = 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 *
- gdb_unparse_agent_expr (struct agent_expr *aexpr)
- {
- char *rslt;
- rslt = (char *) xmalloc (2 * aexpr->length + 1);
- bin2hex (aexpr->bytes, rslt, aexpr->length);
- return rslt;
- }
- /* Bytecode compilation. */
- CORE_ADDR current_insn_ptr;
- int emit_error;
- static struct bytecode_address
- {
- int pc;
- CORE_ADDR address;
- int goto_pc;
- /* Offset and size of field to be modified in the goto block. */
- int from_offset, from_size;
- struct bytecode_address *next;
- } *bytecode_address_table;
- void
- emit_prologue (void)
- {
- target_emit_ops ()->emit_prologue ();
- }
- void
- emit_epilogue (void)
- {
- target_emit_ops ()->emit_epilogue ();
- }
- static void
- emit_add (void)
- {
- target_emit_ops ()->emit_add ();
- }
- static void
- emit_sub (void)
- {
- target_emit_ops ()->emit_sub ();
- }
- static void
- emit_mul (void)
- {
- target_emit_ops ()->emit_mul ();
- }
- static void
- emit_lsh (void)
- {
- target_emit_ops ()->emit_lsh ();
- }
- static void
- emit_rsh_signed (void)
- {
- target_emit_ops ()->emit_rsh_signed ();
- }
- static void
- emit_rsh_unsigned (void)
- {
- target_emit_ops ()->emit_rsh_unsigned ();
- }
- static void
- emit_ext (int arg)
- {
- target_emit_ops ()->emit_ext (arg);
- }
- static void
- emit_log_not (void)
- {
- target_emit_ops ()->emit_log_not ();
- }
- static void
- emit_bit_and (void)
- {
- target_emit_ops ()->emit_bit_and ();
- }
- static void
- emit_bit_or (void)
- {
- target_emit_ops ()->emit_bit_or ();
- }
- static void
- emit_bit_xor (void)
- {
- target_emit_ops ()->emit_bit_xor ();
- }
- static void
- emit_bit_not (void)
- {
- target_emit_ops ()->emit_bit_not ();
- }
- static void
- emit_equal (void)
- {
- target_emit_ops ()->emit_equal ();
- }
- static void
- emit_less_signed (void)
- {
- target_emit_ops ()->emit_less_signed ();
- }
- static void
- emit_less_unsigned (void)
- {
- target_emit_ops ()->emit_less_unsigned ();
- }
- static void
- emit_ref (int size)
- {
- target_emit_ops ()->emit_ref (size);
- }
- static void
- emit_if_goto (int *offset_p, int *size_p)
- {
- target_emit_ops ()->emit_if_goto (offset_p, size_p);
- }
- static void
- emit_goto (int *offset_p, int *size_p)
- {
- target_emit_ops ()->emit_goto (offset_p, size_p);
- }
- static void
- write_goto_address (CORE_ADDR from, CORE_ADDR to, int size)
- {
- target_emit_ops ()->write_goto_address (from, to, size);
- }
- static void
- emit_const (LONGEST num)
- {
- target_emit_ops ()->emit_const (num);
- }
- static void
- emit_reg (int reg)
- {
- target_emit_ops ()->emit_reg (reg);
- }
- static void
- emit_pop (void)
- {
- target_emit_ops ()->emit_pop ();
- }
- static void
- emit_stack_flush (void)
- {
- target_emit_ops ()->emit_stack_flush ();
- }
- static void
- emit_zero_ext (int arg)
- {
- target_emit_ops ()->emit_zero_ext (arg);
- }
- static void
- emit_swap (void)
- {
- target_emit_ops ()->emit_swap ();
- }
- static void
- emit_stack_adjust (int n)
- {
- target_emit_ops ()->emit_stack_adjust (n);
- }
- /* FN's prototype is `LONGEST(*fn)(int)'. */
- static void
- emit_int_call_1 (CORE_ADDR fn, int arg1)
- {
- target_emit_ops ()->emit_int_call_1 (fn, arg1);
- }
- /* FN's prototype is `void(*fn)(int,LONGEST)'. */
- static void
- emit_void_call_2 (CORE_ADDR fn, int arg1)
- {
- target_emit_ops ()->emit_void_call_2 (fn, arg1);
- }
- static void
- emit_eq_goto (int *offset_p, int *size_p)
- {
- target_emit_ops ()->emit_eq_goto (offset_p, size_p);
- }
- static void
- emit_ne_goto (int *offset_p, int *size_p)
- {
- target_emit_ops ()->emit_ne_goto (offset_p, size_p);
- }
- static void
- emit_lt_goto (int *offset_p, int *size_p)
- {
- target_emit_ops ()->emit_lt_goto (offset_p, size_p);
- }
- static void
- emit_ge_goto (int *offset_p, int *size_p)
- {
- target_emit_ops ()->emit_ge_goto (offset_p, size_p);
- }
- static void
- emit_gt_goto (int *offset_p, int *size_p)
- {
- target_emit_ops ()->emit_gt_goto (offset_p, size_p);
- }
- static void
- emit_le_goto (int *offset_p, int *size_p)
- {
- target_emit_ops ()->emit_le_goto (offset_p, size_p);
- }
- /* Scan an agent expression for any evidence that the given PC is the
- target of a jump bytecode in the expression. */
- static int
- is_goto_target (struct agent_expr *aexpr, int pc)
- {
- int i;
- unsigned char op;
- for (i = 0; i < aexpr->length; i += 1 + gdb_agent_op_sizes[op])
- {
- op = aexpr->bytes[i];
- if (op == gdb_agent_op_goto || op == gdb_agent_op_if_goto)
- {
- int target = (aexpr->bytes[i + 1] << 8) + aexpr->bytes[i + 2];
- if (target == pc)
- return 1;
- }
- }
- return 0;
- }
- /* Given an agent expression, turn it into native code. */
- enum eval_result_type
- compile_bytecodes (struct agent_expr *aexpr)
- {
- int pc = 0;
- int done = 0;
- unsigned char op, next_op;
- int arg;
- /* This is only used to build 64-bit value for constants. */
- ULONGEST top;
- struct bytecode_address *aentry, *aentry2;
- #define UNHANDLED \
- do \
- { \
- ax_debug ("Cannot compile op 0x%x\n", op); \
- return expr_eval_unhandled_opcode; \
- } while (0)
- if (aexpr->length == 0)
- {
- ax_debug ("empty agent expression\n");
- return expr_eval_empty_expression;
- }
- bytecode_address_table = NULL;
- while (!done)
- {
- op = aexpr->bytes[pc];
- ax_debug ("About to compile op 0x%x, pc=%d\n", op, pc);
- /* Record the compiled-code address of the bytecode, for use by
- jump instructions. */
- aentry = XNEW (struct bytecode_address);
- aentry->pc = pc;
- aentry->address = current_insn_ptr;
- aentry->goto_pc = -1;
- aentry->from_offset = aentry->from_size = 0;
- aentry->next = bytecode_address_table;
- bytecode_address_table = aentry;
- ++pc;
- emit_error = 0;
- switch (op)
- {
- case gdb_agent_op_add:
- emit_add ();
- break;
- case gdb_agent_op_sub:
- emit_sub ();
- break;
- case gdb_agent_op_mul:
- emit_mul ();
- break;
- case gdb_agent_op_div_signed:
- UNHANDLED;
- break;
- case gdb_agent_op_div_unsigned:
- UNHANDLED;
- break;
- case gdb_agent_op_rem_signed:
- UNHANDLED;
- break;
- case gdb_agent_op_rem_unsigned:
- UNHANDLED;
- break;
- case gdb_agent_op_lsh:
- emit_lsh ();
- break;
- case gdb_agent_op_rsh_signed:
- emit_rsh_signed ();
- break;
- case gdb_agent_op_rsh_unsigned:
- emit_rsh_unsigned ();
- break;
- case gdb_agent_op_trace:
- UNHANDLED;
- break;
- case gdb_agent_op_trace_quick:
- UNHANDLED;
- break;
- case gdb_agent_op_log_not:
- emit_log_not ();
- break;
- case gdb_agent_op_bit_and:
- emit_bit_and ();
- break;
- case gdb_agent_op_bit_or:
- emit_bit_or ();
- break;
- case gdb_agent_op_bit_xor:
- emit_bit_xor ();
- break;
- case gdb_agent_op_bit_not:
- emit_bit_not ();
- break;
- case gdb_agent_op_equal:
- next_op = aexpr->bytes[pc];
- if (next_op == gdb_agent_op_if_goto
- && !is_goto_target (aexpr, pc)
- && target_emit_ops ()->emit_eq_goto)
- {
- ax_debug ("Combining equal & if_goto");
- pc += 1;
- aentry->pc = pc;
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- aentry->goto_pc = arg;
- emit_eq_goto (&(aentry->from_offset), &(aentry->from_size));
- }
- else if (next_op == gdb_agent_op_log_not
- && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto)
- && !is_goto_target (aexpr, pc + 1)
- && target_emit_ops ()->emit_ne_goto)
- {
- ax_debug ("Combining equal & log_not & if_goto");
- pc += 2;
- aentry->pc = pc;
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- aentry->goto_pc = arg;
- emit_ne_goto (&(aentry->from_offset), &(aentry->from_size));
- }
- else
- emit_equal ();
- break;
- case gdb_agent_op_less_signed:
- next_op = aexpr->bytes[pc];
- if (next_op == gdb_agent_op_if_goto
- && !is_goto_target (aexpr, pc))
- {
- ax_debug ("Combining less_signed & if_goto");
- pc += 1;
- aentry->pc = pc;
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- aentry->goto_pc = arg;
- emit_lt_goto (&(aentry->from_offset), &(aentry->from_size));
- }
- else if (next_op == gdb_agent_op_log_not
- && !is_goto_target (aexpr, pc)
- && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto)
- && !is_goto_target (aexpr, pc + 1))
- {
- ax_debug ("Combining less_signed & log_not & if_goto");
- pc += 2;
- aentry->pc = pc;
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- aentry->goto_pc = arg;
- emit_ge_goto (&(aentry->from_offset), &(aentry->from_size));
- }
- else
- emit_less_signed ();
- break;
- case gdb_agent_op_less_unsigned:
- emit_less_unsigned ();
- break;
- case gdb_agent_op_ext:
- arg = aexpr->bytes[pc++];
- if (arg < (sizeof (LONGEST) * 8))
- emit_ext (arg);
- break;
- case gdb_agent_op_ref8:
- emit_ref (1);
- break;
- case gdb_agent_op_ref16:
- emit_ref (2);
- break;
- case gdb_agent_op_ref32:
- emit_ref (4);
- break;
- case gdb_agent_op_ref64:
- emit_ref (8);
- break;
- case gdb_agent_op_if_goto:
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- aentry->goto_pc = arg;
- emit_if_goto (&(aentry->from_offset), &(aentry->from_size));
- break;
- case gdb_agent_op_goto:
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- aentry->goto_pc = arg;
- emit_goto (&(aentry->from_offset), &(aentry->from_size));
- break;
- case gdb_agent_op_const8:
- emit_stack_flush ();
- top = aexpr->bytes[pc++];
- emit_const (top);
- break;
- case gdb_agent_op_const16:
- emit_stack_flush ();
- top = aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- emit_const (top);
- break;
- case gdb_agent_op_const32:
- emit_stack_flush ();
- top = aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- emit_const (top);
- break;
- case gdb_agent_op_const64:
- emit_stack_flush ();
- top = aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- emit_const (top);
- break;
- case gdb_agent_op_reg:
- emit_stack_flush ();
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- emit_reg (arg);
- break;
- case gdb_agent_op_end:
- ax_debug ("At end of expression\n");
- /* Assume there is one stack element left, and that it is
- cached in "top" where emit_epilogue can get to it. */
- emit_stack_adjust (1);
- done = 1;
- break;
- case gdb_agent_op_dup:
- /* In our design, dup is equivalent to stack flushing. */
- emit_stack_flush ();
- break;
- case gdb_agent_op_pop:
- emit_pop ();
- break;
- case gdb_agent_op_zero_ext:
- arg = aexpr->bytes[pc++];
- if (arg < (sizeof (LONGEST) * 8))
- emit_zero_ext (arg);
- break;
- case gdb_agent_op_swap:
- next_op = aexpr->bytes[pc];
- /* Detect greater-than comparison sequences. */
- if (next_op == gdb_agent_op_less_signed
- && !is_goto_target (aexpr, pc)
- && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto)
- && !is_goto_target (aexpr, pc + 1))
- {
- ax_debug ("Combining swap & less_signed & if_goto");
- pc += 2;
- aentry->pc = pc;
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- aentry->goto_pc = arg;
- emit_gt_goto (&(aentry->from_offset), &(aentry->from_size));
- }
- else if (next_op == gdb_agent_op_less_signed
- && !is_goto_target (aexpr, pc)
- && (aexpr->bytes[pc + 1] == gdb_agent_op_log_not)
- && !is_goto_target (aexpr, pc + 1)
- && (aexpr->bytes[pc + 2] == gdb_agent_op_if_goto)
- && !is_goto_target (aexpr, pc + 2))
- {
- ax_debug ("Combining swap & less_signed & log_not & if_goto");
- pc += 3;
- aentry->pc = pc;
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- aentry->goto_pc = arg;
- emit_le_goto (&(aentry->from_offset), &(aentry->from_size));
- }
- else
- emit_swap ();
- break;
- case gdb_agent_op_getv:
- emit_stack_flush ();
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- emit_int_call_1 (get_get_tsv_func_addr (),
- arg);
- break;
- case gdb_agent_op_setv:
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- emit_void_call_2 (get_set_tsv_func_addr (),
- arg);
- break;
- case gdb_agent_op_tracev:
- UNHANDLED;
- break;
- /* GDB never (currently) generates any of these ops. */
- case gdb_agent_op_float:
- case gdb_agent_op_ref_float:
- case gdb_agent_op_ref_double:
- case gdb_agent_op_ref_long_double:
- case gdb_agent_op_l_to_d:
- case gdb_agent_op_d_to_l:
- case gdb_agent_op_trace16:
- UNHANDLED;
- break;
- default:
- ax_debug ("Agent expression op 0x%x not recognized\n", op);
- /* Don't struggle on, things will just get worse. */
- return expr_eval_unrecognized_opcode;
- }
- /* This catches errors that occur in target-specific code
- emission. */
- if (emit_error)
- {
- ax_debug ("Error %d while emitting code for %s\n",
- emit_error, gdb_agent_op_name (op));
- return expr_eval_unhandled_opcode;
- }
- ax_debug ("Op %s compiled\n", gdb_agent_op_name (op));
- }
- /* Now fill in real addresses as goto destinations. */
- for (aentry = bytecode_address_table; aentry; aentry = aentry->next)
- {
- int written = 0;
- if (aentry->goto_pc < 0)
- continue;
- /* Find the location that we are going to, and call back into
- target-specific code to write the actual address or
- displacement. */
- for (aentry2 = bytecode_address_table; aentry2; aentry2 = aentry2->next)
- {
- if (aentry2->pc == aentry->goto_pc)
- {
- ax_debug ("Want to jump from %s to %s\n",
- paddress (aentry->address),
- paddress (aentry2->address));
- write_goto_address (aentry->address + aentry->from_offset,
- aentry2->address, aentry->from_size);
- written = 1;
- break;
- }
- }
- /* Error out if we didn't find a destination. */
- if (!written)
- {
- ax_debug ("Destination of goto %d not found\n",
- aentry->goto_pc);
- return expr_eval_invalid_goto;
- }
- }
- return expr_eval_no_error;
- }
- #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 (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 size_t_arg:
- {
- size_t 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 eval_agent_expr_context *ctx,
- struct agent_expr *aexpr,
- ULONGEST *rslt)
- {
- int pc = 0;
- #define STACK_MAX 100
- ULONGEST stack[STACK_MAX], top;
- int sp = 0;
- unsigned char op;
- int arg;
- /* This union is a convenient way to convert representations. For
- now, assume a standard architecture where the hardware integer
- types have 8, 16, 32, 64 bit types. A more robust solution would
- be to import stdint.h from gnulib. */
- union
- {
- union
- {
- unsigned char bytes[1];
- unsigned char val;
- } u8;
- union
- {
- unsigned char bytes[2];
- unsigned short val;
- } u16;
- union
- {
- unsigned char bytes[4];
- unsigned int val;
- } u32;
- union
- {
- unsigned char bytes[8];
- ULONGEST val;
- } u64;
- } cnv;
- if (aexpr->length == 0)
- {
- ax_debug ("empty agent expression");
- return expr_eval_empty_expression;
- }
- /* Cache the stack top in its own variable. Much of the time we can
- operate on this variable, rather than dinking with the stack. It
- needs to be copied to the stack when sp changes. */
- top = 0;
- while (1)
- {
- op = aexpr->bytes[pc++];
- ax_debug ("About to interpret byte 0x%x", op);
- switch (op)
- {
- case gdb_agent_op_add:
- top += stack[--sp];
- break;
- case gdb_agent_op_sub:
- top = stack[--sp] - top;
- break;
- case gdb_agent_op_mul:
- top *= stack[--sp];
- break;
- case gdb_agent_op_div_signed:
- if (top == 0)
- {
- ax_debug ("Attempted to divide by zero");
- return expr_eval_divide_by_zero;
- }
- top = ((LONGEST) stack[--sp]) / ((LONGEST) top);
- break;
- case gdb_agent_op_div_unsigned:
- if (top == 0)
- {
- ax_debug ("Attempted to divide by zero");
- return expr_eval_divide_by_zero;
- }
- top = stack[--sp] / top;
- break;
- case gdb_agent_op_rem_signed:
- if (top == 0)
- {
- ax_debug ("Attempted to divide by zero");
- return expr_eval_divide_by_zero;
- }
- top = ((LONGEST) stack[--sp]) % ((LONGEST) top);
- break;
- case gdb_agent_op_rem_unsigned:
- if (top == 0)
- {
- ax_debug ("Attempted to divide by zero");
- return expr_eval_divide_by_zero;
- }
- top = stack[--sp] % top;
- break;
- case gdb_agent_op_lsh:
- top = stack[--sp] << top;
- break;
- case gdb_agent_op_rsh_signed:
- top = ((LONGEST) stack[--sp]) >> top;
- break;
- case gdb_agent_op_rsh_unsigned:
- top = stack[--sp] >> top;
- break;
- case gdb_agent_op_trace:
- 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 (ctx, NULL, (CORE_ADDR) top, (ULONGEST) arg);
- break;
- case gdb_agent_op_log_not:
- top = !top;
- break;
- case gdb_agent_op_bit_and:
- top &= stack[--sp];
- break;
- case gdb_agent_op_bit_or:
- top |= stack[--sp];
- break;
- case gdb_agent_op_bit_xor:
- top ^= stack[--sp];
- break;
- case gdb_agent_op_bit_not:
- top = ~top;
- break;
- case gdb_agent_op_equal:
- top = (stack[--sp] == top);
- break;
- case gdb_agent_op_less_signed:
- top = (((LONGEST) stack[--sp]) < ((LONGEST) top));
- break;
- case gdb_agent_op_less_unsigned:
- top = (stack[--sp] < top);
- break;
- case gdb_agent_op_ext:
- arg = aexpr->bytes[pc++];
- if (arg < (sizeof (LONGEST) * 8))
- {
- LONGEST mask = 1 << (arg - 1);
- top &= ((LONGEST) 1 << arg) - 1;
- top = (top ^ mask) - mask;
- }
- break;
- case gdb_agent_op_ref8:
- agent_mem_read (ctx, cnv.u8.bytes, (CORE_ADDR) top, 1);
- top = cnv.u8.val;
- break;
- case gdb_agent_op_ref16:
- agent_mem_read (ctx, cnv.u16.bytes, (CORE_ADDR) top, 2);
- top = cnv.u16.val;
- break;
- case gdb_agent_op_ref32:
- agent_mem_read (ctx, cnv.u32.bytes, (CORE_ADDR) top, 4);
- top = cnv.u32.val;
- break;
- case gdb_agent_op_ref64:
- agent_mem_read (ctx, cnv.u64.bytes, (CORE_ADDR) top, 8);
- top = cnv.u64.val;
- break;
- case gdb_agent_op_if_goto:
- if (top)
- pc = (aexpr->bytes[pc] << 8) + (aexpr->bytes[pc + 1]);
- else
- pc += 2;
- if (--sp >= 0)
- top = stack[sp];
- break;
- case gdb_agent_op_goto:
- pc = (aexpr->bytes[pc] << 8) + (aexpr->bytes[pc + 1]);
- break;
- case gdb_agent_op_const8:
- /* Flush the cached stack top. */
- stack[sp++] = top;
- top = aexpr->bytes[pc++];
- break;
- case gdb_agent_op_const16:
- /* Flush the cached stack top. */
- stack[sp++] = top;
- top = aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- break;
- case gdb_agent_op_const32:
- /* Flush the cached stack top. */
- stack[sp++] = top;
- top = aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- break;
- case gdb_agent_op_const64:
- /* Flush the cached stack top. */
- stack[sp++] = top;
- top = aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- break;
- case gdb_agent_op_reg:
- /* Flush the cached stack top. */
- stack[sp++] = top;
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- {
- int regnum = arg;
- struct regcache *regcache = ctx->regcache;
- switch (register_size (regcache->tdesc, regnum))
- {
- case 8:
- collect_register (regcache, regnum, cnv.u64.bytes);
- top = cnv.u64.val;
- break;
- case 4:
- collect_register (regcache, regnum, cnv.u32.bytes);
- top = cnv.u32.val;
- break;
- case 2:
- collect_register (regcache, regnum, cnv.u16.bytes);
- top = cnv.u16.val;
- break;
- case 1:
- collect_register (regcache, regnum, cnv.u8.bytes);
- top = cnv.u8.val;
- break;
- default:
- internal_error (__FILE__, __LINE__,
- "unhandled register size");
- }
- }
- break;
- case gdb_agent_op_end:
- ax_debug ("At end of expression, sp=%d, stack top cache=0x%s",
- sp, pulongest (top));
- if (rslt)
- {
- if (sp <= 0)
- {
- /* This should be an error */
- ax_debug ("Stack is empty, nothing to return");
- return expr_eval_empty_stack;
- }
- *rslt = top;
- }
- return expr_eval_no_error;
- case gdb_agent_op_dup:
- stack[sp++] = top;
- break;
- case gdb_agent_op_pop:
- if (--sp >= 0)
- top = stack[sp];
- break;
- case gdb_agent_op_pick:
- arg = aexpr->bytes[pc++];
- stack[sp] = top;
- top = stack[sp - arg];
- ++sp;
- break;
- case gdb_agent_op_rot:
- {
- ULONGEST tem = stack[sp - 1];
- stack[sp - 1] = stack[sp - 2];
- stack[sp - 2] = top;
- top = tem;
- }
- break;
- case gdb_agent_op_zero_ext:
- arg = aexpr->bytes[pc++];
- if (arg < (sizeof (LONGEST) * 8))
- top &= ((LONGEST) 1 << arg) - 1;
- break;
- case gdb_agent_op_swap:
- /* Interchange top two stack elements, making sure top gets
- copied back onto stack. */
- stack[sp] = top;
- top = stack[sp - 1];
- stack[sp - 1] = stack[sp];
- break;
- case gdb_agent_op_getv:
- /* Flush the cached stack top. */
- stack[sp++] = top;
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- top = agent_get_trace_state_variable_value (arg);
- break;
- case gdb_agent_op_setv:
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- agent_set_trace_state_variable_value (arg, top);
- /* Note that we leave the value on the stack, for the
- benefit of later/enclosing expressions. */
- break;
- case gdb_agent_op_tracev:
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- agent_tsv_read (ctx, arg);
- break;
- case gdb_agent_op_tracenz:
- 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:
- case gdb_agent_op_ref_double:
- case gdb_agent_op_ref_long_double:
- case gdb_agent_op_l_to_d:
- case gdb_agent_op_d_to_l:
- case gdb_agent_op_trace16:
- ax_debug ("Agent expression op 0x%x valid, but not handled",
- op);
- /* If ever GDB generates any of these, we don't have the
- option of ignoring. */
- return expr_eval_unhandled_opcode;
- default:
- ax_debug ("Agent expression op 0x%x not recognized", op);
- /* Don't struggle on, things will just get worse. */
- return expr_eval_unrecognized_opcode;
- }
- /* Check for stack badness. */
- if (sp >= (STACK_MAX - 1))
- {
- ax_debug ("Expression stack overflow");
- return expr_eval_stack_overflow;
- }
- if (sp < 0)
- {
- ax_debug ("Expression stack underflow");
- return expr_eval_stack_underflow;
- }
- ax_debug ("Op %s -> sp=%d, top=0x%s",
- gdb_agent_op_name (op), sp, phex_nz (top, 0));
- }
- }
|