12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799 |
- /* SystemTap probe support for GDB.
- Copyright (C) 2012-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 "defs.h"
- #include "stap-probe.h"
- #include "probe.h"
- #include "ui-out.h"
- #include "objfiles.h"
- #include "arch-utils.h"
- #include "command.h"
- #include "gdbcmd.h"
- #include "filenames.h"
- #include "value.h"
- #include "ax.h"
- #include "ax-gdb.h"
- #include "complaints.h"
- #include "cli/cli-utils.h"
- #include "linespec.h"
- #include "user-regs.h"
- #include "parser-defs.h"
- #include "language.h"
- #include "elf-bfd.h"
- #include "expop.h"
- #include <unordered_map>
- #include "gdbsupport/hash_enum.h"
- #include <ctype.h>
- /* The name of the SystemTap section where we will find information about
- the probes. */
- #define STAP_BASE_SECTION_NAME ".stapsdt.base"
- /* Should we display debug information for the probe's argument expression
- parsing? */
- static unsigned int stap_expression_debug = 0;
- /* The various possibilities of bitness defined for a probe's argument.
- The relationship is:
- - STAP_ARG_BITNESS_UNDEFINED: The user hasn't specified the bitness.
- - STAP_ARG_BITNESS_8BIT_UNSIGNED: argument string starts with `1@'.
- - STAP_ARG_BITNESS_8BIT_SIGNED: argument string starts with `-1@'.
- - STAP_ARG_BITNESS_16BIT_UNSIGNED: argument string starts with `2@'.
- - STAP_ARG_BITNESS_16BIT_SIGNED: argument string starts with `-2@'.
- - STAP_ARG_BITNESS_32BIT_UNSIGNED: argument string starts with `4@'.
- - STAP_ARG_BITNESS_32BIT_SIGNED: argument string starts with `-4@'.
- - STAP_ARG_BITNESS_64BIT_UNSIGNED: argument string starts with `8@'.
- - STAP_ARG_BITNESS_64BIT_SIGNED: argument string starts with `-8@'. */
- enum stap_arg_bitness
- {
- STAP_ARG_BITNESS_UNDEFINED,
- STAP_ARG_BITNESS_8BIT_UNSIGNED,
- STAP_ARG_BITNESS_8BIT_SIGNED,
- STAP_ARG_BITNESS_16BIT_UNSIGNED,
- STAP_ARG_BITNESS_16BIT_SIGNED,
- STAP_ARG_BITNESS_32BIT_UNSIGNED,
- STAP_ARG_BITNESS_32BIT_SIGNED,
- STAP_ARG_BITNESS_64BIT_UNSIGNED,
- STAP_ARG_BITNESS_64BIT_SIGNED,
- };
- /* The following structure represents a single argument for the probe. */
- struct stap_probe_arg
- {
- /* Constructor for stap_probe_arg. */
- stap_probe_arg (enum stap_arg_bitness bitness_, struct type *atype_,
- expression_up &&aexpr_)
- : bitness (bitness_), atype (atype_), aexpr (std::move (aexpr_))
- {}
- /* The bitness of this argument. */
- enum stap_arg_bitness bitness;
- /* The corresponding `struct type *' to the bitness. */
- struct type *atype;
- /* The argument converted to an internal GDB expression. */
- expression_up aexpr;
- };
- /* Class that implements the static probe methods for "stap" probes. */
- class stap_static_probe_ops : public static_probe_ops
- {
- public:
- /* We need a user-provided constructor to placate some compilers.
- See PR build/24937. */
- stap_static_probe_ops ()
- {
- }
- /* See probe.h. */
- bool is_linespec (const char **linespecp) const override;
- /* See probe.h. */
- void get_probes (std::vector<std::unique_ptr<probe>> *probesp,
- struct objfile *objfile) const override;
- /* See probe.h. */
- const char *type_name () const override;
- /* See probe.h. */
- std::vector<struct info_probe_column> gen_info_probes_table_header
- () const override;
- };
- /* SystemTap static_probe_ops. */
- const stap_static_probe_ops stap_static_probe_ops {};
- class stap_probe : public probe
- {
- public:
- /* Constructor for stap_probe. */
- stap_probe (std::string &&name_, std::string &&provider_, CORE_ADDR address_,
- struct gdbarch *arch_, CORE_ADDR sem_addr, const char *args_text)
- : probe (std::move (name_), std::move (provider_), address_, arch_),
- m_sem_addr (sem_addr),
- m_have_parsed_args (false), m_unparsed_args_text (args_text)
- {}
- /* See probe.h. */
- CORE_ADDR get_relocated_address (struct objfile *objfile) override;
- /* See probe.h. */
- unsigned get_argument_count (struct gdbarch *gdbarch) override;
- /* See probe.h. */
- bool can_evaluate_arguments () const override;
- /* See probe.h. */
- struct value *evaluate_argument (unsigned n,
- struct frame_info *frame) override;
- /* See probe.h. */
- void compile_to_ax (struct agent_expr *aexpr,
- struct axs_value *axs_value,
- unsigned n) override;
- /* See probe.h. */
- void set_semaphore (struct objfile *objfile,
- struct gdbarch *gdbarch) override;
- /* See probe.h. */
- void clear_semaphore (struct objfile *objfile,
- struct gdbarch *gdbarch) override;
- /* See probe.h. */
- const static_probe_ops *get_static_ops () const override;
- /* See probe.h. */
- std::vector<const char *> gen_info_probes_table_values () const override;
- /* Return argument N of probe.
- If the probe's arguments have not been parsed yet, parse them. If
- there are no arguments, throw an exception (error). Otherwise,
- return the requested argument. */
- struct stap_probe_arg *get_arg_by_number (unsigned n,
- struct gdbarch *gdbarch)
- {
- if (!m_have_parsed_args)
- this->parse_arguments (gdbarch);
- gdb_assert (m_have_parsed_args);
- if (m_parsed_args.empty ())
- internal_error (__FILE__, __LINE__,
- _("Probe '%s' apparently does not have arguments, but \n"
- "GDB is requesting its argument number %u anyway. "
- "This should not happen. Please report this bug."),
- this->get_name ().c_str (), n);
- if (n > m_parsed_args.size ())
- internal_error (__FILE__, __LINE__,
- _("Probe '%s' has %d arguments, but GDB is requesting\n"
- "argument %u. This should not happen. Please\n"
- "report this bug."),
- this->get_name ().c_str (),
- (int) m_parsed_args.size (), n);
- return &m_parsed_args[n];
- }
- /* Function which parses an argument string from the probe,
- correctly splitting the arguments and storing their information
- in properly ways.
- Consider the following argument string (x86 syntax):
- `4@%eax 4@$10'
- We have two arguments, `%eax' and `$10', both with 32-bit
- unsigned bitness. This function basically handles them, properly
- filling some structures with this information. */
- void parse_arguments (struct gdbarch *gdbarch);
- private:
- /* If the probe has a semaphore associated, then this is the value of
- it, relative to SECT_OFF_DATA. */
- CORE_ADDR m_sem_addr;
- /* True if the arguments have been parsed. */
- bool m_have_parsed_args;
- /* The text version of the probe's arguments, unparsed. */
- const char *m_unparsed_args_text;
- /* Information about each argument. This is an array of `stap_probe_arg',
- with each entry representing one argument. This is only valid if
- M_ARGS_PARSED is true. */
- std::vector<struct stap_probe_arg> m_parsed_args;
- };
- /* When parsing the arguments, we have to establish different precedences
- for the various kinds of asm operators. This enumeration represents those
- precedences.
- This logic behind this is available at
- <http://sourceware.org/binutils/docs/as/Infix-Ops.html#Infix-Ops>, or using
- the command "info '(as)Infix Ops'". */
- enum stap_operand_prec
- {
- /* Lowest precedence, used for non-recognized operands or for the beginning
- of the parsing process. */
- STAP_OPERAND_PREC_NONE = 0,
- /* Precedence of logical OR. */
- STAP_OPERAND_PREC_LOGICAL_OR,
- /* Precedence of logical AND. */
- STAP_OPERAND_PREC_LOGICAL_AND,
- /* Precedence of additive (plus, minus) and comparative (equal, less,
- greater-than, etc) operands. */
- STAP_OPERAND_PREC_ADD_CMP,
- /* Precedence of bitwise operands (bitwise OR, XOR, bitwise AND,
- logical NOT). */
- STAP_OPERAND_PREC_BITWISE,
- /* Precedence of multiplicative operands (multiplication, division,
- remainder, left shift and right shift). */
- STAP_OPERAND_PREC_MUL
- };
- static expr::operation_up stap_parse_argument_1 (struct stap_parse_info *p,
- expr::operation_up &&lhs,
- enum stap_operand_prec prec)
- ATTRIBUTE_UNUSED_RESULT;
- static expr::operation_up stap_parse_argument_conditionally
- (struct stap_parse_info *p) ATTRIBUTE_UNUSED_RESULT;
- /* Returns true if *S is an operator, false otherwise. */
- static bool stap_is_operator (const char *op);
- static void
- show_stapexpressiondebug (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("SystemTap Probe expression debugging is %s.\n"),
- value);
- }
- /* Returns the operator precedence level of OP, or STAP_OPERAND_PREC_NONE
- if the operator code was not recognized. */
- static enum stap_operand_prec
- stap_get_operator_prec (enum exp_opcode op)
- {
- switch (op)
- {
- case BINOP_LOGICAL_OR:
- return STAP_OPERAND_PREC_LOGICAL_OR;
- case BINOP_LOGICAL_AND:
- return STAP_OPERAND_PREC_LOGICAL_AND;
- case BINOP_ADD:
- case BINOP_SUB:
- case BINOP_EQUAL:
- case BINOP_NOTEQUAL:
- case BINOP_LESS:
- case BINOP_LEQ:
- case BINOP_GTR:
- case BINOP_GEQ:
- return STAP_OPERAND_PREC_ADD_CMP;
- case BINOP_BITWISE_IOR:
- case BINOP_BITWISE_AND:
- case BINOP_BITWISE_XOR:
- case UNOP_LOGICAL_NOT:
- return STAP_OPERAND_PREC_BITWISE;
- case BINOP_MUL:
- case BINOP_DIV:
- case BINOP_REM:
- case BINOP_LSH:
- case BINOP_RSH:
- return STAP_OPERAND_PREC_MUL;
- default:
- return STAP_OPERAND_PREC_NONE;
- }
- }
- /* Given S, read the operator in it. Return the EXP_OPCODE which
- represents the operator detected, or throw an error if no operator
- was found. */
- static enum exp_opcode
- stap_get_opcode (const char **s)
- {
- const char c = **s;
- enum exp_opcode op;
- *s += 1;
- switch (c)
- {
- case '*':
- op = BINOP_MUL;
- break;
- case '/':
- op = BINOP_DIV;
- break;
- case '%':
- op = BINOP_REM;
- break;
- case '<':
- op = BINOP_LESS;
- if (**s == '<')
- {
- *s += 1;
- op = BINOP_LSH;
- }
- else if (**s == '=')
- {
- *s += 1;
- op = BINOP_LEQ;
- }
- else if (**s == '>')
- {
- *s += 1;
- op = BINOP_NOTEQUAL;
- }
- break;
- case '>':
- op = BINOP_GTR;
- if (**s == '>')
- {
- *s += 1;
- op = BINOP_RSH;
- }
- else if (**s == '=')
- {
- *s += 1;
- op = BINOP_GEQ;
- }
- break;
- case '|':
- op = BINOP_BITWISE_IOR;
- if (**s == '|')
- {
- *s += 1;
- op = BINOP_LOGICAL_OR;
- }
- break;
- case '&':
- op = BINOP_BITWISE_AND;
- if (**s == '&')
- {
- *s += 1;
- op = BINOP_LOGICAL_AND;
- }
- break;
- case '^':
- op = BINOP_BITWISE_XOR;
- break;
- case '!':
- op = UNOP_LOGICAL_NOT;
- break;
- case '+':
- op = BINOP_ADD;
- break;
- case '-':
- op = BINOP_SUB;
- break;
- case '=':
- gdb_assert (**s == '=');
- op = BINOP_EQUAL;
- break;
- default:
- error (_("Invalid opcode in expression `%s' for SystemTap"
- "probe"), *s);
- }
- return op;
- }
- typedef expr::operation_up binop_maker_ftype (expr::operation_up &&,
- expr::operation_up &&);
- /* Map from an expression opcode to a function that can create a
- binary operation of that type. */
- static std::unordered_map<exp_opcode, binop_maker_ftype *,
- gdb::hash_enum<exp_opcode>> stap_maker_map;
- /* Helper function to create a binary operation. */
- static expr::operation_up
- stap_make_binop (enum exp_opcode opcode, expr::operation_up &&lhs,
- expr::operation_up &&rhs)
- {
- auto iter = stap_maker_map.find (opcode);
- gdb_assert (iter != stap_maker_map.end ());
- return iter->second (std::move (lhs), std::move (rhs));
- }
- /* Given the bitness of the argument, represented by B, return the
- corresponding `struct type *', or throw an error if B is
- unknown. */
- static struct type *
- stap_get_expected_argument_type (struct gdbarch *gdbarch,
- enum stap_arg_bitness b,
- const char *probe_name)
- {
- switch (b)
- {
- case STAP_ARG_BITNESS_UNDEFINED:
- if (gdbarch_addr_bit (gdbarch) == 32)
- return builtin_type (gdbarch)->builtin_uint32;
- else
- return builtin_type (gdbarch)->builtin_uint64;
- case STAP_ARG_BITNESS_8BIT_UNSIGNED:
- return builtin_type (gdbarch)->builtin_uint8;
- case STAP_ARG_BITNESS_8BIT_SIGNED:
- return builtin_type (gdbarch)->builtin_int8;
- case STAP_ARG_BITNESS_16BIT_UNSIGNED:
- return builtin_type (gdbarch)->builtin_uint16;
- case STAP_ARG_BITNESS_16BIT_SIGNED:
- return builtin_type (gdbarch)->builtin_int16;
- case STAP_ARG_BITNESS_32BIT_SIGNED:
- return builtin_type (gdbarch)->builtin_int32;
- case STAP_ARG_BITNESS_32BIT_UNSIGNED:
- return builtin_type (gdbarch)->builtin_uint32;
- case STAP_ARG_BITNESS_64BIT_SIGNED:
- return builtin_type (gdbarch)->builtin_int64;
- case STAP_ARG_BITNESS_64BIT_UNSIGNED:
- return builtin_type (gdbarch)->builtin_uint64;
- default:
- error (_("Undefined bitness for probe '%s'."), probe_name);
- break;
- }
- }
- /* Helper function to check for a generic list of prefixes. GDBARCH
- is the current gdbarch being used. S is the expression being
- analyzed. If R is not NULL, it will be used to return the found
- prefix. PREFIXES is the list of expected prefixes.
- This function does a case-insensitive match.
- Return true if any prefix has been found, false otherwise. */
- static bool
- stap_is_generic_prefix (struct gdbarch *gdbarch, const char *s,
- const char **r, const char *const *prefixes)
- {
- const char *const *p;
- if (prefixes == NULL)
- {
- if (r != NULL)
- *r = "";
- return true;
- }
- for (p = prefixes; *p != NULL; ++p)
- if (strncasecmp (s, *p, strlen (*p)) == 0)
- {
- if (r != NULL)
- *r = *p;
- return true;
- }
- return false;
- }
- /* Return true if S points to a register prefix, false otherwise. For
- a description of the arguments, look at stap_is_generic_prefix. */
- static bool
- stap_is_register_prefix (struct gdbarch *gdbarch, const char *s,
- const char **r)
- {
- const char *const *t = gdbarch_stap_register_prefixes (gdbarch);
- return stap_is_generic_prefix (gdbarch, s, r, t);
- }
- /* Return true if S points to a register indirection prefix, false
- otherwise. For a description of the arguments, look at
- stap_is_generic_prefix. */
- static bool
- stap_is_register_indirection_prefix (struct gdbarch *gdbarch, const char *s,
- const char **r)
- {
- const char *const *t = gdbarch_stap_register_indirection_prefixes (gdbarch);
- return stap_is_generic_prefix (gdbarch, s, r, t);
- }
- /* Return true if S points to an integer prefix, false otherwise. For
- a description of the arguments, look at stap_is_generic_prefix.
- This function takes care of analyzing whether we are dealing with
- an expected integer prefix, or, if there is no integer prefix to be
- expected, whether we are dealing with a digit. It does a
- case-insensitive match. */
- static bool
- stap_is_integer_prefix (struct gdbarch *gdbarch, const char *s,
- const char **r)
- {
- const char *const *t = gdbarch_stap_integer_prefixes (gdbarch);
- const char *const *p;
- if (t == NULL)
- {
- /* A NULL value here means that integers do not have a prefix.
- We just check for a digit then. */
- if (r != NULL)
- *r = "";
- return isdigit (*s) > 0;
- }
- for (p = t; *p != NULL; ++p)
- {
- size_t len = strlen (*p);
- if ((len == 0 && isdigit (*s))
- || (len > 0 && strncasecmp (s, *p, len) == 0))
- {
- /* Integers may or may not have a prefix. The "len == 0"
- check covers the case when integers do not have a prefix
- (therefore, we just check if we have a digit). The call
- to "strncasecmp" covers the case when they have a
- prefix. */
- if (r != NULL)
- *r = *p;
- return true;
- }
- }
- return false;
- }
- /* Helper function to check for a generic list of suffixes. If we are
- not expecting any suffixes, then it just returns 1. If we are
- expecting at least one suffix, then it returns true if a suffix has
- been found, false otherwise. GDBARCH is the current gdbarch being
- used. S is the expression being analyzed. If R is not NULL, it
- will be used to return the found suffix. SUFFIXES is the list of
- expected suffixes. This function does a case-insensitive
- match. */
- static bool
- stap_generic_check_suffix (struct gdbarch *gdbarch, const char *s,
- const char **r, const char *const *suffixes)
- {
- const char *const *p;
- bool found = false;
- if (suffixes == NULL)
- {
- if (r != NULL)
- *r = "";
- return true;
- }
- for (p = suffixes; *p != NULL; ++p)
- if (strncasecmp (s, *p, strlen (*p)) == 0)
- {
- if (r != NULL)
- *r = *p;
- found = true;
- break;
- }
- return found;
- }
- /* Return true if S points to an integer suffix, false otherwise. For
- a description of the arguments, look at
- stap_generic_check_suffix. */
- static bool
- stap_check_integer_suffix (struct gdbarch *gdbarch, const char *s,
- const char **r)
- {
- const char *const *p = gdbarch_stap_integer_suffixes (gdbarch);
- return stap_generic_check_suffix (gdbarch, s, r, p);
- }
- /* Return true if S points to a register suffix, false otherwise. For
- a description of the arguments, look at
- stap_generic_check_suffix. */
- static bool
- stap_check_register_suffix (struct gdbarch *gdbarch, const char *s,
- const char **r)
- {
- const char *const *p = gdbarch_stap_register_suffixes (gdbarch);
- return stap_generic_check_suffix (gdbarch, s, r, p);
- }
- /* Return true if S points to a register indirection suffix, false
- otherwise. For a description of the arguments, look at
- stap_generic_check_suffix. */
- static bool
- stap_check_register_indirection_suffix (struct gdbarch *gdbarch, const char *s,
- const char **r)
- {
- const char *const *p = gdbarch_stap_register_indirection_suffixes (gdbarch);
- return stap_generic_check_suffix (gdbarch, s, r, p);
- }
- /* Function responsible for parsing a register operand according to
- SystemTap parlance. Assuming:
- RP = register prefix
- RS = register suffix
- RIP = register indirection prefix
- RIS = register indirection suffix
-
- Then a register operand can be:
-
- [RIP] [RP] REGISTER [RS] [RIS]
- This function takes care of a register's indirection, displacement and
- direct access. It also takes into consideration the fact that some
- registers are named differently inside and outside GDB, e.g., PPC's
- general-purpose registers are represented by integers in the assembly
- language (e.g., `15' is the 15th general-purpose register), but inside
- GDB they have a prefix (the letter `r') appended. */
- static expr::operation_up
- stap_parse_register_operand (struct stap_parse_info *p)
- {
- /* Simple flag to indicate whether we have seen a minus signal before
- certain number. */
- bool got_minus = false;
- /* Flag to indicate whether this register access is being
- indirected. */
- bool indirect_p = false;
- struct gdbarch *gdbarch = p->gdbarch;
- /* Variables used to extract the register name from the probe's
- argument. */
- const char *start;
- const char *gdb_reg_prefix = gdbarch_stap_gdb_register_prefix (gdbarch);
- const char *gdb_reg_suffix = gdbarch_stap_gdb_register_suffix (gdbarch);
- const char *reg_prefix;
- const char *reg_ind_prefix;
- const char *reg_suffix;
- const char *reg_ind_suffix;
- using namespace expr;
- /* Checking for a displacement argument. */
- if (*p->arg == '+')
- {
- /* If it's a plus sign, we don't need to do anything, just advance the
- pointer. */
- ++p->arg;
- }
- else if (*p->arg == '-')
- {
- got_minus = true;
- ++p->arg;
- }
- struct type *long_type = builtin_type (gdbarch)->builtin_long;
- operation_up disp_op;
- if (isdigit (*p->arg))
- {
- /* The value of the displacement. */
- long displacement;
- char *endp;
- displacement = strtol (p->arg, &endp, 10);
- p->arg = endp;
- /* Generating the expression for the displacement. */
- if (got_minus)
- displacement = -displacement;
- disp_op = make_operation<long_const_operation> (long_type, displacement);
- }
- /* Getting rid of register indirection prefix. */
- if (stap_is_register_indirection_prefix (gdbarch, p->arg, ®_ind_prefix))
- {
- indirect_p = true;
- p->arg += strlen (reg_ind_prefix);
- }
- if (disp_op != nullptr && !indirect_p)
- error (_("Invalid register displacement syntax on expression `%s'."),
- p->saved_arg);
- /* Getting rid of register prefix. */
- if (stap_is_register_prefix (gdbarch, p->arg, ®_prefix))
- p->arg += strlen (reg_prefix);
- /* Now we should have only the register name. Let's extract it and get
- the associated number. */
- start = p->arg;
- /* We assume the register name is composed by letters and numbers. */
- while (isalnum (*p->arg))
- ++p->arg;
- std::string regname (start, p->arg - start);
- /* We only add the GDB's register prefix/suffix if we are dealing with
- a numeric register. */
- if (isdigit (*start))
- {
- if (gdb_reg_prefix != NULL)
- regname = gdb_reg_prefix + regname;
- if (gdb_reg_suffix != NULL)
- regname += gdb_reg_suffix;
- }
- int regnum = user_reg_map_name_to_regnum (gdbarch, regname.c_str (),
- regname.size ());
- /* Is this a valid register name? */
- if (regnum == -1)
- error (_("Invalid register name `%s' on expression `%s'."),
- regname.c_str (), p->saved_arg);
- /* Check if there's any special treatment that the arch-specific
- code would like to perform on the register name. */
- if (gdbarch_stap_adjust_register_p (gdbarch))
- {
- std::string newregname
- = gdbarch_stap_adjust_register (gdbarch, p, regname, regnum);
- if (regname != newregname)
- {
- /* This is just a check we perform to make sure that the
- arch-dependent code has provided us with a valid
- register name. */
- regnum = user_reg_map_name_to_regnum (gdbarch, newregname.c_str (),
- newregname.size ());
- if (regnum == -1)
- internal_error (__FILE__, __LINE__,
- _("Invalid register name '%s' after replacing it"
- " (previous name was '%s')"),
- newregname.c_str (), regname.c_str ());
- regname = std::move (newregname);
- }
- }
- operation_up reg = make_operation<register_operation> (std::move (regname));
- /* If the argument has been placed into a vector register then (for most
- architectures), the type of this register will be a union of arrays.
- As a result, attempting to cast from the register type to the scalar
- argument type will not be possible (GDB will throw an error during
- expression evaluation).
- The solution is to extract the scalar type from the value contents of
- the entire register value. */
- if (!is_scalar_type (gdbarch_register_type (gdbarch, regnum)))
- {
- gdb_assert (is_scalar_type (p->arg_type));
- reg = make_operation<unop_extract_operation> (std::move (reg),
- p->arg_type);
- }
- if (indirect_p)
- {
- if (disp_op != nullptr)
- reg = make_operation<add_operation> (std::move (disp_op),
- std::move (reg));
- /* Casting to the expected type. */
- struct type *arg_ptr_type = lookup_pointer_type (p->arg_type);
- reg = make_operation<unop_cast_operation> (std::move (reg),
- arg_ptr_type);
- reg = make_operation<unop_ind_operation> (std::move (reg));
- }
- /* Getting rid of the register name suffix. */
- if (stap_check_register_suffix (gdbarch, p->arg, ®_suffix))
- p->arg += strlen (reg_suffix);
- else
- error (_("Missing register name suffix on expression `%s'."),
- p->saved_arg);
- /* Getting rid of the register indirection suffix. */
- if (indirect_p)
- {
- if (stap_check_register_indirection_suffix (gdbarch, p->arg,
- ®_ind_suffix))
- p->arg += strlen (reg_ind_suffix);
- else
- error (_("Missing indirection suffix on expression `%s'."),
- p->saved_arg);
- }
- return reg;
- }
- /* This function is responsible for parsing a single operand.
- A single operand can be:
- - an unary operation (e.g., `-5', `~2', or even with subexpressions
- like `-(2 + 1)')
- - a register displacement, which will be treated as a register
- operand (e.g., `-4(%eax)' on x86)
- - a numeric constant, or
- - a register operand (see function `stap_parse_register_operand')
- The function also calls special-handling functions to deal with
- unrecognized operands, allowing arch-specific parsers to be
- created. */
- static expr::operation_up
- stap_parse_single_operand (struct stap_parse_info *p)
- {
- struct gdbarch *gdbarch = p->gdbarch;
- const char *int_prefix = NULL;
- using namespace expr;
- /* We first try to parse this token as a "special token". */
- if (gdbarch_stap_parse_special_token_p (gdbarch))
- {
- operation_up token = gdbarch_stap_parse_special_token (gdbarch, p);
- if (token != nullptr)
- return token;
- }
- struct type *long_type = builtin_type (gdbarch)->builtin_long;
- operation_up result;
- if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+' || *p->arg == '!')
- {
- char c = *p->arg;
- /* We use this variable to do a lookahead. */
- const char *tmp = p->arg;
- bool has_digit = false;
- /* Skipping signal. */
- ++tmp;
- /* This is an unary operation. Here is a list of allowed tokens
- here:
- - numeric literal;
- - number (from register displacement)
- - subexpression (beginning with `(')
- We handle the register displacement here, and the other cases
- recursively. */
- if (p->inside_paren_p)
- tmp = skip_spaces (tmp);
- while (isdigit (*tmp))
- {
- /* We skip the digit here because we are only interested in
- knowing what kind of unary operation this is. The digit
- will be handled by one of the functions that will be
- called below ('stap_parse_argument_conditionally' or
- 'stap_parse_register_operand'). */
- ++tmp;
- has_digit = true;
- }
- if (has_digit && stap_is_register_indirection_prefix (gdbarch, tmp,
- NULL))
- {
- /* If we are here, it means it is a displacement. The only
- operations allowed here are `-' and `+'. */
- if (c != '-' && c != '+')
- error (_("Invalid operator `%c' for register displacement "
- "on expression `%s'."), c, p->saved_arg);
- result = stap_parse_register_operand (p);
- }
- else
- {
- /* This is not a displacement. We skip the operator, and
- deal with it when the recursion returns. */
- ++p->arg;
- result = stap_parse_argument_conditionally (p);
- if (c == '-')
- result = make_operation<unary_neg_operation> (std::move (result));
- else if (c == '~')
- result = (make_operation<unary_complement_operation>
- (std::move (result)));
- else if (c == '!')
- result = (make_operation<unary_logical_not_operation>
- (std::move (result)));
- }
- }
- else if (isdigit (*p->arg))
- {
- /* A temporary variable, needed for lookahead. */
- const char *tmp = p->arg;
- char *endp;
- long number;
- /* We can be dealing with a numeric constant, or with a register
- displacement. */
- number = strtol (tmp, &endp, 10);
- tmp = endp;
- if (p->inside_paren_p)
- tmp = skip_spaces (tmp);
- /* If "stap_is_integer_prefix" returns true, it means we can
- accept integers without a prefix here. But we also need to
- check whether the next token (i.e., "tmp") is not a register
- indirection prefix. */
- if (stap_is_integer_prefix (gdbarch, p->arg, NULL)
- && !stap_is_register_indirection_prefix (gdbarch, tmp, NULL))
- {
- const char *int_suffix;
- /* We are dealing with a numeric constant. */
- result = make_operation<long_const_operation> (long_type, number);
- p->arg = tmp;
- if (stap_check_integer_suffix (gdbarch, p->arg, &int_suffix))
- p->arg += strlen (int_suffix);
- else
- error (_("Invalid constant suffix on expression `%s'."),
- p->saved_arg);
- }
- else if (stap_is_register_indirection_prefix (gdbarch, tmp, NULL))
- result = stap_parse_register_operand (p);
- else
- error (_("Unknown numeric token on expression `%s'."),
- p->saved_arg);
- }
- else if (stap_is_integer_prefix (gdbarch, p->arg, &int_prefix))
- {
- /* We are dealing with a numeric constant. */
- long number;
- char *endp;
- const char *int_suffix;
- p->arg += strlen (int_prefix);
- number = strtol (p->arg, &endp, 10);
- p->arg = endp;
- result = make_operation<long_const_operation> (long_type, number);
- if (stap_check_integer_suffix (gdbarch, p->arg, &int_suffix))
- p->arg += strlen (int_suffix);
- else
- error (_("Invalid constant suffix on expression `%s'."),
- p->saved_arg);
- }
- else if (stap_is_register_prefix (gdbarch, p->arg, NULL)
- || stap_is_register_indirection_prefix (gdbarch, p->arg, NULL))
- result = stap_parse_register_operand (p);
- else
- error (_("Operator `%c' not recognized on expression `%s'."),
- *p->arg, p->saved_arg);
- return result;
- }
- /* This function parses an argument conditionally, based on single or
- non-single operands. A non-single operand would be a parenthesized
- expression (e.g., `(2 + 1)'), and a single operand is anything that
- starts with `-', `~', `+' (i.e., unary operators), a digit, or
- something recognized by `gdbarch_stap_is_single_operand'. */
- static expr::operation_up
- stap_parse_argument_conditionally (struct stap_parse_info *p)
- {
- gdb_assert (gdbarch_stap_is_single_operand_p (p->gdbarch));
- expr::operation_up result;
- if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+' || *p->arg == '!'
- || isdigit (*p->arg)
- || gdbarch_stap_is_single_operand (p->gdbarch, p->arg))
- result = stap_parse_single_operand (p);
- else if (*p->arg == '(')
- {
- /* We are dealing with a parenthesized operand. It means we
- have to parse it as it was a separate expression, without
- left-side or precedence. */
- ++p->arg;
- p->arg = skip_spaces (p->arg);
- ++p->inside_paren_p;
- result = stap_parse_argument_1 (p, {}, STAP_OPERAND_PREC_NONE);
- p->arg = skip_spaces (p->arg);
- if (*p->arg != ')')
- error (_("Missing close-parenthesis on expression `%s'."),
- p->saved_arg);
- --p->inside_paren_p;
- ++p->arg;
- if (p->inside_paren_p)
- p->arg = skip_spaces (p->arg);
- }
- else
- error (_("Cannot parse expression `%s'."), p->saved_arg);
- return result;
- }
- /* Helper function for `stap_parse_argument'. Please, see its comments to
- better understand what this function does. */
- static expr::operation_up ATTRIBUTE_UNUSED_RESULT
- stap_parse_argument_1 (struct stap_parse_info *p,
- expr::operation_up &&lhs_in,
- enum stap_operand_prec prec)
- {
- /* This is an operator-precedence parser.
- We work with left- and right-sides of expressions, and
- parse them depending on the precedence of the operators
- we find. */
- gdb_assert (p->arg != NULL);
- if (p->inside_paren_p)
- p->arg = skip_spaces (p->arg);
- using namespace expr;
- operation_up lhs = std::move (lhs_in);
- if (lhs == nullptr)
- {
- /* We were called without a left-side, either because this is the
- first call, or because we were called to parse a parenthesized
- expression. It doesn't really matter; we have to parse the
- left-side in order to continue the process. */
- lhs = stap_parse_argument_conditionally (p);
- }
- if (p->inside_paren_p)
- p->arg = skip_spaces (p->arg);
- /* Start to parse the right-side, and to "join" left and right sides
- depending on the operation specified.
- This loop shall continue until we run out of characters in the input,
- or until we find a close-parenthesis, which means that we've reached
- the end of a sub-expression. */
- while (*p->arg != '\0' && *p->arg != ')' && !isspace (*p->arg))
- {
- const char *tmp_exp_buf;
- enum exp_opcode opcode;
- enum stap_operand_prec cur_prec;
- if (!stap_is_operator (p->arg))
- error (_("Invalid operator `%c' on expression `%s'."), *p->arg,
- p->saved_arg);
- /* We have to save the current value of the expression buffer because
- the `stap_get_opcode' modifies it in order to get the current
- operator. If this operator's precedence is lower than PREC, we
- should return and not advance the expression buffer pointer. */
- tmp_exp_buf = p->arg;
- opcode = stap_get_opcode (&tmp_exp_buf);
- cur_prec = stap_get_operator_prec (opcode);
- if (cur_prec < prec)
- {
- /* If the precedence of the operator that we are seeing now is
- lower than the precedence of the first operator seen before
- this parsing process began, it means we should stop parsing
- and return. */
- break;
- }
- p->arg = tmp_exp_buf;
- if (p->inside_paren_p)
- p->arg = skip_spaces (p->arg);
- /* Parse the right-side of the expression.
- We save whether the right-side is a parenthesized
- subexpression because, if it is, we will have to finish
- processing this part of the expression before continuing. */
- bool paren_subexp = *p->arg == '(';
- operation_up rhs = stap_parse_argument_conditionally (p);
- if (p->inside_paren_p)
- p->arg = skip_spaces (p->arg);
- if (paren_subexp)
- {
- lhs = stap_make_binop (opcode, std::move (lhs), std::move (rhs));
- continue;
- }
- /* While we still have operators, try to parse another
- right-side, but using the current right-side as a left-side. */
- while (*p->arg != '\0' && stap_is_operator (p->arg))
- {
- enum exp_opcode lookahead_opcode;
- enum stap_operand_prec lookahead_prec;
- /* Saving the current expression buffer position. The explanation
- is the same as above. */
- tmp_exp_buf = p->arg;
- lookahead_opcode = stap_get_opcode (&tmp_exp_buf);
- lookahead_prec = stap_get_operator_prec (lookahead_opcode);
- if (lookahead_prec <= prec)
- {
- /* If we are dealing with an operator whose precedence is lower
- than the first one, just abandon the attempt. */
- break;
- }
- /* Parse the right-side of the expression, using the current
- right-hand-side as the left-hand-side of the new
- subexpression. */
- rhs = stap_parse_argument_1 (p, std::move (rhs), lookahead_prec);
- if (p->inside_paren_p)
- p->arg = skip_spaces (p->arg);
- }
- lhs = stap_make_binop (opcode, std::move (lhs), std::move (rhs));
- }
- return lhs;
- }
- /* Parse a probe's argument.
- Assuming that:
- LP = literal integer prefix
- LS = literal integer suffix
- RP = register prefix
- RS = register suffix
- RIP = register indirection prefix
- RIS = register indirection suffix
- This routine assumes that arguments' tokens are of the form:
- - [LP] NUMBER [LS]
- - [RP] REGISTER [RS]
- - [RIP] [RP] REGISTER [RS] [RIS]
- - If we find a number without LP, we try to parse it as a literal integer
- constant (if LP == NULL), or as a register displacement.
- - We count parenthesis, and only skip whitespaces if we are inside them.
- - If we find an operator, we skip it.
- This function can also call a special function that will try to match
- unknown tokens. It will return the expression_up generated from
- parsing the argument. */
- static expression_up
- stap_parse_argument (const char **arg, struct type *atype,
- struct gdbarch *gdbarch)
- {
- /* We need to initialize the expression buffer, in order to begin
- our parsing efforts. We use language_c here because we may need
- to do pointer arithmetics. */
- struct stap_parse_info p (*arg, atype, language_def (language_c),
- gdbarch);
- using namespace expr;
- operation_up result = stap_parse_argument_1 (&p, {}, STAP_OPERAND_PREC_NONE);
- gdb_assert (p.inside_paren_p == 0);
- /* Casting the final expression to the appropriate type. */
- result = make_operation<unop_cast_operation> (std::move (result), atype);
- p.pstate.set_operation (std::move (result));
- p.arg = skip_spaces (p.arg);
- *arg = p.arg;
- return p.pstate.release ();
- }
- /* Implementation of 'parse_arguments' method. */
- void
- stap_probe::parse_arguments (struct gdbarch *gdbarch)
- {
- const char *cur;
- gdb_assert (!m_have_parsed_args);
- cur = m_unparsed_args_text;
- m_have_parsed_args = true;
- if (cur == NULL || *cur == '\0' || *cur == ':')
- return;
- while (*cur != '\0')
- {
- enum stap_arg_bitness bitness;
- bool got_minus = false;
- /* We expect to find something like:
- N@OP
- Where `N' can be [+,-][1,2,4,8]. This is not mandatory, so
- we check it here. If we don't find it, go to the next
- state. */
- if ((cur[0] == '-' && isdigit (cur[1]) && cur[2] == '@')
- || (isdigit (cur[0]) && cur[1] == '@'))
- {
- if (*cur == '-')
- {
- /* Discard the `-'. */
- ++cur;
- got_minus = true;
- }
- /* Defining the bitness. */
- switch (*cur)
- {
- case '1':
- bitness = (got_minus ? STAP_ARG_BITNESS_8BIT_SIGNED
- : STAP_ARG_BITNESS_8BIT_UNSIGNED);
- break;
- case '2':
- bitness = (got_minus ? STAP_ARG_BITNESS_16BIT_SIGNED
- : STAP_ARG_BITNESS_16BIT_UNSIGNED);
- break;
- case '4':
- bitness = (got_minus ? STAP_ARG_BITNESS_32BIT_SIGNED
- : STAP_ARG_BITNESS_32BIT_UNSIGNED);
- break;
- case '8':
- bitness = (got_minus ? STAP_ARG_BITNESS_64BIT_SIGNED
- : STAP_ARG_BITNESS_64BIT_UNSIGNED);
- break;
- default:
- {
- /* We have an error, because we don't expect anything
- except 1, 2, 4 and 8. */
- warning (_("unrecognized bitness %s%c' for probe `%s'"),
- got_minus ? "`-" : "`", *cur,
- this->get_name ().c_str ());
- return;
- }
- }
- /* Discard the number and the `@' sign. */
- cur += 2;
- }
- else
- bitness = STAP_ARG_BITNESS_UNDEFINED;
- struct type *atype
- = stap_get_expected_argument_type (gdbarch, bitness,
- this->get_name ().c_str ());
- expression_up expr = stap_parse_argument (&cur, atype, gdbarch);
- if (stap_expression_debug)
- dump_prefix_expression (expr.get (), gdb_stdlog);
- m_parsed_args.emplace_back (bitness, atype, std::move (expr));
- /* Start it over again. */
- cur = skip_spaces (cur);
- }
- }
- /* Helper function to relocate an address. */
- static CORE_ADDR
- relocate_address (CORE_ADDR address, struct objfile *objfile)
- {
- return address + objfile->text_section_offset ();
- }
- /* Implementation of the get_relocated_address method. */
- CORE_ADDR
- stap_probe::get_relocated_address (struct objfile *objfile)
- {
- return relocate_address (this->get_address (), objfile);
- }
- /* Given PROBE, returns the number of arguments present in that probe's
- argument string. */
- unsigned
- stap_probe::get_argument_count (struct gdbarch *gdbarch)
- {
- if (!m_have_parsed_args)
- {
- if (this->can_evaluate_arguments ())
- this->parse_arguments (gdbarch);
- else
- {
- static bool have_warned_stap_incomplete = false;
- if (!have_warned_stap_incomplete)
- {
- warning (_(
- "The SystemTap SDT probe support is not fully implemented on this target;\n"
- "you will not be able to inspect the arguments of the probes.\n"
- "Please report a bug against GDB requesting a port to this target."));
- have_warned_stap_incomplete = true;
- }
- /* Marking the arguments as "already parsed". */
- m_have_parsed_args = true;
- }
- }
- gdb_assert (m_have_parsed_args);
- return m_parsed_args.size ();
- }
- /* Return true if OP is a valid operator inside a probe argument, or
- false otherwise. */
- static bool
- stap_is_operator (const char *op)
- {
- bool ret = true;
- switch (*op)
- {
- case '*':
- case '/':
- case '%':
- case '^':
- case '!':
- case '+':
- case '-':
- case '<':
- case '>':
- case '|':
- case '&':
- break;
- case '=':
- if (op[1] != '=')
- ret = false;
- break;
- default:
- /* We didn't find any operator. */
- ret = false;
- }
- return ret;
- }
- /* Implement the `can_evaluate_arguments' method. */
- bool
- stap_probe::can_evaluate_arguments () const
- {
- struct gdbarch *gdbarch = this->get_gdbarch ();
- /* For SystemTap probes, we have to guarantee that the method
- stap_is_single_operand is defined on gdbarch. If it is not, then it
- means that argument evaluation is not implemented on this target. */
- return gdbarch_stap_is_single_operand_p (gdbarch);
- }
- /* Evaluate the probe's argument N (indexed from 0), returning a value
- corresponding to it. Assertion is thrown if N does not exist. */
- struct value *
- stap_probe::evaluate_argument (unsigned n, struct frame_info *frame)
- {
- struct stap_probe_arg *arg;
- struct gdbarch *gdbarch = get_frame_arch (frame);
- arg = this->get_arg_by_number (n, gdbarch);
- return evaluate_expression (arg->aexpr.get (), arg->atype);
- }
- /* Compile the probe's argument N (indexed from 0) to agent expression.
- Assertion is thrown if N does not exist. */
- void
- stap_probe::compile_to_ax (struct agent_expr *expr, struct axs_value *value,
- unsigned n)
- {
- struct stap_probe_arg *arg;
- arg = this->get_arg_by_number (n, expr->gdbarch);
- arg->aexpr->op->generate_ax (arg->aexpr.get (), expr, value);
- require_rvalue (expr, value);
- value->type = arg->atype;
- }
- /* Set or clear a SystemTap semaphore. ADDRESS is the semaphore's
- address. SET is zero if the semaphore should be cleared, or one if
- it should be set. This is a helper function for
- 'stap_probe::set_semaphore' and 'stap_probe::clear_semaphore'. */
- static void
- stap_modify_semaphore (CORE_ADDR address, int set, struct gdbarch *gdbarch)
- {
- gdb_byte bytes[sizeof (LONGEST)];
- /* The ABI specifies "unsigned short". */
- struct type *type = builtin_type (gdbarch)->builtin_unsigned_short;
- ULONGEST value;
- /* Swallow errors. */
- if (target_read_memory (address, bytes, TYPE_LENGTH (type)) != 0)
- {
- warning (_("Could not read the value of a SystemTap semaphore."));
- return;
- }
- enum bfd_endian byte_order = type_byte_order (type);
- value = extract_unsigned_integer (bytes, TYPE_LENGTH (type), byte_order);
- /* Note that we explicitly don't worry about overflow or
- underflow. */
- if (set)
- ++value;
- else
- --value;
- store_unsigned_integer (bytes, TYPE_LENGTH (type), byte_order, value);
- if (target_write_memory (address, bytes, TYPE_LENGTH (type)) != 0)
- warning (_("Could not write the value of a SystemTap semaphore."));
- }
- /* Implementation of the 'set_semaphore' method.
- SystemTap semaphores act as reference counters, so calls to this
- function must be paired with calls to 'clear_semaphore'.
- This function and 'clear_semaphore' race with another tool
- changing the probes, but that is too rare to care. */
- void
- stap_probe::set_semaphore (struct objfile *objfile, struct gdbarch *gdbarch)
- {
- if (m_sem_addr == 0)
- return;
- stap_modify_semaphore (relocate_address (m_sem_addr, objfile), 1, gdbarch);
- }
- /* Implementation of the 'clear_semaphore' method. */
- void
- stap_probe::clear_semaphore (struct objfile *objfile, struct gdbarch *gdbarch)
- {
- if (m_sem_addr == 0)
- return;
- stap_modify_semaphore (relocate_address (m_sem_addr, objfile), 0, gdbarch);
- }
- /* Implementation of the 'get_static_ops' method. */
- const static_probe_ops *
- stap_probe::get_static_ops () const
- {
- return &stap_static_probe_ops;
- }
- /* Implementation of the 'gen_info_probes_table_values' method. */
- std::vector<const char *>
- stap_probe::gen_info_probes_table_values () const
- {
- const char *val = NULL;
- if (m_sem_addr != 0)
- val = print_core_address (this->get_gdbarch (), m_sem_addr);
- return std::vector<const char *> { val };
- }
- /* Helper function that parses the information contained in a
- SystemTap's probe. Basically, the information consists in:
- - Probe's PC address;
- - Link-time section address of `.stapsdt.base' section;
- - Link-time address of the semaphore variable, or ZERO if the
- probe doesn't have an associated semaphore;
- - Probe's provider name;
- - Probe's name;
- - Probe's argument format. */
- static void
- handle_stap_probe (struct objfile *objfile, struct sdt_note *el,
- std::vector<std::unique_ptr<probe>> *probesp,
- CORE_ADDR base)
- {
- bfd *abfd = objfile->obfd;
- int size = bfd_get_arch_size (abfd) / 8;
- struct gdbarch *gdbarch = objfile->arch ();
- struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
- /* Provider and the name of the probe. */
- const char *provider = (const char *) &el->data[3 * size];
- const char *name = ((const char *)
- memchr (provider, '\0',
- (char *) el->data + el->size - provider));
- /* Making sure there is a name. */
- if (name == NULL)
- {
- complaint (_("corrupt probe name when reading `%s'"),
- objfile_name (objfile));
- /* There is no way to use a probe without a name or a provider, so
- returning here makes sense. */
- return;
- }
- else
- ++name;
- /* Retrieving the probe's address. */
- CORE_ADDR address = extract_typed_address (&el->data[0], ptr_type);
- /* Link-time sh_addr of `.stapsdt.base' section. */
- CORE_ADDR base_ref = extract_typed_address (&el->data[size], ptr_type);
- /* Semaphore address. */
- CORE_ADDR sem_addr = extract_typed_address (&el->data[2 * size], ptr_type);
- address += base - base_ref;
- if (sem_addr != 0)
- sem_addr += base - base_ref;
- /* Arguments. We can only extract the argument format if there is a valid
- name for this probe. */
- const char *probe_args = ((const char*)
- memchr (name, '\0',
- (char *) el->data + el->size - name));
- if (probe_args != NULL)
- ++probe_args;
- if (probe_args == NULL
- || (memchr (probe_args, '\0', (char *) el->data + el->size - name)
- != el->data + el->size - 1))
- {
- complaint (_("corrupt probe argument when reading `%s'"),
- objfile_name (objfile));
- /* If the argument string is NULL, it means some problem happened with
- it. So we return. */
- return;
- }
- stap_probe *ret = new stap_probe (std::string (name), std::string (provider),
- address, gdbarch, sem_addr, probe_args);
- /* Successfully created probe. */
- probesp->emplace_back (ret);
- }
- /* Helper function which iterates over every section in the BFD file,
- trying to find the base address of the SystemTap base section.
- Returns 1 if found (setting BASE to the proper value), zero otherwise. */
- static int
- get_stap_base_address (bfd *obfd, bfd_vma *base)
- {
- asection *ret = NULL;
- for (asection *sect : gdb_bfd_sections (obfd))
- if ((sect->flags & (SEC_DATA | SEC_ALLOC | SEC_HAS_CONTENTS))
- && sect->name && !strcmp (sect->name, STAP_BASE_SECTION_NAME))
- ret = sect;
- if (ret == NULL)
- {
- complaint (_("could not obtain base address for "
- "SystemTap section on objfile `%s'."),
- bfd_get_filename (obfd));
- return 0;
- }
- if (base != NULL)
- *base = ret->vma;
- return 1;
- }
- /* Implementation of the 'is_linespec' method. */
- bool
- stap_static_probe_ops::is_linespec (const char **linespecp) const
- {
- static const char *const keywords[] = { "-pstap", "-probe-stap", NULL };
- return probe_is_linespec_by_keyword (linespecp, keywords);
- }
- /* Implementation of the 'get_probes' method. */
- void
- stap_static_probe_ops::get_probes
- (std::vector<std::unique_ptr<probe>> *probesp,
- struct objfile *objfile) const
- {
- /* If we are here, then this is the first time we are parsing the
- SystemTap probe's information. We basically have to count how many
- probes the objfile has, and then fill in the necessary information
- for each one. */
- bfd *obfd = objfile->obfd;
- bfd_vma base;
- struct sdt_note *iter;
- unsigned save_probesp_len = probesp->size ();
- if (objfile->separate_debug_objfile_backlink != NULL)
- {
- /* This is a .debug file, not the objfile itself. */
- return;
- }
- if (elf_tdata (obfd)->sdt_note_head == NULL)
- {
- /* There isn't any probe here. */
- return;
- }
- if (!get_stap_base_address (obfd, &base))
- {
- /* There was an error finding the base address for the section.
- Just return NULL. */
- return;
- }
- /* Parsing each probe's information. */
- for (iter = elf_tdata (obfd)->sdt_note_head;
- iter != NULL;
- iter = iter->next)
- {
- /* We first have to handle all the information about the
- probe which is present in the section. */
- handle_stap_probe (objfile, iter, probesp, base);
- }
- if (save_probesp_len == probesp->size ())
- {
- /* If we are here, it means we have failed to parse every known
- probe. */
- complaint (_("could not parse SystemTap probe(s) from inferior"));
- return;
- }
- }
- /* Implementation of the type_name method. */
- const char *
- stap_static_probe_ops::type_name () const
- {
- return "stap";
- }
- /* Implementation of the 'gen_info_probes_table_header' method. */
- std::vector<struct info_probe_column>
- stap_static_probe_ops::gen_info_probes_table_header () const
- {
- struct info_probe_column stap_probe_column;
- stap_probe_column.field_name = "semaphore";
- stap_probe_column.print_name = _("Semaphore");
- return std::vector<struct info_probe_column> { stap_probe_column };
- }
- /* Implementation of the `info probes stap' command. */
- static void
- info_probes_stap_command (const char *arg, int from_tty)
- {
- info_probes_for_spops (arg, from_tty, &stap_static_probe_ops);
- }
- void _initialize_stap_probe ();
- void
- _initialize_stap_probe ()
- {
- all_static_probe_ops.push_back (&stap_static_probe_ops);
- add_setshow_zuinteger_cmd ("stap-expression", class_maintenance,
- &stap_expression_debug,
- _("Set SystemTap expression debugging."),
- _("Show SystemTap expression debugging."),
- _("When non-zero, the internal representation "
- "of SystemTap expressions will be printed."),
- NULL,
- show_stapexpressiondebug,
- &setdebuglist, &showdebuglist);
- add_cmd ("stap", class_info, info_probes_stap_command,
- _("\
- Show information about SystemTap static probes.\n\
- Usage: info probes stap [PROVIDER [NAME [OBJECT]]]\n\
- Each argument is a regular expression, used to select probes.\n\
- PROVIDER matches probe provider names.\n\
- NAME matches the probe names.\n\
- OBJECT matches the executable or shared library name."),
- info_probes_cmdlist_get ());
- using namespace expr;
- stap_maker_map[BINOP_ADD] = make_operation<add_operation>;
- stap_maker_map[BINOP_BITWISE_AND] = make_operation<bitwise_and_operation>;
- stap_maker_map[BINOP_BITWISE_IOR] = make_operation<bitwise_ior_operation>;
- stap_maker_map[BINOP_BITWISE_XOR] = make_operation<bitwise_xor_operation>;
- stap_maker_map[BINOP_DIV] = make_operation<div_operation>;
- stap_maker_map[BINOP_EQUAL] = make_operation<equal_operation>;
- stap_maker_map[BINOP_GEQ] = make_operation<geq_operation>;
- stap_maker_map[BINOP_GTR] = make_operation<gtr_operation>;
- stap_maker_map[BINOP_LEQ] = make_operation<leq_operation>;
- stap_maker_map[BINOP_LESS] = make_operation<less_operation>;
- stap_maker_map[BINOP_LOGICAL_AND] = make_operation<logical_and_operation>;
- stap_maker_map[BINOP_LOGICAL_OR] = make_operation<logical_or_operation>;
- stap_maker_map[BINOP_LSH] = make_operation<lsh_operation>;
- stap_maker_map[BINOP_MUL] = make_operation<mul_operation>;
- stap_maker_map[BINOP_NOTEQUAL] = make_operation<notequal_operation>;
- stap_maker_map[BINOP_REM] = make_operation<rem_operation>;
- stap_maker_map[BINOP_RSH] = make_operation<rsh_operation>;
- stap_maker_map[BINOP_SUB] = make_operation<sub_operation>;
- }
|