1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700 |
- /* General utility routines for GDB, the GNU debugger.
- Copyright (C) 1986-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 <ctype.h>
- #include "gdbsupport/gdb_wait.h"
- #include "event-top.h"
- #include "gdbthread.h"
- #include "fnmatch.h"
- #include "gdb_bfd.h"
- #ifdef HAVE_SYS_RESOURCE_H
- #include <sys/resource.h>
- #endif /* HAVE_SYS_RESOURCE_H */
- #ifdef TUI
- #include "tui/tui.h" /* For tui_get_command_dimension. */
- #endif
- #ifdef __GO32__
- #include <pc.h>
- #endif
- #include <signal.h>
- #include "gdbcmd.h"
- #include "serial.h"
- #include "bfd.h"
- #include "target.h"
- #include "gdb-demangle.h"
- #include "expression.h"
- #include "language.h"
- #include "charset.h"
- #include "annotate.h"
- #include "filenames.h"
- #include "symfile.h"
- #include "gdbsupport/gdb_obstack.h"
- #include "gdbcore.h"
- #include "top.h"
- #include "main.h"
- #include "solist.h"
- #include "inferior.h" /* for signed_pointer_to_address */
- #include "gdb_curses.h"
- #include "readline/readline.h"
- #include <chrono>
- #include "interps.h"
- #include "gdbsupport/gdb_regex.h"
- #include "gdbsupport/job-control.h"
- #include "gdbsupport/selftest.h"
- #include "gdbsupport/gdb_optional.h"
- #include "cp-support.h"
- #include <algorithm>
- #include "gdbsupport/pathstuff.h"
- #include "cli/cli-style.h"
- #include "gdbsupport/scope-exit.h"
- #include "gdbarch.h"
- #include "cli-out.h"
- #include "gdbsupport/gdb-safe-ctype.h"
- #include "bt-utils.h"
- #include "gdbsupport/buildargv.h"
- #include "pager.h"
- #include "run-on-main-thread.h"
- void (*deprecated_error_begin_hook) (void);
- /* Prototypes for local functions */
- static void set_screen_size (void);
- static void set_width (void);
- /* Time spent in prompt_for_continue in the currently executing command
- waiting for user to respond.
- Initialized in make_command_stats_cleanup.
- Modified in prompt_for_continue and defaulted_query.
- Used in report_command_stats. */
- static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
- /* A flag indicating whether to timestamp debugging messages. */
- bool debug_timestamp = false;
- /* True means that strings with character values >0x7F should be printed
- as octal escapes. False means just print the value (e.g. it's an
- international character, and the terminal or window can cope.) */
- bool sevenbit_strings = false;
- static void
- show_sevenbit_strings (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("Printing of 8-bit characters "
- "in strings as \\nnn is %s.\n"),
- value);
- }
- /* String to be printed before warning messages, if any. */
- const char *warning_pre_print = "\nwarning: ";
- bool pagination_enabled = true;
- static void
- show_pagination_enabled (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("State of pagination is %s.\n"), value);
- }
- /* Print a warning message. The first argument STRING is the warning
- message, used as an fprintf format string, the second is the
- va_list of arguments for that string. A warning is unfiltered (not
- paginated) so that the user does not need to page through each
- screen full of warnings when there are lots of them. */
- void
- vwarning (const char *string, va_list args)
- {
- if (deprecated_warning_hook)
- (*deprecated_warning_hook) (string, args);
- else
- {
- gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
- if (target_supports_terminal_ours ())
- {
- term_state.emplace ();
- target_terminal::ours_for_output ();
- }
- if (warning_pre_print)
- gdb_puts (warning_pre_print, gdb_stderr);
- gdb_vprintf (gdb_stderr, string, args);
- gdb_printf (gdb_stderr, "\n");
- }
- }
- /* Print an error message and return to command level.
- The first argument STRING is the error message, used as a fprintf string,
- and the remaining args are passed as arguments to it. */
- void
- verror (const char *string, va_list args)
- {
- throw_verror (GENERIC_ERROR, string, args);
- }
- void
- error_stream (const string_file &stream)
- {
- error (("%s"), stream.c_str ());
- }
- /* Emit a message and abort. */
- static void ATTRIBUTE_NORETURN
- abort_with_message (const char *msg)
- {
- if (current_ui == NULL)
- fputs (msg, stderr);
- else
- gdb_puts (msg, gdb_stderr);
- abort (); /* ARI: abort */
- }
- /* Dump core trying to increase the core soft limit to hard limit first. */
- void
- dump_core (void)
- {
- #ifdef HAVE_SETRLIMIT
- struct rlimit rlim = { (rlim_t) RLIM_INFINITY, (rlim_t) RLIM_INFINITY };
- setrlimit (RLIMIT_CORE, &rlim);
- #endif /* HAVE_SETRLIMIT */
- /* Ensure that the SIGABRT we're about to raise will immediately cause
- GDB to exit and dump core, we don't want to trigger GDB's printing of
- a backtrace to the console here. */
- signal (SIGABRT, SIG_DFL);
- abort (); /* ARI: abort */
- }
- /* Check whether GDB will be able to dump core using the dump_core
- function. Returns zero if GDB cannot or should not dump core.
- If LIMIT_KIND is LIMIT_CUR the user's soft limit will be respected.
- If LIMIT_KIND is LIMIT_MAX only the hard limit will be respected. */
- int
- can_dump_core (enum resource_limit_kind limit_kind)
- {
- #ifdef HAVE_GETRLIMIT
- struct rlimit rlim;
- /* Be quiet and assume we can dump if an error is returned. */
- if (getrlimit (RLIMIT_CORE, &rlim) != 0)
- return 1;
- switch (limit_kind)
- {
- case LIMIT_CUR:
- if (rlim.rlim_cur == 0)
- return 0;
- /* Fall through. */
- case LIMIT_MAX:
- if (rlim.rlim_max == 0)
- return 0;
- }
- #endif /* HAVE_GETRLIMIT */
- return 1;
- }
- /* Print a warning that we cannot dump core. */
- void
- warn_cant_dump_core (const char *reason)
- {
- gdb_printf (gdb_stderr,
- _("%s\nUnable to dump core, use `ulimit -c"
- " unlimited' before executing GDB next time.\n"),
- reason);
- }
- /* Check whether GDB will be able to dump core using the dump_core
- function, and print a warning if we cannot. */
- static int
- can_dump_core_warn (enum resource_limit_kind limit_kind,
- const char *reason)
- {
- int core_dump_allowed = can_dump_core (limit_kind);
- if (!core_dump_allowed)
- warn_cant_dump_core (reason);
- return core_dump_allowed;
- }
- /* Allow the user to configure the debugger behavior with respect to
- what to do when an internal problem is detected. */
- const char internal_problem_ask[] = "ask";
- const char internal_problem_yes[] = "yes";
- const char internal_problem_no[] = "no";
- static const char *const internal_problem_modes[] =
- {
- internal_problem_ask,
- internal_problem_yes,
- internal_problem_no,
- NULL
- };
- /* Data structure used to control how the internal_vproblem function
- should behave. An instance of this structure is created for each
- problem type that GDB supports. */
- struct internal_problem
- {
- /* The name of this problem type. This must not contain white space as
- this string is used to build command names. */
- const char *name;
- /* When this is true then a user command is created (based on NAME) that
- allows the SHOULD_QUIT field to be modified, otherwise, SHOULD_QUIT
- can't be changed from its default value by the user. */
- bool user_settable_should_quit;
- /* Reference a value from internal_problem_modes to indicate if GDB
- should quit when it hits a problem of this type. */
- const char *should_quit;
- /* Like USER_SETTABLE_SHOULD_QUIT but for SHOULD_DUMP_CORE. */
- bool user_settable_should_dump_core;
- /* Like SHOULD_QUIT, but whether GDB should dump core. */
- const char *should_dump_core;
- /* Like USER_SETTABLE_SHOULD_QUIT but for SHOULD_PRINT_BACKTRACE. */
- bool user_settable_should_print_backtrace;
- /* When this is true GDB will print a backtrace when a problem of this
- type is encountered. */
- bool should_print_backtrace;
- };
- /* Return true if the readline callbacks have been initialized for UI.
- This is always true once GDB is fully initialized, but during the early
- startup phase this is initially false. */
- static bool
- readline_initialized (struct ui *ui)
- {
- return ui->call_readline != nullptr;
- }
- /* Report a problem, internal to GDB, to the user. Once the problem
- has been reported, and assuming GDB didn't quit, the caller can
- either allow execution to resume or throw an error. */
- static void ATTRIBUTE_PRINTF (4, 0)
- internal_vproblem (struct internal_problem *problem,
- const char *file, int line, const char *fmt, va_list ap)
- {
- static int dejavu;
- int quit_p;
- int dump_core_p;
- std::string reason;
- /* Don't allow infinite error/warning recursion. */
- {
- static const char msg[] = "Recursive internal problem.\n";
- switch (dejavu)
- {
- case 0:
- dejavu = 1;
- break;
- case 1:
- dejavu = 2;
- abort_with_message (msg);
- default:
- dejavu = 3;
- /* Newer GLIBC versions put the warn_unused_result attribute
- on write, but this is one of those rare cases where
- ignoring the return value is correct. Casting to (void)
- does not fix this problem. This is the solution suggested
- at http://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509. */
- if (write (STDERR_FILENO, msg, sizeof (msg)) != sizeof (msg))
- abort (); /* ARI: abort */
- exit (1);
- }
- }
- /* Create a string containing the full error/warning message. Need
- to call query with this full string, as otherwize the reason
- (error/warning) and question become separated. Format using a
- style similar to a compiler error message. Include extra detail
- so that the user knows that they are living on the edge. */
- {
- std::string msg = string_vprintf (fmt, ap);
- reason = string_printf ("%s:%d: %s: %s\n"
- "A problem internal to GDB has been detected,\n"
- "further debugging may prove unreliable.",
- file, line, problem->name, msg.c_str ());
- }
- /* Fall back to abort_with_message if gdb_stderr is not set up. */
- if (current_ui == NULL)
- {
- fputs (reason.c_str (), stderr);
- abort_with_message ("\n");
- }
- /* Try to get the message out and at the start of a new line. */
- gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
- if (target_supports_terminal_ours ())
- {
- term_state.emplace ();
- target_terminal::ours_for_output ();
- }
- if (filtered_printing_initialized ())
- begin_line ();
- /* Emit the message unless query will emit it below. */
- if (problem->should_quit != internal_problem_ask
- || !confirm
- || !filtered_printing_initialized ()
- || !readline_initialized (current_ui)
- || problem->should_print_backtrace)
- gdb_printf (gdb_stderr, "%s\n", reason.c_str ());
- if (problem->should_print_backtrace)
- gdb_internal_backtrace ();
- if (problem->should_quit == internal_problem_ask)
- {
- /* Default (yes/batch case) is to quit GDB. When in batch mode
- this lessens the likelihood of GDB going into an infinite
- loop. */
- if (!confirm || !filtered_printing_initialized ()
- || !readline_initialized (current_ui))
- quit_p = 1;
- else
- quit_p = query (_("%s\nQuit this debugging session? "),
- reason.c_str ());
- }
- else if (problem->should_quit == internal_problem_yes)
- quit_p = 1;
- else if (problem->should_quit == internal_problem_no)
- quit_p = 0;
- else
- internal_error (__FILE__, __LINE__, _("bad switch"));
- gdb_puts (_("\nThis is a bug, please report it."), gdb_stderr);
- if (REPORT_BUGS_TO[0])
- gdb_printf (gdb_stderr, _(" For instructions, see:\n%ps."),
- styled_string (file_name_style.style (),
- REPORT_BUGS_TO));
- gdb_puts ("\n\n", gdb_stderr);
- if (problem->should_dump_core == internal_problem_ask)
- {
- if (!can_dump_core_warn (LIMIT_MAX, reason.c_str ()))
- dump_core_p = 0;
- else if (!filtered_printing_initialized ()
- || !readline_initialized (current_ui))
- dump_core_p = 1;
- else
- {
- /* Default (yes/batch case) is to dump core. This leaves a GDB
- `dropping' so that it is easier to see that something went
- wrong in GDB. */
- dump_core_p = query (_("%s\nCreate a core file of GDB? "),
- reason.c_str ());
- }
- }
- else if (problem->should_dump_core == internal_problem_yes)
- dump_core_p = can_dump_core_warn (LIMIT_MAX, reason.c_str ());
- else if (problem->should_dump_core == internal_problem_no)
- dump_core_p = 0;
- else
- internal_error (__FILE__, __LINE__, _("bad switch"));
- if (quit_p)
- {
- if (dump_core_p)
- dump_core ();
- else
- exit (1);
- }
- else
- {
- if (dump_core_p)
- {
- #ifdef HAVE_WORKING_FORK
- if (fork () == 0)
- dump_core ();
- #endif
- }
- }
- dejavu = 0;
- }
- static struct internal_problem internal_error_problem = {
- "internal-error", true, internal_problem_ask, true, internal_problem_ask,
- true, GDB_PRINT_INTERNAL_BACKTRACE_INIT_ON
- };
- void
- internal_verror (const char *file, int line, const char *fmt, va_list ap)
- {
- internal_vproblem (&internal_error_problem, file, line, fmt, ap);
- throw_quit (_("Command aborted."));
- }
- static struct internal_problem internal_warning_problem = {
- "internal-warning", true, internal_problem_ask, true, internal_problem_ask,
- true, false
- };
- void
- internal_vwarning (const char *file, int line, const char *fmt, va_list ap)
- {
- internal_vproblem (&internal_warning_problem, file, line, fmt, ap);
- }
- static struct internal_problem demangler_warning_problem = {
- "demangler-warning", true, internal_problem_ask, false, internal_problem_no,
- false, false
- };
- void
- demangler_vwarning (const char *file, int line, const char *fmt, va_list ap)
- {
- internal_vproblem (&demangler_warning_problem, file, line, fmt, ap);
- }
- void
- demangler_warning (const char *file, int line, const char *string, ...)
- {
- va_list ap;
- va_start (ap, string);
- demangler_vwarning (file, line, string, ap);
- va_end (ap);
- }
- /* When GDB reports an internal problem (error or warning) it gives
- the user the opportunity to quit GDB and/or create a core file of
- the current debug session. This function registers a few commands
- that make it possible to specify that GDB should always or never
- quit or create a core file, without asking. The commands look
- like:
- maint set PROBLEM-NAME quit ask|yes|no
- maint show PROBLEM-NAME quit
- maint set PROBLEM-NAME corefile ask|yes|no
- maint show PROBLEM-NAME corefile
- Where PROBLEM-NAME is currently "internal-error" or
- "internal-warning". */
- static void
- add_internal_problem_command (struct internal_problem *problem)
- {
- struct cmd_list_element **set_cmd_list;
- struct cmd_list_element **show_cmd_list;
- set_cmd_list = XNEW (struct cmd_list_element *);
- show_cmd_list = XNEW (struct cmd_list_element *);
- *set_cmd_list = NULL;
- *show_cmd_list = NULL;
- /* The add_basic_prefix_cmd and add_show_prefix_cmd functions take
- ownership of the string passed in, which is why we don't need to free
- set_doc and show_doc in this function. */
- const char *set_doc
- = xstrprintf (_("Configure what GDB does when %s is detected."),
- problem->name).release ();
- const char *show_doc
- = xstrprintf (_("Show what GDB does when %s is detected."),
- problem->name).release ();
- add_setshow_prefix_cmd (problem->name, class_maintenance,
- set_doc, show_doc, set_cmd_list, show_cmd_list,
- &maintenance_set_cmdlist, &maintenance_show_cmdlist);
- if (problem->user_settable_should_quit)
- {
- std::string set_quit_doc
- = string_printf (_("Set whether GDB should quit when an %s is "
- "detected."), problem->name);
- std::string show_quit_doc
- = string_printf (_("Show whether GDB will quit when an %s is "
- "detected."), problem->name);
- add_setshow_enum_cmd ("quit", class_maintenance,
- internal_problem_modes,
- &problem->should_quit,
- set_quit_doc.c_str (),
- show_quit_doc.c_str (),
- NULL, /* help_doc */
- NULL, /* setfunc */
- NULL, /* showfunc */
- set_cmd_list,
- show_cmd_list);
- }
- if (problem->user_settable_should_dump_core)
- {
- std::string set_core_doc
- = string_printf (_("Set whether GDB should create a core file of "
- "GDB when %s is detected."), problem->name);
- std::string show_core_doc
- = string_printf (_("Show whether GDB will create a core file of "
- "GDB when %s is detected."), problem->name);
- add_setshow_enum_cmd ("corefile", class_maintenance,
- internal_problem_modes,
- &problem->should_dump_core,
- set_core_doc.c_str (),
- show_core_doc.c_str (),
- NULL, /* help_doc */
- NULL, /* setfunc */
- NULL, /* showfunc */
- set_cmd_list,
- show_cmd_list);
- }
- if (problem->user_settable_should_print_backtrace)
- {
- std::string set_bt_doc
- = string_printf (_("Set whether GDB should print a backtrace of "
- "GDB when %s is detected."), problem->name);
- std::string show_bt_doc
- = string_printf (_("Show whether GDB will print a backtrace of "
- "GDB when %s is detected."), problem->name);
- add_setshow_boolean_cmd ("backtrace", class_maintenance,
- &problem->should_print_backtrace,
- set_bt_doc.c_str (),
- show_bt_doc.c_str (),
- NULL, /* help_doc */
- gdb_internal_backtrace_set_cmd,
- NULL, /* showfunc */
- set_cmd_list,
- show_cmd_list);
- }
- }
- /* Return a newly allocated string, containing the PREFIX followed
- by the system error message for errno (separated by a colon). */
- static std::string
- perror_string (const char *prefix)
- {
- const char *err = safe_strerror (errno);
- return std::string (prefix) + ": " + err;
- }
- /* Print the system error message for errno, and also mention STRING
- as the file name for which the error was encountered. Use ERRCODE
- for the thrown exception. Then return to command level. */
- void
- throw_perror_with_name (enum errors errcode, const char *string)
- {
- std::string combined = perror_string (string);
- /* I understand setting these is a matter of taste. Still, some people
- may clear errno but not know about bfd_error. Doing this here is not
- unreasonable. */
- bfd_set_error (bfd_error_no_error);
- errno = 0;
- throw_error (errcode, _("%s."), combined.c_str ());
- }
- /* See throw_perror_with_name, ERRCODE defaults here to GENERIC_ERROR. */
- void
- perror_with_name (const char *string)
- {
- throw_perror_with_name (GENERIC_ERROR, string);
- }
- /* Same as perror_with_name except that it prints a warning instead
- of throwing an error. */
- void
- perror_warning_with_name (const char *string)
- {
- std::string combined = perror_string (string);
- warning (_("%s"), combined.c_str ());
- }
- /* Print the system error message for ERRCODE, and also mention STRING
- as the file name for which the error was encountered. */
- void
- print_sys_errmsg (const char *string, int errcode)
- {
- const char *err = safe_strerror (errcode);
- gdb_printf (gdb_stderr, "%s: %s.\n", string, err);
- }
- /* Control C eventually causes this to be called, at a convenient time. */
- void
- quit (void)
- {
- if (sync_quit_force_run)
- {
- sync_quit_force_run = 0;
- quit_force (NULL, 0);
- }
- #ifdef __MSDOS__
- /* No steenking SIGINT will ever be coming our way when the
- program is resumed. Don't lie. */
- throw_quit ("Quit");
- #else
- if (job_control
- /* If there is no terminal switching for this target, then we can't
- possibly get screwed by the lack of job control. */
- || !target_supports_terminal_ours ())
- throw_quit ("Quit");
- else
- throw_quit ("Quit (expect signal SIGINT when the program is resumed)");
- #endif
- }
- /* See defs.h. */
- void
- maybe_quit (void)
- {
- if (!is_main_thread ())
- return;
- if (sync_quit_force_run)
- quit ();
- quit_handler ();
- }
- /* Called when a memory allocation fails, with the number of bytes of
- memory requested in SIZE. */
- void
- malloc_failure (long size)
- {
- if (size > 0)
- {
- internal_error (__FILE__, __LINE__,
- _("virtual memory exhausted: can't allocate %ld bytes."),
- size);
- }
- else
- {
- internal_error (__FILE__, __LINE__, _("virtual memory exhausted."));
- }
- }
- /* See common/errors.h. */
- void
- flush_streams ()
- {
- gdb_stdout->flush ();
- gdb_stderr->flush ();
- }
- /* My replacement for the read system call.
- Used like `read' but keeps going if `read' returns too soon. */
- int
- myread (int desc, char *addr, int len)
- {
- int val;
- int orglen = len;
- while (len > 0)
- {
- val = read (desc, addr, len);
- if (val < 0)
- return val;
- if (val == 0)
- return orglen - len;
- len -= val;
- addr += val;
- }
- return orglen;
- }
- /* See utils.h. */
- ULONGEST
- uinteger_pow (ULONGEST v1, LONGEST v2)
- {
- if (v2 < 0)
- {
- if (v1 == 0)
- error (_("Attempt to raise 0 to negative power."));
- else
- return 0;
- }
- else
- {
- /* The Russian Peasant's Algorithm. */
- ULONGEST v;
- v = 1;
- for (;;)
- {
- if (v2 & 1L)
- v *= v1;
- v2 >>= 1;
- if (v2 == 0)
- return v;
- v1 *= v1;
- }
- }
- }
- /* An RAII class that sets up to handle input and then tears down
- during destruction. */
- class scoped_input_handler
- {
- public:
- scoped_input_handler ()
- : m_quit_handler (&quit_handler, default_quit_handler),
- m_ui (NULL)
- {
- target_terminal::ours ();
- ui_register_input_event_handler (current_ui);
- if (current_ui->prompt_state == PROMPT_BLOCKED)
- m_ui = current_ui;
- }
- ~scoped_input_handler ()
- {
- if (m_ui != NULL)
- ui_unregister_input_event_handler (m_ui);
- }
- DISABLE_COPY_AND_ASSIGN (scoped_input_handler);
- private:
- /* Save and restore the terminal state. */
- target_terminal::scoped_restore_terminal_state m_term_state;
- /* Save and restore the quit handler. */
- scoped_restore_tmpl<quit_handler_ftype *> m_quit_handler;
- /* The saved UI, if non-NULL. */
- struct ui *m_ui;
- };
- /* This function supports the query, nquery, and yquery functions.
- Ask user a y-or-n question and return 0 if answer is no, 1 if
- answer is yes, or default the answer to the specified default
- (for yquery or nquery). DEFCHAR may be 'y' or 'n' to provide a
- default answer, or '\0' for no default.
- CTLSTR is the control string and should end in "? ". It should
- not say how to answer, because we do that.
- ARGS are the arguments passed along with the CTLSTR argument to
- printf. */
- static int ATTRIBUTE_PRINTF (1, 0)
- defaulted_query (const char *ctlstr, const char defchar, va_list args)
- {
- int retval;
- int def_value;
- char def_answer, not_def_answer;
- const char *y_string, *n_string;
- /* Set up according to which answer is the default. */
- if (defchar == '\0')
- {
- def_value = 1;
- def_answer = 'Y';
- not_def_answer = 'N';
- y_string = "y";
- n_string = "n";
- }
- else if (defchar == 'y')
- {
- def_value = 1;
- def_answer = 'Y';
- not_def_answer = 'N';
- y_string = "[y]";
- n_string = "n";
- }
- else
- {
- def_value = 0;
- def_answer = 'N';
- not_def_answer = 'Y';
- y_string = "y";
- n_string = "[n]";
- }
- /* Automatically answer the default value if the user did not want
- prompts or the command was issued with the server prefix. */
- if (!confirm || server_command)
- return def_value;
- /* If input isn't coming from the user directly, just say what
- question we're asking, and then answer the default automatically. This
- way, important error messages don't get lost when talking to GDB
- over a pipe. */
- if (current_ui->instream != current_ui->stdin_stream
- || !input_interactive_p (current_ui)
- /* Restrict queries to the main UI. */
- || current_ui != main_ui)
- {
- target_terminal::scoped_restore_terminal_state term_state;
- target_terminal::ours_for_output ();
- gdb_stdout->wrap_here (0);
- gdb_vprintf (gdb_stdout, ctlstr, args);
- gdb_printf (_("(%s or %s) [answered %c; "
- "input not from terminal]\n"),
- y_string, n_string, def_answer);
- return def_value;
- }
- if (deprecated_query_hook)
- {
- target_terminal::scoped_restore_terminal_state term_state;
- return deprecated_query_hook (ctlstr, args);
- }
- /* Format the question outside of the loop, to avoid reusing args. */
- std::string question = string_vprintf (ctlstr, args);
- std::string prompt
- = string_printf (_("%s%s(%s or %s) %s"),
- annotation_level > 1 ? "\n\032\032pre-query\n" : "",
- question.c_str (), y_string, n_string,
- annotation_level > 1 ? "\n\032\032query\n" : "");
- /* Used to add duration we waited for user to respond to
- prompt_for_continue_wait_time. */
- using namespace std::chrono;
- steady_clock::time_point prompt_started = steady_clock::now ();
- scoped_input_handler prepare_input;
- while (1)
- {
- char *response, answer;
- gdb_flush (gdb_stdout);
- response = gdb_readline_wrapper (prompt.c_str ());
- if (response == NULL) /* C-d */
- {
- gdb_printf ("EOF [assumed %c]\n", def_answer);
- retval = def_value;
- break;
- }
- answer = response[0];
- xfree (response);
- if (answer >= 'a')
- answer -= 040;
- /* Check answer. For the non-default, the user must specify
- the non-default explicitly. */
- if (answer == not_def_answer)
- {
- retval = !def_value;
- break;
- }
- /* Otherwise, if a default was specified, the user may either
- specify the required input or have it default by entering
- nothing. */
- if (answer == def_answer
- || (defchar != '\0' && answer == '\0'))
- {
- retval = def_value;
- break;
- }
- /* Invalid entries are not defaulted and require another selection. */
- gdb_printf (_("Please answer %s or %s.\n"),
- y_string, n_string);
- }
- /* Add time spend in this routine to prompt_for_continue_wait_time. */
- prompt_for_continue_wait_time += steady_clock::now () - prompt_started;
- if (annotation_level > 1)
- gdb_printf (("\n\032\032post-query\n"));
- return retval;
- }
- /* Ask user a y-or-n question and return 0 if answer is no, 1 if
- answer is yes, or 0 if answer is defaulted.
- Takes three args which are given to printf to print the question.
- The first, a control string, should end in "? ".
- It should not say how to answer, because we do that. */
- int
- nquery (const char *ctlstr, ...)
- {
- va_list args;
- int ret;
- va_start (args, ctlstr);
- ret = defaulted_query (ctlstr, 'n', args);
- va_end (args);
- return ret;
- }
- /* Ask user a y-or-n question and return 0 if answer is no, 1 if
- answer is yes, or 1 if answer is defaulted.
- Takes three args which are given to printf to print the question.
- The first, a control string, should end in "? ".
- It should not say how to answer, because we do that. */
- int
- yquery (const char *ctlstr, ...)
- {
- va_list args;
- int ret;
- va_start (args, ctlstr);
- ret = defaulted_query (ctlstr, 'y', args);
- va_end (args);
- return ret;
- }
- /* Ask user a y-or-n question and return 1 iff answer is yes.
- Takes three args which are given to printf to print the question.
- The first, a control string, should end in "? ".
- It should not say how to answer, because we do that. */
- int
- query (const char *ctlstr, ...)
- {
- va_list args;
- int ret;
- va_start (args, ctlstr);
- ret = defaulted_query (ctlstr, '\0', args);
- va_end (args);
- return ret;
- }
- /* A helper for parse_escape that converts a host character to a
- target character. C is the host character. If conversion is
- possible, then the target character is stored in *TARGET_C and the
- function returns 1. Otherwise, the function returns 0. */
- static int
- host_char_to_target (struct gdbarch *gdbarch, int c, int *target_c)
- {
- char the_char = c;
- int result = 0;
- auto_obstack host_data;
- convert_between_encodings (target_charset (gdbarch), host_charset (),
- (gdb_byte *) &the_char, 1, 1,
- &host_data, translit_none);
- if (obstack_object_size (&host_data) == 1)
- {
- result = 1;
- *target_c = *(char *) obstack_base (&host_data);
- }
- return result;
- }
- /* Parse a C escape sequence. STRING_PTR points to a variable
- containing a pointer to the string to parse. That pointer
- should point to the character after the \. That pointer
- is updated past the characters we use. The value of the
- escape sequence is returned.
- A negative value means the sequence \ newline was seen,
- which is supposed to be equivalent to nothing at all.
- If \ is followed by a null character, we return a negative
- value and leave the string pointer pointing at the null character.
- If \ is followed by 000, we return 0 and leave the string pointer
- after the zeros. A value of 0 does not mean end of string. */
- int
- parse_escape (struct gdbarch *gdbarch, const char **string_ptr)
- {
- int target_char = -2; /* Initialize to avoid GCC warnings. */
- int c = *(*string_ptr)++;
- switch (c)
- {
- case '\n':
- return -2;
- case 0:
- (*string_ptr)--;
- return 0;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- {
- int i = fromhex (c);
- int count = 0;
- while (++count < 3)
- {
- c = (**string_ptr);
- if (ISDIGIT (c) && c != '8' && c != '9')
- {
- (*string_ptr)++;
- i *= 8;
- i += fromhex (c);
- }
- else
- {
- break;
- }
- }
- return i;
- }
- case 'a':
- c = '\a';
- break;
- case 'b':
- c = '\b';
- break;
- case 'f':
- c = '\f';
- break;
- case 'n':
- c = '\n';
- break;
- case 'r':
- c = '\r';
- break;
- case 't':
- c = '\t';
- break;
- case 'v':
- c = '\v';
- break;
- default:
- break;
- }
- if (!host_char_to_target (gdbarch, c, &target_char))
- error (_("The escape sequence `\\%c' is equivalent to plain `%c',"
- " which has no equivalent\nin the `%s' character set."),
- c, c, target_charset (gdbarch));
- return target_char;
- }
- /* Number of lines per page or UINT_MAX if paging is disabled. */
- static unsigned int lines_per_page;
- static void
- show_lines_per_page (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file,
- _("Number of lines gdb thinks are in a page is %s.\n"),
- value);
- }
- /* Number of chars per line or UINT_MAX if line folding is disabled. */
- static unsigned int chars_per_line;
- static void
- show_chars_per_line (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file,
- _("Number of characters gdb thinks "
- "are in a line is %s.\n"),
- value);
- }
- /* Current count of lines printed on this page, chars on this line. */
- static unsigned int lines_printed, chars_printed;
- /* True if pagination is disabled for just one command. */
- static bool pagination_disabled_for_command;
- /* Buffer and start column of buffered text, for doing smarter word-
- wrapping. When someone calls wrap_here(), we start buffering output
- that comes through gdb_puts(). If we see a newline, we just
- spit it out and forget about the wrap_here(). If we see another
- wrap_here(), we spit it out and remember the newer one. If we see
- the end of the line, we spit out a newline, the indent, and then
- the buffered output. */
- static bool filter_initialized = false;
- /* Initialize the number of lines per page and chars per line. */
- void
- init_page_info (void)
- {
- if (batch_flag)
- {
- lines_per_page = UINT_MAX;
- chars_per_line = UINT_MAX;
- }
- else
- #if defined(TUI)
- if (!tui_get_command_dimension (&chars_per_line, &lines_per_page))
- #endif
- {
- int rows, cols;
- #if defined(__GO32__)
- rows = ScreenRows ();
- cols = ScreenCols ();
- lines_per_page = rows;
- chars_per_line = cols;
- #else
- /* Make sure Readline has initialized its terminal settings. */
- rl_reset_terminal (NULL);
- /* Get the screen size from Readline. */
- rl_get_screen_size (&rows, &cols);
- lines_per_page = rows;
- chars_per_line = cols;
- /* Readline should have fetched the termcap entry for us.
- Only try to use tgetnum function if rl_get_screen_size
- did not return a useful value. */
- if (((rows <= 0) && (tgetnum ((char *) "li") < 0))
- /* Also disable paging if inside Emacs. $EMACS was used
- before Emacs v25.1, $INSIDE_EMACS is used since then. */
- || getenv ("EMACS") || getenv ("INSIDE_EMACS"))
- {
- /* The number of lines per page is not mentioned in the terminal
- description or EMACS environment variable is set. This probably
- means that paging is not useful, so disable paging. */
- lines_per_page = UINT_MAX;
- }
- /* If the output is not a terminal, don't paginate it. */
- if (!gdb_stdout->isatty ())
- lines_per_page = UINT_MAX;
- #endif
- }
- /* We handle SIGWINCH ourselves. */
- rl_catch_sigwinch = 0;
- set_screen_size ();
- set_width ();
- }
- /* Return nonzero if filtered printing is initialized. */
- int
- filtered_printing_initialized (void)
- {
- return filter_initialized;
- }
- set_batch_flag_and_restore_page_info::set_batch_flag_and_restore_page_info ()
- : m_save_lines_per_page (lines_per_page),
- m_save_chars_per_line (chars_per_line),
- m_save_batch_flag (batch_flag)
- {
- batch_flag = 1;
- init_page_info ();
- }
- set_batch_flag_and_restore_page_info::~set_batch_flag_and_restore_page_info ()
- {
- batch_flag = m_save_batch_flag;
- chars_per_line = m_save_chars_per_line;
- lines_per_page = m_save_lines_per_page;
- set_screen_size ();
- set_width ();
- }
- /* Set the screen size based on LINES_PER_PAGE and CHARS_PER_LINE. */
- static void
- set_screen_size (void)
- {
- int rows = lines_per_page;
- int cols = chars_per_line;
- /* If we get 0 or negative ROWS or COLS, treat as "infinite" size.
- A negative number can be seen here with the "set width/height"
- commands and either:
- - the user specified "unlimited", which maps to UINT_MAX, or
- - the user specified some number between INT_MAX and UINT_MAX.
- Cap "infinity" to approximately sqrt(INT_MAX) so that we don't
- overflow in rl_set_screen_size, which multiplies rows and columns
- to compute the number of characters on the screen. */
- const int sqrt_int_max = INT_MAX >> (sizeof (int) * 8 / 2);
- if (rows <= 0 || rows > sqrt_int_max)
- {
- rows = sqrt_int_max;
- lines_per_page = UINT_MAX;
- }
- if (cols <= 0 || cols > sqrt_int_max)
- {
- cols = sqrt_int_max;
- chars_per_line = UINT_MAX;
- }
- /* Update Readline's idea of the terminal size. */
- rl_set_screen_size (rows, cols);
- }
- /* Reinitialize WRAP_BUFFER. */
- static void
- set_width (void)
- {
- if (chars_per_line == 0)
- init_page_info ();
- filter_initialized = true;
- }
- static void
- set_width_command (const char *args, int from_tty, struct cmd_list_element *c)
- {
- set_screen_size ();
- set_width ();
- }
- static void
- set_height_command (const char *args, int from_tty, struct cmd_list_element *c)
- {
- set_screen_size ();
- }
- /* See utils.h. */
- void
- set_screen_width_and_height (int width, int height)
- {
- lines_per_page = height;
- chars_per_line = width;
- set_screen_size ();
- set_width ();
- }
- void
- pager_file::emit_style_escape (const ui_file_style &style)
- {
- if (can_emit_style_escape () && style != m_applied_style)
- {
- m_applied_style = style;
- if (m_paging)
- m_stream->emit_style_escape (style);
- else
- m_wrap_buffer.append (style.to_ansi ());
- }
- }
- /* See pager.h. */
- void
- pager_file::reset_style ()
- {
- if (can_emit_style_escape ())
- {
- m_applied_style = ui_file_style ();
- m_wrap_buffer.append (m_applied_style.to_ansi ());
- }
- }
- /* Wait, so the user can read what's on the screen. Prompt the user
- to continue by pressing RETURN. 'q' is also provided because
- telling users what to do in the prompt is more user-friendly than
- expecting them to think of Ctrl-C/SIGINT. */
- void
- pager_file::prompt_for_continue ()
- {
- char cont_prompt[120];
- /* Used to add duration we waited for user to respond to
- prompt_for_continue_wait_time. */
- using namespace std::chrono;
- steady_clock::time_point prompt_started = steady_clock::now ();
- bool disable_pagination = pagination_disabled_for_command;
- scoped_restore save_paging = make_scoped_restore (&m_paging, true);
- /* Clear the current styling. */
- m_stream->emit_style_escape (ui_file_style ());
- if (annotation_level > 1)
- m_stream->puts (("\n\032\032pre-prompt-for-continue\n"));
- strcpy (cont_prompt,
- "--Type <RET> for more, q to quit, "
- "c to continue without paging--");
- if (annotation_level > 1)
- strcat (cont_prompt, "\n\032\032prompt-for-continue\n");
- /* We must do this *before* we call gdb_readline_wrapper, else it
- will eventually call us -- thinking that we're trying to print
- beyond the end of the screen. */
- reinitialize_more_filter ();
- scoped_input_handler prepare_input;
- /* Call gdb_readline_wrapper, not readline, in order to keep an
- event loop running. */
- gdb::unique_xmalloc_ptr<char> ignore (gdb_readline_wrapper (cont_prompt));
- /* Add time spend in this routine to prompt_for_continue_wait_time. */
- prompt_for_continue_wait_time += steady_clock::now () - prompt_started;
- if (annotation_level > 1)
- m_stream->puts (("\n\032\032post-prompt-for-continue\n"));
- if (ignore != NULL)
- {
- char *p = ignore.get ();
- while (*p == ' ' || *p == '\t')
- ++p;
- if (p[0] == 'q')
- /* Do not call quit here; there is no possibility of SIGINT. */
- throw_quit ("Quit");
- if (p[0] == 'c')
- disable_pagination = true;
- }
- /* Now we have to do this again, so that GDB will know that it doesn't
- need to save the ---Type <return>--- line at the top of the screen. */
- reinitialize_more_filter ();
- pagination_disabled_for_command = disable_pagination;
- dont_repeat (); /* Forget prev cmd -- CR won't repeat it. */
- }
- /* Initialize timer to keep track of how long we waited for the user. */
- void
- reset_prompt_for_continue_wait_time (void)
- {
- using namespace std::chrono;
- prompt_for_continue_wait_time = steady_clock::duration::zero ();
- }
- /* Fetch the cumulative time spent in prompt_for_continue. */
- std::chrono::steady_clock::duration
- get_prompt_for_continue_wait_time ()
- {
- return prompt_for_continue_wait_time;
- }
- /* Reinitialize filter; ie. tell it to reset to original values. */
- void
- reinitialize_more_filter (void)
- {
- lines_printed = 0;
- chars_printed = 0;
- pagination_disabled_for_command = false;
- }
- void
- pager_file::flush_wrap_buffer ()
- {
- if (!m_paging && !m_wrap_buffer.empty ())
- {
- m_stream->puts (m_wrap_buffer.c_str ());
- m_wrap_buffer.clear ();
- }
- }
- void
- pager_file::flush ()
- {
- flush_wrap_buffer ();
- m_stream->flush ();
- }
- /* See utils.h. */
- void
- gdb_flush (struct ui_file *stream)
- {
- stream->flush ();
- }
- /* See utils.h. */
- int
- get_chars_per_line ()
- {
- return chars_per_line;
- }
- /* See ui-file.h. */
- void
- pager_file::wrap_here (int indent)
- {
- /* This should have been allocated, but be paranoid anyway. */
- gdb_assert (filter_initialized);
- flush_wrap_buffer ();
- if (chars_per_line == UINT_MAX) /* No line overflow checking. */
- {
- m_wrap_column = 0;
- }
- else if (chars_printed >= chars_per_line)
- {
- this->puts ("\n");
- if (indent != 0)
- this->puts (n_spaces (indent));
- m_wrap_column = 0;
- }
- else
- {
- m_wrap_column = chars_printed;
- m_wrap_indent = indent;
- m_wrap_style = m_applied_style;
- }
- }
- /* Print input string to gdb_stdout arranging strings in columns of n
- chars. String can be right or left justified in the column. Never
- prints trailing spaces. String should never be longer than width.
- FIXME: this could be useful for the EXAMINE command, which
- currently doesn't tabulate very well. */
- void
- puts_tabular (char *string, int width, int right)
- {
- int spaces = 0;
- int stringlen;
- char *spacebuf;
- gdb_assert (chars_per_line > 0);
- if (chars_per_line == UINT_MAX)
- {
- gdb_puts (string);
- gdb_puts ("\n");
- return;
- }
- if (((chars_printed - 1) / width + 2) * width >= chars_per_line)
- gdb_puts ("\n");
- if (width >= chars_per_line)
- width = chars_per_line - 1;
- stringlen = strlen (string);
- if (chars_printed > 0)
- spaces = width - (chars_printed - 1) % width - 1;
- if (right)
- spaces += width - stringlen;
- spacebuf = (char *) alloca (spaces + 1);
- spacebuf[spaces] = '\0';
- while (spaces--)
- spacebuf[spaces] = ' ';
- gdb_puts (spacebuf);
- gdb_puts (string);
- }
- /* Ensure that whatever gets printed next, using the filtered output
- commands, starts at the beginning of the line. I.e. if there is
- any pending output for the current line, flush it and start a new
- line. Otherwise do nothing. */
- void
- begin_line (void)
- {
- if (chars_printed > 0)
- {
- gdb_puts ("\n");
- }
- }
- void
- pager_file::puts (const char *linebuffer)
- {
- const char *lineptr;
- if (linebuffer == 0)
- return;
- /* Don't do any filtering if it is disabled. */
- if (!pagination_enabled
- || pagination_disabled_for_command
- || batch_flag
- || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX)
- || top_level_interpreter () == NULL
- || top_level_interpreter ()->interp_ui_out ()->is_mi_like_p ())
- {
- flush_wrap_buffer ();
- m_stream->puts (linebuffer);
- return;
- }
- auto buffer_clearer
- = make_scope_exit ([&] ()
- {
- m_wrap_buffer.clear ();
- m_wrap_column = 0;
- m_wrap_indent = 0;
- });
- /* Go through and output each character. Show line extension
- when this is necessary; prompt user for new page when this is
- necessary. */
- lineptr = linebuffer;
- while (*lineptr)
- {
- /* Possible new page. Note that PAGINATION_DISABLED_FOR_COMMAND
- might be set during this loop, so we must continue to check
- it here. */
- if ((lines_printed >= lines_per_page - 1)
- && !pagination_disabled_for_command)
- prompt_for_continue ();
- while (*lineptr && *lineptr != '\n')
- {
- int skip_bytes;
- /* Print a single line. */
- if (*lineptr == '\t')
- {
- m_wrap_buffer.push_back ('\t');
- /* Shifting right by 3 produces the number of tab stops
- we have already passed, and then adding one and
- shifting left 3 advances to the next tab stop. */
- chars_printed = ((chars_printed >> 3) + 1) << 3;
- lineptr++;
- }
- else if (*lineptr == '\033'
- && skip_ansi_escape (lineptr, &skip_bytes))
- {
- m_wrap_buffer.append (lineptr, skip_bytes);
- /* Note that we don't consider this a character, so we
- don't increment chars_printed here. */
- lineptr += skip_bytes;
- }
- else if (*lineptr == '\r')
- {
- m_wrap_buffer.push_back (*lineptr);
- chars_printed = 0;
- lineptr++;
- }
- else
- {
- m_wrap_buffer.push_back (*lineptr);
- chars_printed++;
- lineptr++;
- }
- if (chars_printed >= chars_per_line)
- {
- unsigned int save_chars = chars_printed;
- /* If we change the style, below, we'll want to reset it
- before continuing to print. If there is no wrap
- column, then we'll only reset the style if the pager
- prompt is given; and to avoid emitting style
- sequences in the middle of a run of text, we track
- this as well. */
- ui_file_style save_style = m_applied_style;
- bool did_paginate = false;
- chars_printed = 0;
- lines_printed++;
- if (m_wrap_column)
- {
- /* We are about to insert a newline at an historic
- location in the WRAP_BUFFER. Before we do we want to
- restore the default style. To know if we actually
- need to insert an escape sequence we must restore the
- current applied style to how it was at the WRAP_COLUMN
- location. */
- m_applied_style = m_wrap_style;
- m_stream->emit_style_escape (ui_file_style ());
- /* If we aren't actually wrapping, don't output
- newline -- if chars_per_line is right, we
- probably just overflowed anyway; if it's wrong,
- let us keep going. */
- m_stream->puts ("\n");
- }
- else
- this->flush_wrap_buffer ();
- /* Possible new page. Note that
- PAGINATION_DISABLED_FOR_COMMAND might be set during
- this loop, so we must continue to check it here. */
- if (lines_printed >= lines_per_page - 1
- && !pagination_disabled_for_command)
- {
- prompt_for_continue ();
- did_paginate = true;
- }
- /* Now output indentation and wrapped string. */
- if (m_wrap_column)
- {
- m_stream->puts (n_spaces (m_wrap_indent));
- /* Having finished inserting the wrapping we should
- restore the style as it was at the WRAP_COLUMN. */
- m_stream->emit_style_escape (m_wrap_style);
- /* The WRAP_BUFFER will still contain content, and that
- content might set some alternative style. Restore
- APPLIED_STYLE as it was before we started wrapping,
- this reflects the current style for the last character
- in WRAP_BUFFER. */
- m_applied_style = save_style;
- /* Note that this can set chars_printed > chars_per_line
- if we are printing a long string. */
- chars_printed = m_wrap_indent + (save_chars - m_wrap_column);
- m_wrap_column = 0; /* And disable fancy wrap */
- }
- else if (did_paginate)
- m_stream->emit_style_escape (save_style);
- }
- }
- if (*lineptr == '\n')
- {
- chars_printed = 0;
- wrap_here (0); /* Spit out chars, cancel further wraps. */
- lines_printed++;
- m_stream->puts ("\n");
- lineptr++;
- }
- }
- buffer_clearer.release ();
- }
- void
- pager_file::write (const char *buf, long length_buf)
- {
- /* We have to make a string here because the pager uses
- skip_ansi_escape, which requires NUL-termination. */
- std::string str (buf, length_buf);
- this->puts (str.c_str ());
- }
- void
- gdb_puts (const char *linebuffer, struct ui_file *stream)
- {
- stream->puts (linebuffer);
- }
- /* See utils.h. */
- void
- fputs_styled (const char *linebuffer, const ui_file_style &style,
- struct ui_file *stream)
- {
- stream->emit_style_escape (style);
- gdb_puts (linebuffer, stream);
- stream->emit_style_escape (ui_file_style ());
- }
- /* See utils.h. */
- void
- fputs_highlighted (const char *str, const compiled_regex &highlight,
- struct ui_file *stream)
- {
- regmatch_t pmatch;
- while (*str && highlight.exec (str, 1, &pmatch, 0) == 0)
- {
- size_t n_highlight = pmatch.rm_eo - pmatch.rm_so;
- /* Output the part before pmatch with current style. */
- while (pmatch.rm_so > 0)
- {
- gdb_putc (*str, stream);
- pmatch.rm_so--;
- str++;
- }
- /* Output pmatch with the highlight style. */
- stream->emit_style_escape (highlight_style.style ());
- while (n_highlight > 0)
- {
- gdb_putc (*str, stream);
- n_highlight--;
- str++;
- }
- stream->emit_style_escape (ui_file_style ());
- }
- /* Output the trailing part of STR not matching HIGHLIGHT. */
- if (*str)
- gdb_puts (str, stream);
- }
- /* Write character C to gdb_stdout using GDB's paging mechanism and return C.
- May return nonlocally. */
- int
- gdb_putc (int c)
- {
- return gdb_stdout->putc (c);
- }
- int
- gdb_putc (int c, struct ui_file *stream)
- {
- return stream->putc (c);
- }
- void
- gdb_vprintf (struct ui_file *stream, const char *format, va_list args)
- {
- stream->vprintf (format, args);
- }
- void
- gdb_vprintf (const char *format, va_list args)
- {
- gdb_stdout->vprintf (format, args);
- }
- void
- gdb_printf (struct ui_file *stream, const char *format, ...)
- {
- va_list args;
- va_start (args, format);
- gdb_vprintf (stream, format, args);
- va_end (args);
- }
- /* See utils.h. */
- void
- fprintf_styled (struct ui_file *stream, const ui_file_style &style,
- const char *format, ...)
- {
- va_list args;
- stream->emit_style_escape (style);
- va_start (args, format);
- gdb_vprintf (stream, format, args);
- va_end (args);
- stream->emit_style_escape (ui_file_style ());
- }
- void
- gdb_printf (const char *format, ...)
- {
- va_list args;
- va_start (args, format);
- gdb_vprintf (gdb_stdout, format, args);
- va_end (args);
- }
- void
- printf_unfiltered (const char *format, ...)
- {
- va_list args;
- va_start (args, format);
- string_file file (gdb_stdout->can_emit_style_escape ());
- file.vprintf (format, args);
- gdb_stdout->puts_unfiltered (file.string ().c_str ());
- va_end (args);
- }
- /* Easy -- but watch out!
- This routine is *not* a replacement for puts()! puts() appends a newline.
- This one doesn't, and had better not! */
- void
- gdb_puts (const char *string)
- {
- gdb_stdout->puts (string);
- }
- /* Return a pointer to N spaces and a null. The pointer is good
- until the next call to here. */
- const char *
- n_spaces (int n)
- {
- char *t;
- static char *spaces = 0;
- static int max_spaces = -1;
- if (n > max_spaces)
- {
- xfree (spaces);
- spaces = (char *) xmalloc (n + 1);
- for (t = spaces + n; t != spaces;)
- *--t = ' ';
- spaces[n] = '\0';
- max_spaces = n;
- }
- return spaces + max_spaces - n;
- }
- /* Print N spaces. */
- void
- print_spaces (int n, struct ui_file *stream)
- {
- gdb_puts (n_spaces (n), stream);
- }
- /* C++/ObjC demangler stuff. */
- /* fprintf_symbol attempts to demangle NAME, a symbol in language
- LANG, using demangling args ARG_MODE, and print it filtered to STREAM.
- If the name is not mangled, or the language for the name is unknown, or
- demangling is off, the name is printed in its "raw" form. */
- void
- fprintf_symbol (struct ui_file *stream, const char *name,
- enum language lang, int arg_mode)
- {
- if (name != NULL)
- {
- /* If user wants to see raw output, no problem. */
- if (!demangle)
- {
- gdb_puts (name, stream);
- }
- else
- {
- gdb::unique_xmalloc_ptr<char> demangled
- = language_demangle (language_def (lang), name, arg_mode);
- gdb_puts (demangled ? demangled.get () : name, stream);
- }
- }
- }
- /* True if CH is a character that can be part of a symbol name. I.e.,
- either a number, a letter, or a '_'. */
- static bool
- valid_identifier_name_char (int ch)
- {
- return (ISALNUM (ch) || ch == '_');
- }
- /* Skip to end of token, or to END, whatever comes first. Input is
- assumed to be a C++ operator name. */
- static const char *
- cp_skip_operator_token (const char *token, const char *end)
- {
- const char *p = token;
- while (p != end && !ISSPACE (*p) && *p != '(')
- {
- if (valid_identifier_name_char (*p))
- {
- while (p != end && valid_identifier_name_char (*p))
- p++;
- return p;
- }
- else
- {
- /* Note, ordered such that among ops that share a prefix,
- longer comes first. This is so that the loop below can
- bail on first match. */
- static const char *ops[] =
- {
- "[",
- "]",
- "~",
- ",",
- "-=", "--", "->", "-",
- "+=", "++", "+",
- "*=", "*",
- "/=", "/",
- "%=", "%",
- "|=", "||", "|",
- "&=", "&&", "&",
- "^=", "^",
- "!=", "!",
- "<<=", "<=", "<<", "<",
- ">>=", ">=", ">>", ">",
- "==", "=",
- };
- for (const char *op : ops)
- {
- size_t oplen = strlen (op);
- size_t lencmp = std::min<size_t> (oplen, end - p);
- if (strncmp (p, op, lencmp) == 0)
- return p + lencmp;
- }
- /* Some unidentified character. Return it. */
- return p + 1;
- }
- }
- return p;
- }
- /* Advance STRING1/STRING2 past whitespace. */
- static void
- skip_ws (const char *&string1, const char *&string2, const char *end_str2)
- {
- while (ISSPACE (*string1))
- string1++;
- while (string2 < end_str2 && ISSPACE (*string2))
- string2++;
- }
- /* True if STRING points at the start of a C++ operator name. START
- is the start of the string that STRING points to, hence when
- reading backwards, we must not read any character before START. */
- static bool
- cp_is_operator (const char *string, const char *start)
- {
- return ((string == start
- || !valid_identifier_name_char (string[-1]))
- && strncmp (string, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0
- && !valid_identifier_name_char (string[CP_OPERATOR_LEN]));
- }
- /* If *NAME points at an ABI tag, skip it and return true. Otherwise
- leave *NAME unmodified and return false. (see GCC's abi_tag
- attribute), such names are demangled as e.g.,
- "function[abi:cxx11]()". */
- static bool
- skip_abi_tag (const char **name)
- {
- const char *p = *name;
- if (startswith (p, "[abi:"))
- {
- p += 5;
- while (valid_identifier_name_char (*p))
- p++;
- if (*p == ']')
- {
- p++;
- *name = p;
- return true;
- }
- }
- return false;
- }
- /* If *NAME points at a template parameter list, skip it and return true.
- Otherwise do nothing and return false. */
- static bool
- skip_template_parameter_list (const char **name)
- {
- const char *p = *name;
- if (*p == '<')
- {
- const char *template_param_list_end = find_toplevel_char (p + 1, '>');
- if (template_param_list_end == NULL)
- return false;
- p = template_param_list_end + 1;
- /* Skip any whitespace that might occur after the closing of the
- parameter list, but only if it is the end of parameter list. */
- const char *q = p;
- while (ISSPACE (*q))
- ++q;
- if (*q == '>')
- p = q;
- *name = p;
- return true;
- }
- return false;
- }
- /* See utils.h. */
- int
- strncmp_iw_with_mode (const char *string1, const char *string2,
- size_t string2_len, strncmp_iw_mode mode,
- enum language language,
- completion_match_for_lcd *match_for_lcd,
- bool ignore_template_params)
- {
- const char *string1_start = string1;
- const char *end_str2 = string2 + string2_len;
- bool skip_spaces = true;
- bool have_colon_op = (language == language_cplus
- || language == language_rust
- || language == language_fortran);
- while (1)
- {
- if (skip_spaces
- || ((ISSPACE (*string1) && !valid_identifier_name_char (*string2))
- || (ISSPACE (*string2) && !valid_identifier_name_char (*string1))))
- {
- skip_ws (string1, string2, end_str2);
- skip_spaces = false;
- }
- /* Skip [abi:cxx11] tags in the symbol name if the lookup name
- doesn't include them. E.g.:
- string1: function[abi:cxx1](int)
- string2: function
- string1: function[abi:cxx1](int)
- string2: function(int)
- string1: Struct[abi:cxx1]::function()
- string2: Struct::function()
- string1: function(Struct[abi:cxx1], int)
- string2: function(Struct, int)
- */
- if (string2 == end_str2
- || (*string2 != '[' && !valid_identifier_name_char (*string2)))
- {
- const char *abi_start = string1;
- /* There can be more than one tag. */
- while (*string1 == '[' && skip_abi_tag (&string1))
- ;
- if (match_for_lcd != NULL && abi_start != string1)
- match_for_lcd->mark_ignored_range (abi_start, string1);
- while (ISSPACE (*string1))
- string1++;
- }
- /* Skip template parameters in STRING1 if STRING2 does not contain
- any. E.g.:
- Case 1: User is looking for all functions named "foo".
- string1: foo <...> (...)
- string2: foo
- Case 2: User is looking for all methods named "foo" in all template
- class instantiations.
- string1: Foo<...>::foo <...> (...)
- string2: Foo::foo (...)
- Case 3: User is looking for a specific overload of a template
- function or method.
- string1: foo<...>
- string2: foo(...)
- Case 4: User is looking for a specific overload of a specific
- template instantiation.
- string1: foo<A> (...)
- string2: foo<B> (...)
- Case 5: User is looking wild parameter match.
- string1: foo<A<a<b<...> > > > (...)
- string2: foo<A
- */
- if (language == language_cplus && ignore_template_params
- && *string1 == '<' && *string2 != '<')
- {
- /* Skip any parameter list in STRING1. */
- const char *template_start = string1;
- if (skip_template_parameter_list (&string1))
- {
- /* Don't mark the parameter list ignored if the user didn't
- try to ignore it. [Case #5 above] */
- if (*string2 != '\0'
- && match_for_lcd != NULL && template_start != string1)
- match_for_lcd->mark_ignored_range (template_start, string1);
- }
- }
- if (*string1 == '\0' || string2 == end_str2)
- break;
- /* Handle the :: operator. */
- if (have_colon_op && string1[0] == ':' && string1[1] == ':')
- {
- if (*string2 != ':')
- return 1;
- string1++;
- string2++;
- if (string2 == end_str2)
- break;
- if (*string2 != ':')
- return 1;
- string1++;
- string2++;
- while (ISSPACE (*string1))
- string1++;
- while (string2 < end_str2 && ISSPACE (*string2))
- string2++;
- continue;
- }
- /* Handle C++ user-defined operators. */
- else if (language == language_cplus
- && *string1 == 'o')
- {
- if (cp_is_operator (string1, string1_start))
- {
- /* An operator name in STRING1. Check STRING2. */
- size_t cmplen
- = std::min<size_t> (CP_OPERATOR_LEN, end_str2 - string2);
- if (strncmp (string1, string2, cmplen) != 0)
- return 1;
- string1 += cmplen;
- string2 += cmplen;
- if (string2 != end_str2)
- {
- /* Check for "operatorX" in STRING2. */
- if (valid_identifier_name_char (*string2))
- return 1;
- skip_ws (string1, string2, end_str2);
- }
- /* Handle operator(). */
- if (*string1 == '(')
- {
- if (string2 == end_str2)
- {
- if (mode == strncmp_iw_mode::NORMAL)
- return 0;
- else
- {
- /* Don't break for the regular return at the
- bottom, because "operator" should not
- match "operator()", since this open
- parentheses is not the parameter list
- start. */
- return *string1 != '\0';
- }
- }
- if (*string1 != *string2)
- return 1;
- string1++;
- string2++;
- }
- while (1)
- {
- skip_ws (string1, string2, end_str2);
- /* Skip to end of token, or to END, whatever comes
- first. */
- const char *end_str1 = string1 + strlen (string1);
- const char *p1 = cp_skip_operator_token (string1, end_str1);
- const char *p2 = cp_skip_operator_token (string2, end_str2);
- cmplen = std::min (p1 - string1, p2 - string2);
- if (p2 == end_str2)
- {
- if (strncmp (string1, string2, cmplen) != 0)
- return 1;
- }
- else
- {
- if (p1 - string1 != p2 - string2)
- return 1;
- if (strncmp (string1, string2, cmplen) != 0)
- return 1;
- }
- string1 += cmplen;
- string2 += cmplen;
- if (*string1 == '\0' || string2 == end_str2)
- break;
- if (*string1 == '(' || *string2 == '(')
- break;
- /* If STRING1 or STRING2 starts with a template
- parameter list, break out of operator processing. */
- skip_ws (string1, string2, end_str2);
- if (*string1 == '<' || *string2 == '<')
- break;
- }
- continue;
- }
- }
- if (case_sensitivity == case_sensitive_on && *string1 != *string2)
- break;
- if (case_sensitivity == case_sensitive_off
- && (TOLOWER ((unsigned char) *string1)
- != TOLOWER ((unsigned char) *string2)))
- break;
- /* If we see any non-whitespace, non-identifier-name character
- (any of "()<>*&" etc.), then skip spaces the next time
- around. */
- if (!ISSPACE (*string1) && !valid_identifier_name_char (*string1))
- skip_spaces = true;
- string1++;
- string2++;
- }
- if (string2 == end_str2)
- {
- if (mode == strncmp_iw_mode::NORMAL)
- {
- /* Strip abi tag markers from the matched symbol name.
- Usually the ABI marker will be found on function name
- (automatically added because the function returns an
- object marked with an ABI tag). However, it's also
- possible to see a marker in one of the function
- parameters, for example.
- string2 (lookup name):
- func
- symbol name:
- function(some_struct[abi:cxx11], int)
- and for completion LCD computation we want to say that
- the match was for:
- function(some_struct, int)
- */
- if (match_for_lcd != NULL)
- {
- while ((string1 = strstr (string1, "[abi:")) != NULL)
- {
- const char *abi_start = string1;
- /* There can be more than one tag. */
- while (skip_abi_tag (&string1) && *string1 == '[')
- ;
- if (abi_start != string1)
- match_for_lcd->mark_ignored_range (abi_start, string1);
- }
- }
- return 0;
- }
- else
- return (*string1 != '\0' && *string1 != '(');
- }
- else
- return 1;
- }
- #if GDB_SELF_TEST
- /* Unit tests for strncmp_iw_with_mode. */
- #define CHECK_MATCH_LM(S1, S2, MODE, LANG, LCD) \
- SELF_CHECK (strncmp_iw_with_mode ((S1), (S2), strlen ((S2)), \
- strncmp_iw_mode::MODE, \
- (LANG), (LCD)) == 0)
- #define CHECK_MATCH_LANG(S1, S2, MODE, LANG) \
- CHECK_MATCH_LM ((S1), (S2), MODE, (LANG), nullptr)
- #define CHECK_MATCH(S1, S2, MODE) \
- CHECK_MATCH_LANG ((S1), (S2), MODE, language_minimal)
- #define CHECK_NO_MATCH_LM(S1, S2, MODE, LANG, LCD) \
- SELF_CHECK (strncmp_iw_with_mode ((S1), (S2), strlen ((S2)), \
- strncmp_iw_mode::MODE, \
- (LANG)) != 0)
- #define CHECK_NO_MATCH_LANG(S1, S2, MODE, LANG) \
- CHECK_NO_MATCH_LM ((S1), (S2), MODE, (LANG), nullptr)
- #define CHECK_NO_MATCH(S1, S2, MODE) \
- CHECK_NO_MATCH_LANG ((S1), (S2), MODE, language_minimal)
- static void
- check_scope_operator (enum language lang)
- {
- CHECK_MATCH_LANG ("::", "::", NORMAL, lang);
- CHECK_MATCH_LANG ("::foo", "::", NORMAL, lang);
- CHECK_MATCH_LANG ("::foo", "::foo", NORMAL, lang);
- CHECK_MATCH_LANG (" :: foo ", "::foo", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b", "a ::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b", "a\t::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b", "a \t::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b", "a\t ::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b", "a:: b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b", "a::\tb", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b", "a:: \tb", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b", "a::\t b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b", "a :: b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b", "a ::\tb", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b", "a\t:: b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b", "a \t::\t b", NORMAL, lang);
- CHECK_MATCH_LANG ("a ::b", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a\t::b", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a \t::b", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a\t ::b", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a:: b", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::\tb", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a:: \tb", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::\t b", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a :: b", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a ::\tb", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a\t:: b", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a \t::\t b", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b::c", "a::b::c", NORMAL, lang);
- CHECK_MATCH_LANG (" a:: b:: c", "a::b::c", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b::c", " a:: b:: c", NORMAL, lang);
- CHECK_MATCH_LANG ("a ::b ::c", "a::b::c", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b::c", "a :: b:: c", NORMAL, lang);
- CHECK_MATCH_LANG ("\ta::\tb::\tc", "\ta::\tb::\tc", NORMAL, lang);
- CHECK_MATCH_LANG ("a\t::b\t::c\t", "a\t::b\t::c\t", NORMAL, lang);
- CHECK_MATCH_LANG (" \ta:: \tb:: \tc", " \ta:: \tb:: \tc", NORMAL, lang);
- CHECK_MATCH_LANG ("\t a::\t b::\t c", "\t a::\t b::\t c", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b::c", "\ta::\tb::\tc", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b::c", "a\t::b\t::c\t", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b::c", " \ta:: \tb:: \tc", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b::c", "\t a::\t b::\t c", NORMAL, lang);
- CHECK_MATCH_LANG ("\ta::\tb::\tc", "a::b::c", NORMAL, lang);
- CHECK_MATCH_LANG ("a\t::b\t::c\t", "a::b::c", NORMAL, lang);
- CHECK_MATCH_LANG (" \ta:: \tb:: \tc", "a::b::c", NORMAL, lang);
- CHECK_MATCH_LANG ("\t a::\t b::\t c", "a::b::c", NORMAL, lang);
- CHECK_MATCH_LANG ("a :: b:: c\t", "\ta :: b\t:: c\t\t", NORMAL, lang);
- CHECK_MATCH_LANG (" a::\t \t b:: c\t", "\ta ::b:: c\t\t",
- NORMAL, lang);
- CHECK_MATCH_LANG ("a :: b :: \t\t\tc\t",
- "\t\t\t\ta :: \t\t\t b \t\t::c",
- NORMAL, lang);
- CHECK_MATCH_LANG ("a::b()", "a", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b()", "a::", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b()", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b(a)", "a", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b(a)", "a::", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b(a)", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b(a,b)", "a", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b(a,b)", "a::", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b(a,b)", "a::b", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b(a,b,c)", "a", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b(a,b,c)", "a::", NORMAL, lang);
- CHECK_MATCH_LANG ("a::b(a,b,c)", "a::b", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::", "::a", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("::a", "::a()", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("::", "::a", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a:::b", "a::b", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b()", "a::b(a)", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b(a)", "a::b()", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b(a,b)", "a::b(a,a)", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b", "a()", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b", "a::()", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b", "a::b()", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b", "a(a)", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b", "a::(a)", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b", "a::b()", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b", "a(a,b)", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b", "a::(a,b)", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b", "a::b(a,b)", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b", "a(a,b,c)", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b", "a::(a,b,c)", NORMAL, lang);
- CHECK_NO_MATCH_LANG ("a::b", "a::b(a,b,c)", NORMAL, lang);
- }
- /* Callback for strncmp_iw_with_mode unit tests. */
- static void
- strncmp_iw_with_mode_tests ()
- {
- /* Some of the following tests are nonsensical, but could be input by a
- deranged script (or user). */
- /* strncmp_iw_mode::NORMAL: strcmp()-like but ignore any whitespace... */
- CHECK_MATCH ("", "", NORMAL);
- CHECK_MATCH ("foo", "foo", NORMAL);
- CHECK_MATCH (" foo", "foo", NORMAL);
- CHECK_MATCH ("foo ", "foo", NORMAL);
- CHECK_MATCH (" foo ", "foo", NORMAL);
- CHECK_MATCH (" foo", "foo", NORMAL);
- CHECK_MATCH ("foo ", "foo", NORMAL);
- CHECK_MATCH (" foo ", "foo", NORMAL);
- CHECK_MATCH ("\tfoo", "foo", NORMAL);
- CHECK_MATCH ("foo\t", "foo", NORMAL);
- CHECK_MATCH ("\tfoo\t", "foo", NORMAL);
- CHECK_MATCH (" \tfoo \t", "foo", NORMAL);
- CHECK_MATCH ("\t foo\t ", "foo", NORMAL);
- CHECK_MATCH ("\t \t \t\t\t\t foo\t\t\t \t\t \t \t \t \t ",
- "foo", NORMAL);
- CHECK_MATCH ("foo",
- "\t \t \t\t\t\t foo\t\t\t \t\t \t \t \t \t ",
- NORMAL);
- CHECK_MATCH ("foo bar", "foo", NORMAL);
- CHECK_NO_MATCH ("foo", "bar", NORMAL);
- CHECK_NO_MATCH ("foo bar", "foobar", NORMAL);
- CHECK_NO_MATCH (" foo ", "bar", NORMAL);
- CHECK_NO_MATCH ("foo", " bar ", NORMAL);
- CHECK_NO_MATCH (" \t\t foo\t\t ", "\t \t \tbar\t", NORMAL);
- CHECK_NO_MATCH ("@!%&", "@!%&foo", NORMAL);
- /* ... and function parameters in STRING1. */
- CHECK_MATCH ("foo()", "foo()", NORMAL);
- CHECK_MATCH ("foo ()", "foo()", NORMAL);
- CHECK_MATCH ("foo ()", "foo()", NORMAL);
- CHECK_MATCH ("foo\t()", "foo()", NORMAL);
- CHECK_MATCH ("foo\t ()", "foo()", NORMAL);
- CHECK_MATCH ("foo \t()", "foo()", NORMAL);
- CHECK_MATCH ("foo()", "foo ()", NORMAL);
- CHECK_MATCH ("foo()", "foo ()", NORMAL);
- CHECK_MATCH ("foo()", "foo\t()", NORMAL);
- CHECK_MATCH ("foo()", "foo\t ()", NORMAL);
- CHECK_MATCH ("foo()", "foo \t()", NORMAL);
- CHECK_MATCH ("foo()", "foo()", NORMAL);
- CHECK_MATCH ("foo ()", "foo ()", NORMAL);
- CHECK_MATCH ("foo ()", "foo ()", NORMAL);
- CHECK_MATCH ("foo\t()", "foo\t()", NORMAL);
- CHECK_MATCH ("foo\t ()", "foo\t ()", NORMAL);
- CHECK_MATCH ("foo \t()", "foo \t()", NORMAL);
- CHECK_MATCH ("foo(a)", "foo(a)", NORMAL);
- CHECK_MATCH ("foo( a)", "foo(a)", NORMAL);
- CHECK_MATCH ("foo(a )", "foo(a)", NORMAL);
- CHECK_MATCH ("foo(\ta)", "foo(a)", NORMAL);
- CHECK_MATCH ("foo(a\t)", "foo(a)", NORMAL);
- CHECK_MATCH ("foo(\t a)", "foo(a)", NORMAL);
- CHECK_MATCH ("foo( \ta)", "foo(a)", NORMAL);
- CHECK_MATCH ("foo(a\t )", "foo(a)", NORMAL);
- CHECK_MATCH ("foo(a \t)", "foo(a)", NORMAL);
- CHECK_MATCH ("foo( a )", "foo(a)", NORMAL);
- CHECK_MATCH ("foo(\ta\t)", "foo(a)", NORMAL);
- CHECK_MATCH ("foo(\t a\t )", "foo(a)", NORMAL);
- CHECK_MATCH ("foo( \ta \t)", "foo(a)", NORMAL);
- CHECK_MATCH ("foo(a)", "foo( a)", NORMAL);
- CHECK_MATCH ("foo(a)", "foo(a )", NORMAL);
- CHECK_MATCH ("foo(a)", "foo(\ta)", NORMAL);
- CHECK_MATCH ("foo(a)", "foo(a\t)", NORMAL);
- CHECK_MATCH ("foo(a)", "foo(\t a)", NORMAL);
- CHECK_MATCH ("foo(a)", "foo( \ta)", NORMAL);
- CHECK_MATCH ("foo(a)", "foo(a\t )", NORMAL);
- CHECK_MATCH ("foo(a)", "foo(a \t)", NORMAL);
- CHECK_MATCH ("foo(a)", "foo( a )", NORMAL);
- CHECK_MATCH ("foo(a)", "foo(\ta\t)", NORMAL);
- CHECK_MATCH ("foo(a)", "foo(\t a\t )", NORMAL);
- CHECK_MATCH ("foo(a)", "foo( \ta \t)", NORMAL);
- CHECK_MATCH ("foo(a,b)", "foo(a,b)", NORMAL);
- CHECK_MATCH ("foo(a ,b)", "foo(a,b)", NORMAL);
- CHECK_MATCH ("foo(a\t,b)", "foo(a,b)", NORMAL);
- CHECK_MATCH ("foo(a,\tb)", "foo(a,b)", NORMAL);
- CHECK_MATCH ("foo(a\t,\tb)", "foo(a,b)", NORMAL);
- CHECK_MATCH ("foo(a \t,b)", "foo(a,b)", NORMAL);
- CHECK_MATCH ("foo(a\t ,b)", "foo(a,b)", NORMAL);
- CHECK_MATCH ("foo(a,\tb)", "foo(a,b)", NORMAL);
- CHECK_MATCH ("foo(a, \tb)", "foo(a,b)", NORMAL);
- CHECK_MATCH ("foo(a,\t b)", "foo(a,b)", NORMAL);
- CHECK_MATCH ("foo(a,b)", "foo(a ,b)", NORMAL);
- CHECK_MATCH ("foo(a,b)", "foo(a\t,b)", NORMAL);
- CHECK_MATCH ("foo(a,b)", "foo(a,\tb)", NORMAL);
- CHECK_MATCH ("foo(a,b)", "foo(a\t,\tb)", NORMAL);
- CHECK_MATCH ("foo(a,b)", "foo(a \t,b)", NORMAL);
- CHECK_MATCH ("foo(a,b)", "foo(a\t ,b)", NORMAL);
- CHECK_MATCH ("foo(a,b)", "foo(a,\tb)", NORMAL);
- CHECK_MATCH ("foo(a,b)", "foo(a, \tb)", NORMAL);
- CHECK_MATCH ("foo(a,b)", "foo(a,\t b)", NORMAL);
- CHECK_MATCH ("foo(a,b,c,d)", "foo(a,b,c,d)", NORMAL);
- CHECK_MATCH (" foo ( a , b , c , d ) ", "foo(a,b,c,d)", NORMAL);
- CHECK_MATCH (" foo ( a , b , c , d ) ", "foo( a , b , c , d )", NORMAL);
- CHECK_MATCH ("foo &\t*(\ta b *\t\t&)", "foo", NORMAL);
- CHECK_MATCH ("foo &\t*(\ta b *\t\t&)", "foo&*(a b * &)", NORMAL);
- CHECK_MATCH ("foo(a) b", "foo(a)", NORMAL);
- CHECK_MATCH ("*foo(*a&)", "*foo", NORMAL);
- CHECK_MATCH ("*foo(*a&)", "*foo(*a&)", NORMAL);
- CHECK_MATCH ("*a&b#c/^d$foo(*a&)", "*a&b#c/^d$foo", NORMAL);
- CHECK_MATCH ("* foo", "*foo", NORMAL);
- CHECK_MATCH ("foo&", "foo", NORMAL);
- CHECK_MATCH ("foo*", "foo", NORMAL);
- CHECK_MATCH ("foo.", "foo", NORMAL);
- CHECK_MATCH ("foo->", "foo", NORMAL);
- CHECK_NO_MATCH ("foo", "foo(", NORMAL);
- CHECK_NO_MATCH ("foo", "foo()", NORMAL);
- CHECK_NO_MATCH ("foo", "foo(a)", NORMAL);
- CHECK_NO_MATCH ("foo", "foo(a)", NORMAL);
- CHECK_NO_MATCH ("foo", "foo*", NORMAL);
- CHECK_NO_MATCH ("foo", "foo (*", NORMAL);
- CHECK_NO_MATCH ("foo*", "foo (*", NORMAL);
- CHECK_NO_MATCH ("foo *", "foo (*", NORMAL);
- CHECK_NO_MATCH ("foo&", "foo (*", NORMAL);
- CHECK_NO_MATCH ("foo &", "foo (*", NORMAL);
- CHECK_NO_MATCH ("foo &*", "foo (&)", NORMAL);
- CHECK_NO_MATCH ("foo & \t *\t", "foo (*", NORMAL);
- CHECK_NO_MATCH ("foo & \t *\t", "foo (*", NORMAL);
- CHECK_NO_MATCH ("foo(a*) b", "foo(a) b", NORMAL);
- CHECK_NO_MATCH ("foo[aqi:A](a)", "foo(b)", NORMAL);
- CHECK_NO_MATCH ("*foo", "foo", NORMAL);
- CHECK_NO_MATCH ("*foo", "foo*", NORMAL);
- CHECK_NO_MATCH ("*foo*", "*foo&", NORMAL);
- CHECK_NO_MATCH ("*foo*", "foo *", NORMAL);
- CHECK_NO_MATCH ("&foo", "foo", NORMAL);
- CHECK_NO_MATCH ("&foo", "foo&", NORMAL);
- CHECK_NO_MATCH ("foo&", "&foo", NORMAL);
- CHECK_NO_MATCH ("foo", "foo&", NORMAL);
- CHECK_NO_MATCH ("foo", "foo*", NORMAL);
- CHECK_NO_MATCH ("foo", "foo.", NORMAL);
- CHECK_NO_MATCH ("foo", "foo->", NORMAL);
- CHECK_NO_MATCH ("foo bar", "foo()", NORMAL);
- CHECK_NO_MATCH ("foo bar", "foo bar()", NORMAL);
- CHECK_NO_MATCH ("foo()", "foo(a)", NORMAL);
- CHECK_NO_MATCH ("*(*)&", "*(*)*", NORMAL);
- CHECK_NO_MATCH ("foo(a)", "foo()", NORMAL);
- CHECK_NO_MATCH ("foo(a)", "foo(b)", NORMAL);
- CHECK_NO_MATCH ("foo(a,b)", "foo(a,b,c)", NORMAL);
- CHECK_NO_MATCH ("foo(a\\b)", "foo()", NORMAL);
- CHECK_NO_MATCH ("foo bar(a b c d)", "foobar", NORMAL);
- CHECK_NO_MATCH ("foo bar(a b c d)", "foobar ( a b c \td\t)\t", NORMAL);
- /* Test scope operator. */
- check_scope_operator (language_minimal);
- check_scope_operator (language_cplus);
- check_scope_operator (language_fortran);
- check_scope_operator (language_rust);
- /* Test C++ user-defined operators. */
- CHECK_MATCH_LANG ("operator foo(int&)", "operator foo(int &)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("operator foo(int &)", "operator foo(int &)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("operator foo(int\t&)", "operator foo(int\t&)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("operator foo (int)", "operator foo(int)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("operator foo\t(int)", "operator foo(int)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("operator foo \t(int)", "operator foo(int)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("operator foo (int)", "operator foo \t(int)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("operator foo\t(int)", "operator foo \t(int)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("operator foo \t(int)", "operator foo \t(int)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("a::operator foo(int&)", "a::operator foo(int &)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("a :: operator foo(int &)", "a::operator foo(int &)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("a \t:: \toperator foo(int\t&)", "a::operator foo(int\t&)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("a::operator foo (int)", "a::operator foo(int)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("a::operator foo\t(int)", "a::operator foo(int)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("a::operator foo \t(int)", "a::operator foo(int)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("a::operator foo (int)", "a::operator foo \t(int)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("a::operator foo\t(int)", "a::operator foo \t(int)", NORMAL,
- language_cplus);
- CHECK_MATCH_LANG ("a::operator foo \t(int)", "a::operator foo \t(int)", NORMAL,
- language_cplus);
- CHECK_NO_MATCH_LANG ("operator foo(int)", "operator foo(char)", NORMAL,
- language_cplus);
- CHECK_NO_MATCH_LANG ("operator foo(int)", "operator foo(int *)", NORMAL,
- language_cplus);
- CHECK_NO_MATCH_LANG ("operator foo(int)", "operator foo(int &)", NORMAL,
- language_cplus);
- CHECK_NO_MATCH_LANG ("operator foo(int)", "operator foo(int, char *)", NORMAL,
- language_cplus);
- CHECK_NO_MATCH_LANG ("operator foo(int)", "operator bar(int)", NORMAL,
- language_cplus);
- CHECK_NO_MATCH_LANG ("a::operator b::foo(int)", "a::operator a::foo(char)", NORMAL,
- language_cplus);
- CHECK_NO_MATCH_LANG ("a::operator foo(int)", "a::operator foo(int *)", NORMAL,
- language_cplus);
- CHECK_NO_MATCH_LANG ("a::operator foo(int)", "a::operator foo(int &)", NORMAL,
- language_cplus);
- CHECK_NO_MATCH_LANG ("a::operator foo(int)", "a::operator foo(int, char *)", NORMAL,
- language_cplus);
- CHECK_NO_MATCH_LANG ("a::operator foo(int)", "a::operator bar(int)", NORMAL,
- language_cplus);
- /* Skip "[abi:cxx11]" tags in the symbol name if the lookup name
- doesn't include them. These are not language-specific in
- strncmp_iw_with_mode. */
- CHECK_MATCH ("foo[abi:a]", "foo", NORMAL);
- CHECK_MATCH ("foo[abi:a]()", "foo", NORMAL);
- CHECK_MATCH ("foo[abi:a](a)", "foo", NORMAL);
- CHECK_MATCH ("foo[abi:a](a&,b*)", "foo", NORMAL);
- CHECK_MATCH ("foo[abi:a](a,b)", "foo(a,b)", NORMAL);
- CHECK_MATCH ("foo[abi:a](a,b) c", "foo(a,b) c", NORMAL);
- CHECK_MATCH ("foo[abi:a](a)", "foo(a)", NORMAL);
- CHECK_MATCH ("foo[abi:a](a,b)", "foo(a,b)", NORMAL);
- CHECK_MATCH ("foo[abi:a]", "foo[abi:a]", NORMAL);
- CHECK_MATCH ("foo[ abi:a]", "foo[abi:a]", NORMAL);
- CHECK_MATCH ("foo[\tabi:a]", "foo[abi:a]", NORMAL);
- CHECK_MATCH ("foo[ \tabi:a]", "foo[abi:a]", NORMAL);
- CHECK_MATCH ("foo[\t abi:a]", "foo[abi:a]", NORMAL);
- CHECK_MATCH ("foo[abi :a]", "foo[abi:a]", NORMAL);
- CHECK_MATCH ("foo[abi\t:a]", "foo[abi:a]", NORMAL);
- CHECK_MATCH ("foo[abi \t:a]", "foo[abi:a]", NORMAL);
- CHECK_MATCH ("foo[abi\t :a]", "foo[abi:a]", NORMAL);
- CHECK_MATCH ("foo[abi:a]", "foo[ abi:a]", NORMAL);
- CHECK_MATCH ("foo[abi:a]", "foo[\tabi:a]", NORMAL);
- CHECK_MATCH ("foo[abi:a]", "foo[ \tabi:a]", NORMAL);
- CHECK_MATCH ("foo[abi:a]", "foo[\t abi:a]", NORMAL);
- CHECK_MATCH ("foo[abi:a]", "foo[abi :a]", NORMAL);
- CHECK_MATCH ("foo[abi:a]", "foo[abi\t:a]", NORMAL);
- CHECK_MATCH ("foo[abi:a]", "foo[abi \t:a]", NORMAL);
- CHECK_MATCH ("foo[abi:a]", "foo[abi\t :a]", NORMAL);
- CHECK_MATCH ("foo[abi:a]", "foo[abi:a ]", NORMAL);
- CHECK_MATCH ("foo[abi:a]", "foo[abi:a\t]", NORMAL);
- CHECK_MATCH ("foo[abi:a]", "foo[abi:a \t]", NORMAL);
- CHECK_MATCH ("foo[abi:a]", "foo[abi:a\t ]", NORMAL);
- CHECK_MATCH ("foo[abi:a,b]", "foo[abi:a,b]", NORMAL);
- CHECK_MATCH ("foo[abi:::]", "foo[abi:::]", NORMAL);
- CHECK_MATCH ("foo[abi : : : ]", "foo[abi:::]", NORMAL);
- CHECK_MATCH ("foo[abi:::]", "foo[abi : : : ]", NORMAL);
- CHECK_MATCH ("foo[ \t abi \t:\t: : \t]",
- "foo[ abi : \t ::]",
- NORMAL);
- CHECK_MATCH ("foo< bar< baz< quxi > > >(int)", "foo<bar<baz<quxi>>>(int)",
- NORMAL);
- CHECK_MATCH ("\tfoo<\tbar<\tbaz\t<\tquxi\t>\t>\t>(int)",
- "foo<bar<baz<quxi>>>(int)", NORMAL);
- CHECK_MATCH (" \tfoo \t< \tbar \t< \tbaz \t< \tquxi \t> \t> \t> \t( \tint \t)",
- "foo<bar<baz<quxi>>>(int)", NORMAL);
- CHECK_MATCH ("foo<bar<baz<quxi>>>(int)",
- "foo < bar < baz < quxi > > > (int)", NORMAL);
- CHECK_MATCH ("foo<bar<baz<quxi>>>(int)",
- "\tfoo\t<\tbar\t<\tbaz\t<\tquxi\t>\t>\t>\t(int)", NORMAL);
- CHECK_MATCH ("foo<bar<baz<quxi>>>(int)",
- " \tfoo \t< \tbar \t< \tbaz \t< \tquxi \t> \t> \t> \t( \tint \t)", NORMAL);
- CHECK_MATCH ("foo<bar<baz>>::foo(quxi &)", "fo", NORMAL);
- CHECK_MATCH ("foo<bar<baz>>::foo(quxi &)", "foo", NORMAL);
- CHECK_MATCH ("foo<bar<baz>>::foo(quxi &)", "foo<bar<baz>>::", NORMAL);
- CHECK_MATCH ("foo<bar<baz>>::foo(quxi &)", "foo<bar<baz> >::foo", NORMAL);
- CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo[abi:a][abi:b](bar[abi:c][abi:d])",
- NORMAL);
- CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo", NORMAL);
- CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo(bar)", NORMAL);
- CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo[abi:a](bar)", NORMAL);
- CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo(bar[abi:c])", NORMAL);
- CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo[abi:a](bar[abi:c])", NORMAL);
- CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo[abi:a][abi:b](bar)", NORMAL);
- CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo[abi:a][abi:b](bar[abi:c])",
- NORMAL);
- CHECK_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo", NORMAL);
- CHECK_NO_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo()", NORMAL);
- CHECK_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar>", NORMAL);
- CHECK_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar>(char*, baz)", NORMAL);
- CHECK_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar>(char*, baz[abi:b])",
- NORMAL);
- CHECK_NO_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar>(char*, baz[abi:A])",
- NORMAL);
- CHECK_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar[abi:a]>(char*, baz)",
- NORMAL);
- CHECK_NO_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar[abi:A]>(char*, baz)",
- NORMAL);
- CHECK_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar[abi:a]>(char*, baz[abi:b])",
- NORMAL);
- CHECK_NO_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])",
- "foo<bar[abi:a]>(char*, baz[abi:B])", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[ a]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[a ]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[ a ]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[\ta]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[a \t]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[a\t ]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[ \ta]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[\t a]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[ \ta \t]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[\t a\t ]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[ abi]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi ]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[\tabi]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi\t]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[ \tabi]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[\t abi]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi \t]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi\t ]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi :]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi\t:]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi \t:]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi\t :]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi: ]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi:\t]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi: \t]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi:\t ]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi: a]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi:\ta]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi: \ta]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi:\t a]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi:a ]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi:a\t]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi:a \t]", NORMAL);
- CHECK_NO_MATCH ("foo", "foo[abi:a\t ]", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a]()", "foo(a)", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a]()", "foo(a)", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a]()", "foo(a)", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a]()", "foo(a)", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a]()", "foo(a) c", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a]()", "foo(a) .", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a]()", "foo(a) *", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a]()", "foo(a) &", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b) c", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b) .", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b) *", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b) &", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b)c", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b).", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b)*", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b)&", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a](a,b) d", "foo(a,b) c", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a](a)", "foo()", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a](a)", "foo(b)", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a](a)", "foo[abi:b](a)", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a](a)", "foo[abi:a](b)", NORMAL);
- CHECK_NO_MATCH ("foo[abi:]", "foo[abi:a]", NORMAL);
- CHECK_NO_MATCH ("foo[abi:", "foo[abi:a]", NORMAL);
- CHECK_NO_MATCH ("foo[abi:]", "foo[abi:a", NORMAL);
- CHECK_NO_MATCH ("foo[abi:,]", "foo[abi:a]", NORMAL);
- CHECK_NO_MATCH ("foo[abi:a,b]", "foo[abi:a]", NORMAL);
- CHECK_NO_MATCH ("foo[abi::a]", "foo[abi:a]", NORMAL);
- CHECK_NO_MATCH ("foo[abi:,([a]", "foo[abi:a]", NORMAL);
- CHECK_MATCH ("foo <a, b [, c (", "foo", NORMAL);
- CHECK_MATCH ("foo >a, b ], c )", "foo", NORMAL);
- CHECK_MATCH ("@!%&\\*", "@!%&\\*", NORMAL);
- CHECK_MATCH ("()", "()", NORMAL);
- CHECK_MATCH ("*(*)*", "*(*)*", NORMAL);
- CHECK_MATCH ("[]", "[]", NORMAL);
- CHECK_MATCH ("<>", "<>", NORMAL);
- /* strncmp_iw_with_mode::MATCH_PARAMS: the "strcmp_iw hack." */
- CHECK_MATCH ("foo2", "foo", NORMAL);
- CHECK_NO_MATCH ("foo2", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2", "foo ", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2", "foo\t", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2", "foo \t", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2", "foo\t ", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2", "foo \t", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2", " foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2", "\tfoo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2", " \tfoo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2", "\t foo", MATCH_PARAMS);
- CHECK_NO_MATCH (" foo2", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("\tfoo2", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH (" \tfoo2", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("\t foo2", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH (" foo2 ", " foo ", MATCH_PARAMS);
- CHECK_NO_MATCH ("\tfoo2\t", "\tfoo\t", MATCH_PARAMS);
- CHECK_NO_MATCH (" \tfoo2 \t", " \tfoo \t", MATCH_PARAMS);
- CHECK_NO_MATCH ("\t foo2\t ", "\t foo\t ", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2 ", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2\t", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2 ", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2 \t", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2\t ", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2 (args)", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2 (args)", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2\t(args)", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2 \t(args)", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2\t (args)", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2 ( args)", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2(args )", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2(args\t)", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2 (args \t)", "foo", MATCH_PARAMS);
- CHECK_NO_MATCH ("foo2 (args\t )", "foo", MATCH_PARAMS);
- CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo[abi:a][abi:b](bar[abi:c][abi:d])",
- MATCH_PARAMS);
- CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo", MATCH_PARAMS);
- /* strncmp_iw_with_mode also supports case insensitivity. */
- {
- CHECK_NO_MATCH ("FoO", "foo", NORMAL);
- CHECK_NO_MATCH ("FoO", "foo", MATCH_PARAMS);
- scoped_restore restore_case = make_scoped_restore (&case_sensitivity);
- case_sensitivity = case_sensitive_off;
- CHECK_MATCH ("FoO", "foo", NORMAL);
- CHECK_MATCH ("FoO", "foo", MATCH_PARAMS);
- CHECK_MATCH ("foo", "FoO", NORMAL);
- CHECK_MATCH ("foo", "FoO", MATCH_PARAMS);
- CHECK_MATCH ("FoO[AbI:abC]()", "foo", NORMAL);
- CHECK_NO_MATCH ("FoO[AbI:abC]()", "foo", MATCH_PARAMS);
- CHECK_MATCH ("FoO2[AbI:abC]()", "foo", NORMAL);
- CHECK_NO_MATCH ("FoO2[AbI:abC]()", "foo", MATCH_PARAMS);
- CHECK_MATCH ("foo[abi:abc]()", "FoO[AbI:abC]()", NORMAL);
- CHECK_MATCH ("foo[abi:abc]()", "FoO[AbI:AbC]()", MATCH_PARAMS);
- CHECK_MATCH ("foo[abi:abc](xyz)", "FoO[AbI:abC](XyZ)", NORMAL);
- CHECK_MATCH ("foo[abi:abc](xyz)", "FoO[AbI:abC](XyZ)", MATCH_PARAMS);
- CHECK_MATCH ("foo[abi:abc][abi:def](xyz)", "FoO[AbI:abC](XyZ)", NORMAL);
- CHECK_MATCH ("foo[abi:abc][abi:def](xyz)", "FoO[AbI:abC](XyZ)",
- MATCH_PARAMS);
- CHECK_MATCH ("foo<bar<baz>>(bar<baz>)", "FoO<bAr<BaZ>>(bAr<BaZ>)",
- NORMAL);
- CHECK_MATCH ("foo<bar<baz>>(bar<baz>)", "FoO<bAr<BaZ>>(bAr<BaZ>)",
- MATCH_PARAMS);
- }
- }
- #undef MATCH
- #undef NO_MATCH
- #endif
- /* See utils.h. */
- int
- strncmp_iw (const char *string1, const char *string2, size_t string2_len)
- {
- return strncmp_iw_with_mode (string1, string2, string2_len,
- strncmp_iw_mode::NORMAL, language_minimal);
- }
- /* See utils.h. */
- int
- strcmp_iw (const char *string1, const char *string2)
- {
- return strncmp_iw_with_mode (string1, string2, strlen (string2),
- strncmp_iw_mode::MATCH_PARAMS, language_minimal);
- }
- /* This is like strcmp except that it ignores whitespace and treats
- '(' as the first non-NULL character in terms of ordering. Like
- strcmp (and unlike strcmp_iw), it returns negative if STRING1 <
- STRING2, 0 if STRING2 = STRING2, and positive if STRING1 > STRING2
- according to that ordering.
- If a list is sorted according to this function and if you want to
- find names in the list that match some fixed NAME according to
- strcmp_iw(LIST_ELT, NAME), then the place to start looking is right
- where this function would put NAME.
- This function must be neutral to the CASE_SENSITIVITY setting as the user
- may choose it during later lookup. Therefore this function always sorts
- primarily case-insensitively and secondarily case-sensitively.
- Here are some examples of why using strcmp to sort is a bad idea:
- Whitespace example:
- Say your partial symtab contains: "foo<char *>", "goo". Then, if
- we try to do a search for "foo<char*>", strcmp will locate this
- after "foo<char *>" and before "goo". Then lookup_partial_symbol
- will start looking at strings beginning with "goo", and will never
- see the correct match of "foo<char *>".
- Parenthesis example:
- In practice, this is less like to be an issue, but I'll give it a
- shot. Let's assume that '$' is a legitimate character to occur in
- symbols. (Which may well even be the case on some systems.) Then
- say that the partial symbol table contains "foo$" and "foo(int)".
- strcmp will put them in this order, since '$' < '('. Now, if the
- user searches for "foo", then strcmp will sort "foo" before "foo$".
- Then lookup_partial_symbol will notice that strcmp_iw("foo$",
- "foo") is false, so it won't proceed to the actual match of
- "foo(int)" with "foo". */
- int
- strcmp_iw_ordered (const char *string1, const char *string2)
- {
- const char *saved_string1 = string1, *saved_string2 = string2;
- enum case_sensitivity case_pass = case_sensitive_off;
- for (;;)
- {
- /* C1 and C2 are valid only if *string1 != '\0' && *string2 != '\0'.
- Provide stub characters if we are already at the end of one of the
- strings. */
- char c1 = 'X', c2 = 'X';
- while (*string1 != '\0' && *string2 != '\0')
- {
- while (ISSPACE (*string1))
- string1++;
- while (ISSPACE (*string2))
- string2++;
- switch (case_pass)
- {
- case case_sensitive_off:
- c1 = TOLOWER ((unsigned char) *string1);
- c2 = TOLOWER ((unsigned char) *string2);
- break;
- case case_sensitive_on:
- c1 = *string1;
- c2 = *string2;
- break;
- }
- if (c1 != c2)
- break;
- if (*string1 != '\0')
- {
- string1++;
- string2++;
- }
- }
- switch (*string1)
- {
- /* Characters are non-equal unless they're both '\0'; we want to
- make sure we get the comparison right according to our
- comparison in the cases where one of them is '\0' or '('. */
- case '\0':
- if (*string2 == '\0')
- break;
- else
- return -1;
- case '(':
- if (*string2 == '\0')
- return 1;
- else
- return -1;
- default:
- if (*string2 == '\0' || *string2 == '(')
- return 1;
- else if (c1 > c2)
- return 1;
- else if (c1 < c2)
- return -1;
- /* PASSTHRU */
- }
- if (case_pass == case_sensitive_on)
- return 0;
-
- /* Otherwise the strings were equal in case insensitive way, make
- a more fine grained comparison in a case sensitive way. */
- case_pass = case_sensitive_on;
- string1 = saved_string1;
- string2 = saved_string2;
- }
- }
- /* See utils.h. */
- bool
- streq (const char *lhs, const char *rhs)
- {
- return !strcmp (lhs, rhs);
- }
- /*
- ** subset_compare()
- ** Answer whether string_to_compare is a full or partial match to
- ** template_string. The partial match must be in sequence starting
- ** at index 0.
- */
- int
- subset_compare (const char *string_to_compare, const char *template_string)
- {
- int match;
- if (template_string != NULL && string_to_compare != NULL
- && strlen (string_to_compare) <= strlen (template_string))
- match =
- (startswith (template_string, string_to_compare));
- else
- match = 0;
- return match;
- }
- static void
- show_debug_timestamp (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("Timestamping debugging messages is %s.\n"),
- value);
- }
- /* See utils.h. */
- CORE_ADDR
- address_significant (gdbarch *gdbarch, CORE_ADDR addr)
- {
- /* Clear insignificant bits of a target address and sign extend resulting
- address, avoiding shifts larger or equal than the width of a CORE_ADDR.
- The local variable ADDR_BIT stops the compiler reporting a shift overflow
- when it won't occur. Skip updating of target address if current target
- has not set gdbarch significant_addr_bit. */
- int addr_bit = gdbarch_significant_addr_bit (gdbarch);
- if (addr_bit && (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT)))
- {
- CORE_ADDR sign = (CORE_ADDR) 1 << (addr_bit - 1);
- addr &= ((CORE_ADDR) 1 << addr_bit) - 1;
- addr = (addr ^ sign) - sign;
- }
- return addr;
- }
- const char *
- paddress (struct gdbarch *gdbarch, CORE_ADDR addr)
- {
- /* Truncate address to the size of a target address, avoiding shifts
- larger or equal than the width of a CORE_ADDR. The local
- variable ADDR_BIT stops the compiler reporting a shift overflow
- when it won't occur. */
- /* NOTE: This assumes that the significant address information is
- kept in the least significant bits of ADDR - the upper bits were
- either zero or sign extended. Should gdbarch_address_to_pointer or
- some ADDRESS_TO_PRINTABLE() be used to do the conversion? */
- int addr_bit = gdbarch_addr_bit (gdbarch);
- if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
- addr &= ((CORE_ADDR) 1 << addr_bit) - 1;
- return hex_string (addr);
- }
- /* This function is described in "defs.h". */
- const char *
- print_core_address (struct gdbarch *gdbarch, CORE_ADDR address)
- {
- int addr_bit = gdbarch_addr_bit (gdbarch);
- if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
- address &= ((CORE_ADDR) 1 << addr_bit) - 1;
- /* FIXME: cagney/2002-05-03: Need local_address_string() function
- that returns the language localized string formatted to a width
- based on gdbarch_addr_bit. */
- if (addr_bit <= 32)
- return hex_string_custom (address, 8);
- else
- return hex_string_custom (address, 16);
- }
- /* Convert a string back into a CORE_ADDR. */
- CORE_ADDR
- string_to_core_addr (const char *my_string)
- {
- CORE_ADDR addr = 0;
- if (my_string[0] == '0' && TOLOWER (my_string[1]) == 'x')
- {
- /* Assume that it is in hex. */
- int i;
- for (i = 2; my_string[i] != '\0'; i++)
- {
- if (ISDIGIT (my_string[i]))
- addr = (my_string[i] - '0') + (addr * 16);
- else if (ISXDIGIT (my_string[i]))
- addr = (TOLOWER (my_string[i]) - 'a' + 0xa) + (addr * 16);
- else
- error (_("invalid hex \"%s\""), my_string);
- }
- }
- else
- {
- /* Assume that it is in decimal. */
- int i;
- for (i = 0; my_string[i] != '\0'; i++)
- {
- if (ISDIGIT (my_string[i]))
- addr = (my_string[i] - '0') + (addr * 10);
- else
- error (_("invalid decimal \"%s\""), my_string);
- }
- }
- return addr;
- }
- #if GDB_SELF_TEST
- static void
- gdb_realpath_check_trailer (const char *input, const char *trailer)
- {
- gdb::unique_xmalloc_ptr<char> result = gdb_realpath (input);
- size_t len = strlen (result.get ());
- size_t trail_len = strlen (trailer);
- SELF_CHECK (len >= trail_len
- && strcmp (result.get () + len - trail_len, trailer) == 0);
- }
- static void
- gdb_realpath_tests ()
- {
- /* A file which contains a directory prefix. */
- gdb_realpath_check_trailer ("./xfullpath.exp", "/xfullpath.exp");
- /* A file which contains a directory prefix. */
- gdb_realpath_check_trailer ("../../defs.h", "/defs.h");
- /* A one-character filename. */
- gdb_realpath_check_trailer ("./a", "/a");
- /* A file in the root directory. */
- gdb_realpath_check_trailer ("/root_file_which_should_exist",
- "/root_file_which_should_exist");
- /* A file which does not have a directory prefix. */
- gdb_realpath_check_trailer ("xfullpath.exp", "xfullpath.exp");
- /* A one-char filename without any directory prefix. */
- gdb_realpath_check_trailer ("a", "a");
- /* An empty filename. */
- gdb_realpath_check_trailer ("", "");
- }
- /* Test the gdb_argv::as_array_view method. */
- static void
- gdb_argv_as_array_view_test ()
- {
- {
- gdb_argv argv;
- gdb::array_view<char *> view = argv.as_array_view ();
- SELF_CHECK (view.data () == nullptr);
- SELF_CHECK (view.size () == 0);
- }
- {
- gdb_argv argv ("une bonne 50");
- gdb::array_view<char *> view = argv.as_array_view ();
- SELF_CHECK (view.size () == 3);
- SELF_CHECK (strcmp (view[0], "une") == 0);
- SELF_CHECK (strcmp (view[1], "bonne") == 0);
- SELF_CHECK (strcmp (view[2], "50") == 0);
- }
- }
- #endif /* GDB_SELF_TEST */
- /* Simple, portable version of dirname that does not modify its
- argument. */
- std::string
- ldirname (const char *filename)
- {
- std::string dirname;
- const char *base = lbasename (filename);
- while (base > filename && IS_DIR_SEPARATOR (base[-1]))
- --base;
- if (base == filename)
- return dirname;
- dirname = std::string (filename, base - filename);
- /* On DOS based file systems, convert "d:foo" to "d:.", so that we
- create "d:./bar" later instead of the (different) "d:/bar". */
- if (base - filename == 2 && IS_ABSOLUTE_PATH (base)
- && !IS_DIR_SEPARATOR (filename[0]))
- dirname[base++ - filename] = '.';
- return dirname;
- }
- /* Return ARGS parsed as a valid pid, or throw an error. */
- int
- parse_pid_to_attach (const char *args)
- {
- unsigned long pid;
- char *dummy;
- if (!args)
- error_no_arg (_("process-id to attach"));
- dummy = (char *) args;
- pid = strtoul (args, &dummy, 0);
- /* Some targets don't set errno on errors, grrr! */
- if ((pid == 0 && dummy == args) || dummy != &args[strlen (args)])
- error (_("Illegal process-id: %s."), args);
- return pid;
- }
- /* Substitute all occurrences of string FROM by string TO in *STRINGP. *STRINGP
- must come from xrealloc-compatible allocator and it may be updated. FROM
- needs to be delimited by IS_DIR_SEPARATOR or DIRNAME_SEPARATOR (or be
- located at the start or end of *STRINGP. */
- void
- substitute_path_component (char **stringp, const char *from, const char *to)
- {
- char *string = *stringp, *s;
- const size_t from_len = strlen (from);
- const size_t to_len = strlen (to);
- for (s = string;;)
- {
- s = strstr (s, from);
- if (s == NULL)
- break;
- if ((s == string || IS_DIR_SEPARATOR (s[-1])
- || s[-1] == DIRNAME_SEPARATOR)
- && (s[from_len] == '\0' || IS_DIR_SEPARATOR (s[from_len])
- || s[from_len] == DIRNAME_SEPARATOR))
- {
- char *string_new;
- string_new
- = (char *) xrealloc (string, (strlen (string) + to_len + 1));
- /* Relocate the current S pointer. */
- s = s - string + string_new;
- string = string_new;
- /* Replace from by to. */
- memmove (&s[to_len], &s[from_len], strlen (&s[from_len]) + 1);
- memcpy (s, to, to_len);
- s += to_len;
- }
- else
- s++;
- }
- *stringp = string;
- }
- #ifdef HAVE_WAITPID
- #ifdef SIGALRM
- /* SIGALRM handler for waitpid_with_timeout. */
- static void
- sigalrm_handler (int signo)
- {
- /* Nothing to do. */
- }
- #endif
- /* Wrapper to wait for child PID to die with TIMEOUT.
- TIMEOUT is the time to stop waiting in seconds.
- If TIMEOUT is zero, pass WNOHANG to waitpid.
- Returns PID if it was successfully waited for, otherwise -1.
- Timeouts are currently implemented with alarm and SIGALRM.
- If the host does not support them, this waits "forever".
- It would be odd though for a host to have waitpid and not SIGALRM. */
- pid_t
- wait_to_die_with_timeout (pid_t pid, int *status, int timeout)
- {
- pid_t waitpid_result;
- gdb_assert (pid > 0);
- gdb_assert (timeout >= 0);
- if (timeout > 0)
- {
- #ifdef SIGALRM
- #if defined (HAVE_SIGACTION) && defined (SA_RESTART)
- struct sigaction sa, old_sa;
- sa.sa_handler = sigalrm_handler;
- sigemptyset (&sa.sa_mask);
- sa.sa_flags = 0;
- sigaction (SIGALRM, &sa, &old_sa);
- #else
- sighandler_t ofunc;
- ofunc = signal (SIGALRM, sigalrm_handler);
- #endif
- alarm (timeout);
- #endif
- waitpid_result = waitpid (pid, status, 0);
- #ifdef SIGALRM
- alarm (0);
- #if defined (HAVE_SIGACTION) && defined (SA_RESTART)
- sigaction (SIGALRM, &old_sa, NULL);
- #else
- signal (SIGALRM, ofunc);
- #endif
- #endif
- }
- else
- waitpid_result = waitpid (pid, status, WNOHANG);
- if (waitpid_result == pid)
- return pid;
- else
- return -1;
- }
- #endif /* HAVE_WAITPID */
- /* Provide fnmatch compatible function for FNM_FILE_NAME matching of host files.
- Both FNM_FILE_NAME and FNM_NOESCAPE must be set in FLAGS.
- It handles correctly HAVE_DOS_BASED_FILE_SYSTEM and
- HAVE_CASE_INSENSITIVE_FILE_SYSTEM. */
- int
- gdb_filename_fnmatch (const char *pattern, const char *string, int flags)
- {
- gdb_assert ((flags & FNM_FILE_NAME) != 0);
- /* It is unclear how '\' escaping vs. directory separator should coexist. */
- gdb_assert ((flags & FNM_NOESCAPE) != 0);
- #ifdef HAVE_DOS_BASED_FILE_SYSTEM
- {
- char *pattern_slash, *string_slash;
- /* Replace '\' by '/' in both strings. */
- pattern_slash = (char *) alloca (strlen (pattern) + 1);
- strcpy (pattern_slash, pattern);
- pattern = pattern_slash;
- for (; *pattern_slash != 0; pattern_slash++)
- if (IS_DIR_SEPARATOR (*pattern_slash))
- *pattern_slash = '/';
- string_slash = (char *) alloca (strlen (string) + 1);
- strcpy (string_slash, string);
- string = string_slash;
- for (; *string_slash != 0; string_slash++)
- if (IS_DIR_SEPARATOR (*string_slash))
- *string_slash = '/';
- }
- #endif /* HAVE_DOS_BASED_FILE_SYSTEM */
- #ifdef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
- flags |= FNM_CASEFOLD;
- #endif /* HAVE_CASE_INSENSITIVE_FILE_SYSTEM */
- return fnmatch (pattern, string, flags);
- }
- /* Return the number of path elements in PATH.
- / = 1
- /foo = 2
- /foo/ = 2
- foo/bar = 2
- foo/ = 1 */
- int
- count_path_elements (const char *path)
- {
- int count = 0;
- const char *p = path;
- if (HAS_DRIVE_SPEC (p))
- {
- p = STRIP_DRIVE_SPEC (p);
- ++count;
- }
- while (*p != '\0')
- {
- if (IS_DIR_SEPARATOR (*p))
- ++count;
- ++p;
- }
- /* Backup one if last character is /, unless it's the only one. */
- if (p > path + 1 && IS_DIR_SEPARATOR (p[-1]))
- --count;
- /* Add one for the file name, if present. */
- if (p > path && !IS_DIR_SEPARATOR (p[-1]))
- ++count;
- return count;
- }
- /* Remove N leading path elements from PATH.
- N must be non-negative.
- If PATH has more than N path elements then return NULL.
- If PATH has exactly N path elements then return "".
- See count_path_elements for a description of how we do the counting. */
- const char *
- strip_leading_path_elements (const char *path, int n)
- {
- int i = 0;
- const char *p = path;
- gdb_assert (n >= 0);
- if (n == 0)
- return p;
- if (HAS_DRIVE_SPEC (p))
- {
- p = STRIP_DRIVE_SPEC (p);
- ++i;
- }
- while (i < n)
- {
- while (*p != '\0' && !IS_DIR_SEPARATOR (*p))
- ++p;
- if (*p == '\0')
- {
- if (i + 1 == n)
- return "";
- return NULL;
- }
- ++p;
- ++i;
- }
- return p;
- }
- /* See utils.h. */
- void
- copy_bitwise (gdb_byte *dest, ULONGEST dest_offset,
- const gdb_byte *source, ULONGEST source_offset,
- ULONGEST nbits, int bits_big_endian)
- {
- unsigned int buf, avail;
- if (nbits == 0)
- return;
- if (bits_big_endian)
- {
- /* Start from the end, then work backwards. */
- dest_offset += nbits - 1;
- dest += dest_offset / 8;
- dest_offset = 7 - dest_offset % 8;
- source_offset += nbits - 1;
- source += source_offset / 8;
- source_offset = 7 - source_offset % 8;
- }
- else
- {
- dest += dest_offset / 8;
- dest_offset %= 8;
- source += source_offset / 8;
- source_offset %= 8;
- }
- /* Fill BUF with DEST_OFFSET bits from the destination and 8 -
- SOURCE_OFFSET bits from the source. */
- buf = *(bits_big_endian ? source-- : source++) >> source_offset;
- buf <<= dest_offset;
- buf |= *dest & ((1 << dest_offset) - 1);
- /* NBITS: bits yet to be written; AVAIL: BUF's fill level. */
- nbits += dest_offset;
- avail = dest_offset + 8 - source_offset;
- /* Flush 8 bits from BUF, if appropriate. */
- if (nbits >= 8 && avail >= 8)
- {
- *(bits_big_endian ? dest-- : dest++) = buf;
- buf >>= 8;
- avail -= 8;
- nbits -= 8;
- }
- /* Copy the middle part. */
- if (nbits >= 8)
- {
- size_t len = nbits / 8;
- /* Use a faster method for byte-aligned copies. */
- if (avail == 0)
- {
- if (bits_big_endian)
- {
- dest -= len;
- source -= len;
- memcpy (dest + 1, source + 1, len);
- }
- else
- {
- memcpy (dest, source, len);
- dest += len;
- source += len;
- }
- }
- else
- {
- while (len--)
- {
- buf |= *(bits_big_endian ? source-- : source++) << avail;
- *(bits_big_endian ? dest-- : dest++) = buf;
- buf >>= 8;
- }
- }
- nbits %= 8;
- }
- /* Write the last byte. */
- if (nbits)
- {
- if (avail < nbits)
- buf |= *source << avail;
- buf &= (1 << nbits) - 1;
- *dest = (*dest & (~0U << nbits)) | buf;
- }
- }
- void _initialize_utils ();
- void
- _initialize_utils ()
- {
- add_setshow_uinteger_cmd ("width", class_support, &chars_per_line, _("\
- Set number of characters where GDB should wrap lines of its output."), _("\
- Show number of characters where GDB should wrap lines of its output."), _("\
- This affects where GDB wraps its output to fit the screen width.\n\
- Setting this to \"unlimited\" or zero prevents GDB from wrapping its output."),
- set_width_command,
- show_chars_per_line,
- &setlist, &showlist);
- add_setshow_uinteger_cmd ("height", class_support, &lines_per_page, _("\
- Set number of lines in a page for GDB output pagination."), _("\
- Show number of lines in a page for GDB output pagination."), _("\
- This affects the number of lines after which GDB will pause\n\
- its output and ask you whether to continue.\n\
- Setting this to \"unlimited\" or zero causes GDB never pause during output."),
- set_height_command,
- show_lines_per_page,
- &setlist, &showlist);
- add_setshow_boolean_cmd ("pagination", class_support,
- &pagination_enabled, _("\
- Set state of GDB output pagination."), _("\
- Show state of GDB output pagination."), _("\
- When pagination is ON, GDB pauses at end of each screenful of\n\
- its output and asks you whether to continue.\n\
- Turning pagination off is an alternative to \"set height unlimited\"."),
- NULL,
- show_pagination_enabled,
- &setlist, &showlist);
- add_setshow_boolean_cmd ("sevenbit-strings", class_support,
- &sevenbit_strings, _("\
- Set printing of 8-bit characters in strings as \\nnn."), _("\
- Show printing of 8-bit characters in strings as \\nnn."), NULL,
- NULL,
- show_sevenbit_strings,
- &setprintlist, &showprintlist);
- add_setshow_boolean_cmd ("timestamp", class_maintenance,
- &debug_timestamp, _("\
- Set timestamping of debugging messages."), _("\
- Show timestamping of debugging messages."), _("\
- When set, debugging messages will be marked with seconds and microseconds."),
- NULL,
- show_debug_timestamp,
- &setdebuglist, &showdebuglist);
- add_internal_problem_command (&internal_error_problem);
- add_internal_problem_command (&internal_warning_problem);
- add_internal_problem_command (&demangler_warning_problem);
- #if GDB_SELF_TEST
- selftests::register_test ("gdb_realpath", gdb_realpath_tests);
- selftests::register_test ("gdb_argv_array_view", gdb_argv_as_array_view_test);
- selftests::register_test ("strncmp_iw_with_mode",
- strncmp_iw_with_mode_tests);
- #endif
- }
|