123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630 |
- /* Machine independent support for Solaris /proc (process file system) for GDB.
- Copyright (C) 1999-2022 Free Software Foundation, Inc.
- Written by Michael Snyder at Cygnus Solutions.
- Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others.
- 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 "inferior.h"
- #include "infrun.h"
- #include "target.h"
- #include "gdbcore.h"
- #include "elf-bfd.h" /* for elfcore_write_* */
- #include "gdbcmd.h"
- #include "gdbthread.h"
- #include "regcache.h"
- #include "inf-child.h"
- #include "nat/fork-inferior.h"
- #include "gdbarch.h"
- #include <sys/procfs.h>
- #include <sys/fault.h>
- #include <sys/syscall.h>
- #include "gdbsupport/gdb_wait.h"
- #include <signal.h>
- #include <ctype.h>
- #include "gdb_bfd.h"
- #include "auxv.h"
- #include "procfs.h"
- #include "observable.h"
- #include "gdbsupport/scoped_fd.h"
- #include "gdbsupport/pathstuff.h"
- #include "gdbsupport/buildargv.h"
- /* This module provides the interface between GDB and the
- /proc file system, which is used on many versions of Unix
- as a means for debuggers to control other processes.
- /proc works by imitating a file system: you open a simulated file
- that represents the process you wish to interact with, and perform
- operations on that "file" in order to examine or change the state
- of the other process.
- The most important thing to know about /proc and this module is
- that there are two very different interfaces to /proc:
- One that uses the ioctl system call, and another that uses read
- and write system calls.
- This module supports only the Solaris version of the read/write
- interface. */
- #include <sys/types.h>
- #include <dirent.h> /* opendir/readdir, for listing the LWP's */
- #include <fcntl.h> /* for O_RDONLY */
- #include <unistd.h> /* for "X_OK" */
- #include <sys/stat.h> /* for struct stat */
- /* Note: procfs-utils.h must be included after the above system header
- files, because it redefines various system calls using macros.
- This may be incompatible with the prototype declarations. */
- #include "proc-utils.h"
- /* Prototypes for supply_gregset etc. */
- #include "gregset.h"
- /* =================== TARGET_OPS "MODULE" =================== */
- /* This module defines the GDB target vector and its methods. */
- static enum target_xfer_status procfs_xfer_memory (gdb_byte *,
- const gdb_byte *,
- ULONGEST, ULONGEST,
- ULONGEST *);
- class procfs_target final : public inf_child_target
- {
- public:
- void create_inferior (const char *, const std::string &,
- char **, int) override;
- void kill () override;
- void mourn_inferior () override;
- void attach (const char *, int) override;
- void detach (inferior *inf, int) override;
- void resume (ptid_t, int, enum gdb_signal) override;
- ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
- void fetch_registers (struct regcache *, int) override;
- void store_registers (struct regcache *, int) override;
- enum target_xfer_status xfer_partial (enum target_object object,
- const char *annex,
- gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset, ULONGEST len,
- ULONGEST *xfered_len) override;
- void pass_signals (gdb::array_view<const unsigned char>) override;
- void files_info () override;
- void update_thread_list () override;
- bool thread_alive (ptid_t ptid) override;
- std::string pid_to_str (ptid_t) override;
- char *pid_to_exec_file (int pid) override;
- thread_control_capabilities get_thread_control_capabilities () override
- { return tc_schedlock; }
- /* find_memory_regions support method for gcore */
- int find_memory_regions (find_memory_region_ftype func, void *data)
- override;
- gdb::unique_xmalloc_ptr<char> make_corefile_notes (bfd *, int *) override;
- bool info_proc (const char *, enum info_proc_what) override;
- #if PR_MODEL_NATIVE == PR_MODEL_LP64
- int auxv_parse (gdb_byte **readptr,
- gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
- override;
- #endif
- bool stopped_by_watchpoint () override;
- int insert_watchpoint (CORE_ADDR, int, enum target_hw_bp_type,
- struct expression *) override;
- int remove_watchpoint (CORE_ADDR, int, enum target_hw_bp_type,
- struct expression *) override;
- int region_ok_for_hw_watchpoint (CORE_ADDR, int) override;
- int can_use_hw_breakpoint (enum bptype, int, int) override;
- bool stopped_data_address (CORE_ADDR *) override;
- void procfs_init_inferior (int pid);
- };
- static procfs_target the_procfs_target;
- #if PR_MODEL_NATIVE == PR_MODEL_LP64
- /* When GDB is built as 64-bit application on Solaris, the auxv data
- is presented in 64-bit format. We need to provide a custom parser
- to handle that. */
- int
- procfs_target::auxv_parse (gdb_byte **readptr,
- gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
- {
- enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
- gdb_byte *ptr = *readptr;
- if (endptr == ptr)
- return 0;
- if (endptr - ptr < 8 * 2)
- return -1;
- *typep = extract_unsigned_integer (ptr, 4, byte_order);
- ptr += 8;
- /* The size of data is always 64-bit. If the application is 32-bit,
- it will be zero extended, as expected. */
- *valp = extract_unsigned_integer (ptr, 8, byte_order);
- ptr += 8;
- *readptr = ptr;
- return 1;
- }
- #endif
- /* =================== END, TARGET_OPS "MODULE" =================== */
- /* =================== STRUCT PROCINFO "MODULE" =================== */
- /* FIXME: this comment will soon be out of date W.R.T. threads. */
- /* The procinfo struct is a wrapper to hold all the state information
- concerning a /proc process. There should be exactly one procinfo
- for each process, and since GDB currently can debug only one
- process at a time, that means there should be only one procinfo.
- All of the LWP's of a process can be accessed indirectly thru the
- single process procinfo.
- However, against the day when GDB may debug more than one process,
- this data structure is kept in a list (which for now will hold no
- more than one member), and many functions will have a pointer to a
- procinfo as an argument.
- There will be a separate procinfo structure for use by the (not yet
- implemented) "info proc" command, so that we can print useful
- information about any random process without interfering with the
- inferior's procinfo information. */
- /* format strings for /proc paths */
- #define CTL_PROC_NAME_FMT "/proc/%d/ctl"
- #define AS_PROC_NAME_FMT "/proc/%d/as"
- #define MAP_PROC_NAME_FMT "/proc/%d/map"
- #define STATUS_PROC_NAME_FMT "/proc/%d/status"
- #define MAX_PROC_NAME_SIZE sizeof("/proc/999999/lwp/0123456789/lwpstatus")
- typedef struct procinfo {
- struct procinfo *next;
- int pid; /* Process ID */
- int tid; /* Thread/LWP id */
- /* process state */
- int was_stopped;
- int ignore_next_sigstop;
- int ctl_fd; /* File descriptor for /proc control file */
- int status_fd; /* File descriptor for /proc status file */
- int as_fd; /* File descriptor for /proc as file */
- char pathname[MAX_PROC_NAME_SIZE]; /* Pathname to /proc entry */
- fltset_t saved_fltset; /* Saved traced hardware fault set */
- sigset_t saved_sigset; /* Saved traced signal set */
- sigset_t saved_sighold; /* Saved held signal set */
- sysset_t *saved_exitset; /* Saved traced system call exit set */
- sysset_t *saved_entryset; /* Saved traced system call entry set */
- pstatus_t prstatus; /* Current process status info */
- struct procinfo *thread_list;
- int status_valid : 1;
- int gregs_valid : 1;
- int fpregs_valid : 1;
- int threads_valid: 1;
- } procinfo;
- static char errmsg[128]; /* shared error msg buffer */
- /* Function prototypes for procinfo module: */
- static procinfo *find_procinfo_or_die (int pid, int tid);
- static procinfo *find_procinfo (int pid, int tid);
- static procinfo *create_procinfo (int pid, int tid);
- static void destroy_procinfo (procinfo *p);
- static void dead_procinfo (procinfo *p, const char *msg, int killp);
- static int open_procinfo_files (procinfo *p, int which);
- static void close_procinfo_files (procinfo *p);
- static int iterate_over_mappings
- (procinfo *pi, find_memory_region_ftype child_func, void *data,
- int (*func) (struct prmap *map, find_memory_region_ftype child_func,
- void *data));
- /* The head of the procinfo list: */
- static procinfo *procinfo_list;
- /* Search the procinfo list. Return a pointer to procinfo, or NULL if
- not found. */
- static procinfo *
- find_procinfo (int pid, int tid)
- {
- procinfo *pi;
- for (pi = procinfo_list; pi; pi = pi->next)
- if (pi->pid == pid)
- break;
- if (pi)
- if (tid)
- {
- /* Don't check threads_valid. If we're updating the
- thread_list, we want to find whatever threads are already
- here. This means that in general it is the caller's
- responsibility to check threads_valid and update before
- calling find_procinfo, if the caller wants to find a new
- thread. */
- for (pi = pi->thread_list; pi; pi = pi->next)
- if (pi->tid == tid)
- break;
- }
- return pi;
- }
- /* Calls find_procinfo, but errors on failure. */
- static procinfo *
- find_procinfo_or_die (int pid, int tid)
- {
- procinfo *pi = find_procinfo (pid, tid);
- if (pi == NULL)
- {
- if (tid)
- error (_("procfs: couldn't find pid %d "
- "(kernel thread %d) in procinfo list."),
- pid, tid);
- else
- error (_("procfs: couldn't find pid %d in procinfo list."), pid);
- }
- return pi;
- }
- /* Wrapper for `open'. The appropriate open call is attempted; if
- unsuccessful, it will be retried as many times as needed for the
- EAGAIN and EINTR conditions.
- For other conditions, retry the open a limited number of times. In
- addition, a short sleep is imposed prior to retrying the open. The
- reason for this sleep is to give the kernel a chance to catch up
- and create the file in question in the event that GDB "wins" the
- race to open a file before the kernel has created it. */
- static int
- open_with_retry (const char *pathname, int flags)
- {
- int retries_remaining, status;
- retries_remaining = 2;
- while (1)
- {
- status = open (pathname, flags);
- if (status >= 0 || retries_remaining == 0)
- break;
- else if (errno != EINTR && errno != EAGAIN)
- {
- retries_remaining--;
- sleep (1);
- }
- }
- return status;
- }
- /* Open the file descriptor for the process or LWP. We only open the
- control file descriptor; the others are opened lazily as needed.
- Returns the file descriptor, or zero for failure. */
- enum { FD_CTL, FD_STATUS, FD_AS };
- static int
- open_procinfo_files (procinfo *pi, int which)
- {
- char tmp[MAX_PROC_NAME_SIZE];
- int fd;
- /* This function is getting ALMOST long enough to break up into
- several. Here is some rationale:
- There are several file descriptors that may need to be open
- for any given process or LWP. The ones we're interested in are:
- - control (ctl) write-only change the state
- - status (status) read-only query the state
- - address space (as) read/write access memory
- - map (map) read-only virtual addr map
- Most of these are opened lazily as they are needed.
- The pathnames for the 'files' for an LWP look slightly
- different from those of a first-class process:
- Pathnames for a process (<proc-id>):
- /proc/<proc-id>/ctl
- /proc/<proc-id>/status
- /proc/<proc-id>/as
- /proc/<proc-id>/map
- Pathnames for an LWP (lwp-id):
- /proc/<proc-id>/lwp/<lwp-id>/lwpctl
- /proc/<proc-id>/lwp/<lwp-id>/lwpstatus
- An LWP has no map or address space file descriptor, since
- the memory map and address space are shared by all LWPs. */
- /* In this case, there are several different file descriptors that
- we might be asked to open. The control file descriptor will be
- opened early, but the others will be opened lazily as they are
- needed. */
- strcpy (tmp, pi->pathname);
- switch (which) { /* Which file descriptor to open? */
- case FD_CTL:
- if (pi->tid)
- strcat (tmp, "/lwpctl");
- else
- strcat (tmp, "/ctl");
- fd = open_with_retry (tmp, O_WRONLY);
- if (fd < 0)
- return 0; /* fail */
- pi->ctl_fd = fd;
- break;
- case FD_AS:
- if (pi->tid)
- return 0; /* There is no 'as' file descriptor for an lwp. */
- strcat (tmp, "/as");
- fd = open_with_retry (tmp, O_RDWR);
- if (fd < 0)
- return 0; /* fail */
- pi->as_fd = fd;
- break;
- case FD_STATUS:
- if (pi->tid)
- strcat (tmp, "/lwpstatus");
- else
- strcat (tmp, "/status");
- fd = open_with_retry (tmp, O_RDONLY);
- if (fd < 0)
- return 0; /* fail */
- pi->status_fd = fd;
- break;
- default:
- return 0; /* unknown file descriptor */
- }
- return 1; /* success */
- }
- /* Allocate a data structure and link it into the procinfo list.
- First tries to find a pre-existing one (FIXME: why?). Returns the
- pointer to new procinfo struct. */
- static procinfo *
- create_procinfo (int pid, int tid)
- {
- procinfo *pi, *parent = NULL;
- pi = find_procinfo (pid, tid);
- if (pi != NULL)
- return pi; /* Already exists, nothing to do. */
- /* Find parent before doing malloc, to save having to cleanup. */
- if (tid != 0)
- parent = find_procinfo_or_die (pid, 0); /* FIXME: should I
- create it if it
- doesn't exist yet? */
- pi = XNEW (procinfo);
- memset (pi, 0, sizeof (procinfo));
- pi->pid = pid;
- pi->tid = tid;
- pi->saved_entryset = XNEW (sysset_t);
- pi->saved_exitset = XNEW (sysset_t);
- /* Chain into list. */
- if (tid == 0)
- {
- xsnprintf (pi->pathname, sizeof (pi->pathname), "/proc/%d", pid);
- pi->next = procinfo_list;
- procinfo_list = pi;
- }
- else
- {
- xsnprintf (pi->pathname, sizeof (pi->pathname), "/proc/%d/lwp/%d",
- pid, tid);
- pi->next = parent->thread_list;
- parent->thread_list = pi;
- }
- return pi;
- }
- /* Close all file descriptors associated with the procinfo. */
- static void
- close_procinfo_files (procinfo *pi)
- {
- if (pi->ctl_fd > 0)
- close (pi->ctl_fd);
- if (pi->as_fd > 0)
- close (pi->as_fd);
- if (pi->status_fd > 0)
- close (pi->status_fd);
- pi->ctl_fd = pi->as_fd = pi->status_fd = 0;
- }
- /* Destructor function. Close, unlink and deallocate the object. */
- static void
- destroy_one_procinfo (procinfo **list, procinfo *pi)
- {
- procinfo *ptr;
- /* Step one: unlink the procinfo from its list. */
- if (pi == *list)
- *list = pi->next;
- else
- for (ptr = *list; ptr; ptr = ptr->next)
- if (ptr->next == pi)
- {
- ptr->next = pi->next;
- break;
- }
- /* Step two: close any open file descriptors. */
- close_procinfo_files (pi);
- /* Step three: free the memory. */
- xfree (pi->saved_entryset);
- xfree (pi->saved_exitset);
- xfree (pi);
- }
- static void
- destroy_procinfo (procinfo *pi)
- {
- procinfo *tmp;
- if (pi->tid != 0) /* Destroy a thread procinfo. */
- {
- tmp = find_procinfo (pi->pid, 0); /* Find the parent process. */
- destroy_one_procinfo (&tmp->thread_list, pi);
- }
- else /* Destroy a process procinfo and all its threads. */
- {
- /* First destroy the children, if any; */
- while (pi->thread_list != NULL)
- destroy_one_procinfo (&pi->thread_list, pi->thread_list);
- /* Then destroy the parent. Genocide!!! */
- destroy_one_procinfo (&procinfo_list, pi);
- }
- }
- /* A deleter that calls destroy_procinfo. */
- struct procinfo_deleter
- {
- void operator() (procinfo *pi) const
- {
- destroy_procinfo (pi);
- }
- };
- typedef std::unique_ptr<procinfo, procinfo_deleter> procinfo_up;
- enum { NOKILL, KILL };
- /* To be called on a non_recoverable error for a procinfo. Prints
- error messages, optionally sends a SIGKILL to the process, then
- destroys the data structure. */
- static void
- dead_procinfo (procinfo *pi, const char *msg, int kill_p)
- {
- char procfile[80];
- if (pi->pathname)
- print_sys_errmsg (pi->pathname, errno);
- else
- {
- xsnprintf (procfile, sizeof (procfile), "process %d", pi->pid);
- print_sys_errmsg (procfile, errno);
- }
- if (kill_p == KILL)
- kill (pi->pid, SIGKILL);
- destroy_procinfo (pi);
- error ("%s", msg);
- }
- /* =================== END, STRUCT PROCINFO "MODULE" =================== */
- /* =================== /proc "MODULE" =================== */
- /* This "module" is the interface layer between the /proc system API
- and the gdb target vector functions. This layer consists of access
- functions that encapsulate each of the basic operations that we
- need to use from the /proc API.
- The main motivation for this layer is to hide the fact that there
- were two very different implementations of the /proc API. */
- static long proc_flags (procinfo *pi);
- static int proc_why (procinfo *pi);
- static int proc_what (procinfo *pi);
- static int proc_set_current_signal (procinfo *pi, int signo);
- static int proc_get_current_thread (procinfo *pi);
- static int proc_iterate_over_threads
- (procinfo *pi,
- int (*func) (procinfo *, procinfo *, void *),
- void *ptr);
- static void
- proc_warn (procinfo *pi, const char *func, int line)
- {
- xsnprintf (errmsg, sizeof (errmsg), "procfs: %s line %d, %s",
- func, line, pi->pathname);
- print_sys_errmsg (errmsg, errno);
- }
- static void
- proc_error (procinfo *pi, const char *func, int line)
- {
- xsnprintf (errmsg, sizeof (errmsg), "procfs: %s line %d, %s",
- func, line, pi->pathname);
- perror_with_name (errmsg);
- }
- /* Updates the status struct in the procinfo. There is a 'valid'
- flag, to let other functions know when this function needs to be
- called (so the status is only read when it is needed). The status
- file descriptor is also only opened when it is needed. Returns
- non-zero for success, zero for failure. */
- static int
- proc_get_status (procinfo *pi)
- {
- /* Status file descriptor is opened "lazily". */
- if (pi->status_fd == 0 && open_procinfo_files (pi, FD_STATUS) == 0)
- {
- pi->status_valid = 0;
- return 0;
- }
- if (lseek (pi->status_fd, 0, SEEK_SET) < 0)
- pi->status_valid = 0; /* fail */
- else
- {
- /* Sigh... I have to read a different data structure,
- depending on whether this is a main process or an LWP. */
- if (pi->tid)
- pi->status_valid = (read (pi->status_fd,
- (char *) &pi->prstatus.pr_lwp,
- sizeof (lwpstatus_t))
- == sizeof (lwpstatus_t));
- else
- {
- pi->status_valid = (read (pi->status_fd,
- (char *) &pi->prstatus,
- sizeof (pstatus_t))
- == sizeof (pstatus_t));
- }
- }
- if (pi->status_valid)
- {
- PROC_PRETTYFPRINT_STATUS (proc_flags (pi),
- proc_why (pi),
- proc_what (pi),
- proc_get_current_thread (pi));
- }
- /* The status struct includes general regs, so mark them valid too. */
- pi->gregs_valid = pi->status_valid;
- /* In the read/write multiple-fd model, the status struct includes
- the fp regs too, so mark them valid too. */
- pi->fpregs_valid = pi->status_valid;
- return pi->status_valid; /* True if success, false if failure. */
- }
- /* Returns the process flags (pr_flags field). */
- static long
- proc_flags (procinfo *pi)
- {
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return 0; /* FIXME: not a good failure value (but what is?) */
- return pi->prstatus.pr_lwp.pr_flags;
- }
- /* Returns the pr_why field (why the process stopped). */
- static int
- proc_why (procinfo *pi)
- {
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return 0; /* FIXME: not a good failure value (but what is?) */
- return pi->prstatus.pr_lwp.pr_why;
- }
- /* Returns the pr_what field (details of why the process stopped). */
- static int
- proc_what (procinfo *pi)
- {
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return 0; /* FIXME: not a good failure value (but what is?) */
- return pi->prstatus.pr_lwp.pr_what;
- }
- /* This function is only called when PI is stopped by a watchpoint.
- Assuming the OS supports it, write to *ADDR the data address which
- triggered it and return 1. Return 0 if it is not possible to know
- the address. */
- static int
- proc_watchpoint_address (procinfo *pi, CORE_ADDR *addr)
- {
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return 0;
- *addr = (CORE_ADDR) gdbarch_pointer_to_address (target_gdbarch (),
- builtin_type (target_gdbarch ())->builtin_data_ptr,
- (gdb_byte *) &pi->prstatus.pr_lwp.pr_info.si_addr);
- return 1;
- }
- /* Returns the pr_nsysarg field (number of args to the current
- syscall). */
- static int
- proc_nsysarg (procinfo *pi)
- {
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return 0;
- return pi->prstatus.pr_lwp.pr_nsysarg;
- }
- /* Returns the pr_sysarg field (pointer to the arguments of current
- syscall). */
- static long *
- proc_sysargs (procinfo *pi)
- {
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return NULL;
- return (long *) &pi->prstatus.pr_lwp.pr_sysarg;
- }
- /* Set or reset any of the following process flags:
- PR_FORK -- forked child will inherit trace flags
- PR_RLC -- traced process runs when last /proc file closed.
- PR_KLC -- traced process is killed when last /proc file closed.
- PR_ASYNC -- LWP's get to run/stop independently.
- This function is done using read/write [PCSET/PCRESET/PCUNSET].
- Arguments:
- pi -- the procinfo
- flag -- one of PR_FORK, PR_RLC, or PR_ASYNC
- mode -- 1 for set, 0 for reset.
- Returns non-zero for success, zero for failure. */
- enum { FLAG_RESET, FLAG_SET };
- static int
- proc_modify_flag (procinfo *pi, long flag, long mode)
- {
- long win = 0; /* default to fail */
- /* These operations affect the process as a whole, and applying them
- to an individual LWP has the same meaning as applying them to the
- main process. Therefore, if we're ever called with a pointer to
- an LWP's procinfo, let's substitute the process's procinfo and
- avoid opening the LWP's file descriptor unnecessarily. */
- if (pi->pid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- procfs_ctl_t arg[2];
- if (mode == FLAG_SET) /* Set the flag (RLC, FORK, or ASYNC). */
- arg[0] = PCSET;
- else /* Reset the flag. */
- arg[0] = PCUNSET;
- arg[1] = flag;
- win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
- /* The above operation renders the procinfo's cached pstatus
- obsolete. */
- pi->status_valid = 0;
- if (!win)
- warning (_("procfs: modify_flag failed to turn %s %s"),
- flag == PR_FORK ? "PR_FORK" :
- flag == PR_RLC ? "PR_RLC" :
- flag == PR_ASYNC ? "PR_ASYNC" :
- flag == PR_KLC ? "PR_KLC" :
- "<unknown flag>",
- mode == FLAG_RESET ? "off" : "on");
- return win;
- }
- /* Set the run_on_last_close flag. Process with all threads will
- become runnable when debugger closes all /proc fds. Returns
- non-zero for success, zero for failure. */
- static int
- proc_set_run_on_last_close (procinfo *pi)
- {
- return proc_modify_flag (pi, PR_RLC, FLAG_SET);
- }
- /* Reset the run_on_last_close flag. The process will NOT become
- runnable when debugger closes its file handles. Returns non-zero
- for success, zero for failure. */
- static int
- proc_unset_run_on_last_close (procinfo *pi)
- {
- return proc_modify_flag (pi, PR_RLC, FLAG_RESET);
- }
- /* Reset inherit_on_fork flag. If the process forks a child while we
- are registered for events in the parent, then we will NOT receive
- events from the child. Returns non-zero for success, zero for
- failure. */
- static int
- proc_unset_inherit_on_fork (procinfo *pi)
- {
- return proc_modify_flag (pi, PR_FORK, FLAG_RESET);
- }
- /* Set PR_ASYNC flag. If one LWP stops because of a debug event
- (signal etc.), the remaining LWPs will continue to run. Returns
- non-zero for success, zero for failure. */
- static int
- proc_set_async (procinfo *pi)
- {
- return proc_modify_flag (pi, PR_ASYNC, FLAG_SET);
- }
- /* Reset PR_ASYNC flag. If one LWP stops because of a debug event
- (signal etc.), then all other LWPs will stop as well. Returns
- non-zero for success, zero for failure. */
- static int
- proc_unset_async (procinfo *pi)
- {
- return proc_modify_flag (pi, PR_ASYNC, FLAG_RESET);
- }
- /* Request the process/LWP to stop. Does not wait. Returns non-zero
- for success, zero for failure. */
- static int
- proc_stop_process (procinfo *pi)
- {
- int win;
- /* We might conceivably apply this operation to an LWP, and the
- LWP's ctl file descriptor might not be open. */
- if (pi->ctl_fd == 0 && open_procinfo_files (pi, FD_CTL) == 0)
- return 0;
- else
- {
- procfs_ctl_t cmd = PCSTOP;
- win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd));
- }
- return win;
- }
- /* Wait for the process or LWP to stop (block until it does). Returns
- non-zero for success, zero for failure. */
- static int
- proc_wait_for_stop (procinfo *pi)
- {
- int win;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- procfs_ctl_t cmd = PCWSTOP;
- set_sigint_trap ();
- win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd));
- clear_sigint_trap ();
- /* We been runnin' and we stopped -- need to update status. */
- pi->status_valid = 0;
- return win;
- }
- /* Make the process or LWP runnable.
- Options (not all are implemented):
- - single-step
- - clear current fault
- - clear current signal
- - abort the current system call
- - stop as soon as finished with system call
- Always clears the current fault. PI is the process or LWP to
- operate on. If STEP is true, set the process or LWP to trap after
- one instruction. If SIGNO is zero, clear the current signal if
- any; if non-zero, set the current signal to this one. Returns
- non-zero for success, zero for failure. */
- static int
- proc_run_process (procinfo *pi, int step, int signo)
- {
- int win;
- int runflags;
- /* We will probably have to apply this operation to individual
- threads, so make sure the control file descriptor is open. */
- if (pi->ctl_fd == 0 && open_procinfo_files (pi, FD_CTL) == 0)
- return 0;
- runflags = PRCFAULT; /* Always clear current fault. */
- if (step)
- runflags |= PRSTEP;
- if (signo == 0)
- runflags |= PRCSIG;
- else if (signo != -1) /* -1 means do nothing W.R.T. signals. */
- proc_set_current_signal (pi, signo);
- procfs_ctl_t cmd[2];
- cmd[0] = PCRUN;
- cmd[1] = runflags;
- win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd));
- return win;
- }
- /* Register to trace signals in the process or LWP. Returns non-zero
- for success, zero for failure. */
- static int
- proc_set_traced_signals (procinfo *pi, sigset_t *sigset)
- {
- int win;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- struct {
- procfs_ctl_t cmd;
- /* Use char array to avoid alignment issues. */
- char sigset[sizeof (sigset_t)];
- } arg;
- arg.cmd = PCSTRACE;
- memcpy (&arg.sigset, sigset, sizeof (sigset_t));
- win = (write (pi->ctl_fd, (char *) &arg, sizeof (arg)) == sizeof (arg));
- /* The above operation renders the procinfo's cached pstatus obsolete. */
- pi->status_valid = 0;
- if (!win)
- warning (_("procfs: set_traced_signals failed"));
- return win;
- }
- /* Register to trace hardware faults in the process or LWP. Returns
- non-zero for success, zero for failure. */
- static int
- proc_set_traced_faults (procinfo *pi, fltset_t *fltset)
- {
- int win;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- struct {
- procfs_ctl_t cmd;
- /* Use char array to avoid alignment issues. */
- char fltset[sizeof (fltset_t)];
- } arg;
- arg.cmd = PCSFAULT;
- memcpy (&arg.fltset, fltset, sizeof (fltset_t));
- win = (write (pi->ctl_fd, (char *) &arg, sizeof (arg)) == sizeof (arg));
- /* The above operation renders the procinfo's cached pstatus obsolete. */
- pi->status_valid = 0;
- return win;
- }
- /* Register to trace entry to system calls in the process or LWP.
- Returns non-zero for success, zero for failure. */
- static int
- proc_set_traced_sysentry (procinfo *pi, sysset_t *sysset)
- {
- int win;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- struct {
- procfs_ctl_t cmd;
- /* Use char array to avoid alignment issues. */
- char sysset[sizeof (sysset_t)];
- } arg;
- arg.cmd = PCSENTRY;
- memcpy (&arg.sysset, sysset, sizeof (sysset_t));
- win = (write (pi->ctl_fd, (char *) &arg, sizeof (arg)) == sizeof (arg));
- /* The above operation renders the procinfo's cached pstatus
- obsolete. */
- pi->status_valid = 0;
- return win;
- }
- /* Register to trace exit from system calls in the process or LWP.
- Returns non-zero for success, zero for failure. */
- static int
- proc_set_traced_sysexit (procinfo *pi, sysset_t *sysset)
- {
- int win;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- struct gdb_proc_ctl_pcsexit {
- procfs_ctl_t cmd;
- /* Use char array to avoid alignment issues. */
- char sysset[sizeof (sysset_t)];
- } arg;
- arg.cmd = PCSEXIT;
- memcpy (&arg.sysset, sysset, sizeof (sysset_t));
- win = (write (pi->ctl_fd, (char *) &arg, sizeof (arg)) == sizeof (arg));
- /* The above operation renders the procinfo's cached pstatus
- obsolete. */
- pi->status_valid = 0;
- return win;
- }
- /* Specify the set of blocked / held signals in the process or LWP.
- Returns non-zero for success, zero for failure. */
- static int
- proc_set_held_signals (procinfo *pi, sigset_t *sighold)
- {
- int win;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- struct {
- procfs_ctl_t cmd;
- /* Use char array to avoid alignment issues. */
- char hold[sizeof (sigset_t)];
- } arg;
- arg.cmd = PCSHOLD;
- memcpy (&arg.hold, sighold, sizeof (sigset_t));
- win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
- /* The above operation renders the procinfo's cached pstatus
- obsolete. */
- pi->status_valid = 0;
- return win;
- }
- /* Returns the set of signals that are held / blocked. Will also copy
- the sigset if SAVE is non-zero. */
- static sigset_t *
- proc_get_held_signals (procinfo *pi, sigset_t *save)
- {
- sigset_t *ret = NULL;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return NULL;
- ret = &pi->prstatus.pr_lwp.pr_lwphold;
- if (save && ret)
- memcpy (save, ret, sizeof (sigset_t));
- return ret;
- }
- /* Returns the set of signals that are traced / debugged. Will also
- copy the sigset if SAVE is non-zero. */
- static sigset_t *
- proc_get_traced_signals (procinfo *pi, sigset_t *save)
- {
- sigset_t *ret = NULL;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return NULL;
- ret = &pi->prstatus.pr_sigtrace;
- if (save && ret)
- memcpy (save, ret, sizeof (sigset_t));
- return ret;
- }
- /* Returns the set of hardware faults that are traced /debugged. Will
- also copy the faultset if SAVE is non-zero. */
- static fltset_t *
- proc_get_traced_faults (procinfo *pi, fltset_t *save)
- {
- fltset_t *ret = NULL;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return NULL;
- ret = &pi->prstatus.pr_flttrace;
- if (save && ret)
- memcpy (save, ret, sizeof (fltset_t));
- return ret;
- }
- /* Returns the set of syscalls that are traced /debugged on entry.
- Will also copy the syscall set if SAVE is non-zero. */
- static sysset_t *
- proc_get_traced_sysentry (procinfo *pi, sysset_t *save)
- {
- sysset_t *ret = NULL;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return NULL;
- ret = &pi->prstatus.pr_sysentry;
- if (save && ret)
- memcpy (save, ret, sizeof (sysset_t));
- return ret;
- }
- /* Returns the set of syscalls that are traced /debugged on exit.
- Will also copy the syscall set if SAVE is non-zero. */
- static sysset_t *
- proc_get_traced_sysexit (procinfo *pi, sysset_t *save)
- {
- sysset_t *ret = NULL;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return NULL;
- ret = &pi->prstatus.pr_sysexit;
- if (save && ret)
- memcpy (save, ret, sizeof (sysset_t));
- return ret;
- }
- /* The current fault (if any) is cleared; the associated signal will
- not be sent to the process or LWP when it resumes. Returns
- non-zero for success, zero for failure. */
- static int
- proc_clear_current_fault (procinfo *pi)
- {
- int win;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- procfs_ctl_t cmd = PCCFAULT;
- win = (write (pi->ctl_fd, (void *) &cmd, sizeof (cmd)) == sizeof (cmd));
- return win;
- }
- /* Set the "current signal" that will be delivered next to the
- process. NOTE: semantics are different from those of KILL. This
- signal will be delivered to the process or LWP immediately when it
- is resumed (even if the signal is held/blocked); it will NOT
- immediately cause another event of interest, and will NOT first
- trap back to the debugger. Returns non-zero for success, zero for
- failure. */
- static int
- proc_set_current_signal (procinfo *pi, int signo)
- {
- int win;
- struct {
- procfs_ctl_t cmd;
- /* Use char array to avoid alignment issues. */
- char sinfo[sizeof (siginfo_t)];
- } arg;
- siginfo_t mysinfo;
- process_stratum_target *wait_target;
- ptid_t wait_ptid;
- struct target_waitstatus wait_status;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- /* The pointer is just a type alias. */
- get_last_target_status (&wait_target, &wait_ptid, &wait_status);
- if (wait_target == &the_procfs_target
- && wait_ptid == inferior_ptid
- && wait_status.kind () == TARGET_WAITKIND_STOPPED
- && wait_status.sig () == gdb_signal_from_host (signo)
- && proc_get_status (pi)
- && pi->prstatus.pr_lwp.pr_info.si_signo == signo
- )
- /* Use the siginfo associated with the signal being
- redelivered. */
- memcpy (arg.sinfo, &pi->prstatus.pr_lwp.pr_info, sizeof (siginfo_t));
- else
- {
- mysinfo.si_signo = signo;
- mysinfo.si_code = 0;
- mysinfo.si_pid = getpid (); /* ?why? */
- mysinfo.si_uid = getuid (); /* ?why? */
- memcpy (arg.sinfo, &mysinfo, sizeof (siginfo_t));
- }
- arg.cmd = PCSSIG;
- win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
- return win;
- }
- /* The current signal (if any) is cleared, and is not sent to the
- process or LWP when it resumes. Returns non-zero for success, zero
- for failure. */
- static int
- proc_clear_current_signal (procinfo *pi)
- {
- int win;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- struct {
- procfs_ctl_t cmd;
- /* Use char array to avoid alignment issues. */
- char sinfo[sizeof (siginfo_t)];
- } arg;
- siginfo_t mysinfo;
- arg.cmd = PCSSIG;
- /* The pointer is just a type alias. */
- mysinfo.si_signo = 0;
- mysinfo.si_code = 0;
- mysinfo.si_errno = 0;
- mysinfo.si_pid = getpid (); /* ?why? */
- mysinfo.si_uid = getuid (); /* ?why? */
- memcpy (arg.sinfo, &mysinfo, sizeof (siginfo_t));
- win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
- return win;
- }
- /* Return the general-purpose registers for the process or LWP
- corresponding to PI. Upon failure, return NULL. */
- static gdb_gregset_t *
- proc_get_gregs (procinfo *pi)
- {
- if (!pi->status_valid || !pi->gregs_valid)
- if (!proc_get_status (pi))
- return NULL;
- return &pi->prstatus.pr_lwp.pr_reg;
- }
- /* Return the general-purpose registers for the process or LWP
- corresponding to PI. Upon failure, return NULL. */
- static gdb_fpregset_t *
- proc_get_fpregs (procinfo *pi)
- {
- if (!pi->status_valid || !pi->fpregs_valid)
- if (!proc_get_status (pi))
- return NULL;
- return &pi->prstatus.pr_lwp.pr_fpreg;
- }
- /* Write the general-purpose registers back to the process or LWP
- corresponding to PI. Return non-zero for success, zero for
- failure. */
- static int
- proc_set_gregs (procinfo *pi)
- {
- gdb_gregset_t *gregs;
- int win;
- gregs = proc_get_gregs (pi);
- if (gregs == NULL)
- return 0; /* proc_get_regs has already warned. */
- if (pi->ctl_fd == 0 && open_procinfo_files (pi, FD_CTL) == 0)
- return 0;
- else
- {
- struct {
- procfs_ctl_t cmd;
- /* Use char array to avoid alignment issues. */
- char gregs[sizeof (gdb_gregset_t)];
- } arg;
- arg.cmd = PCSREG;
- memcpy (&arg.gregs, gregs, sizeof (arg.gregs));
- win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
- }
- /* Policy: writing the registers invalidates our cache. */
- pi->gregs_valid = 0;
- return win;
- }
- /* Write the floating-pointer registers back to the process or LWP
- corresponding to PI. Return non-zero for success, zero for
- failure. */
- static int
- proc_set_fpregs (procinfo *pi)
- {
- gdb_fpregset_t *fpregs;
- int win;
- fpregs = proc_get_fpregs (pi);
- if (fpregs == NULL)
- return 0; /* proc_get_fpregs has already warned. */
- if (pi->ctl_fd == 0 && open_procinfo_files (pi, FD_CTL) == 0)
- return 0;
- else
- {
- struct {
- procfs_ctl_t cmd;
- /* Use char array to avoid alignment issues. */
- char fpregs[sizeof (gdb_fpregset_t)];
- } arg;
- arg.cmd = PCSFPREG;
- memcpy (&arg.fpregs, fpregs, sizeof (arg.fpregs));
- win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
- }
- /* Policy: writing the registers invalidates our cache. */
- pi->fpregs_valid = 0;
- return win;
- }
- /* Send a signal to the proc or lwp with the semantics of "kill()".
- Returns non-zero for success, zero for failure. */
- static int
- proc_kill (procinfo *pi, int signo)
- {
- int win;
- /* We might conceivably apply this operation to an LWP, and the
- LWP's ctl file descriptor might not be open. */
- if (pi->ctl_fd == 0 && open_procinfo_files (pi, FD_CTL) == 0)
- return 0;
- else
- {
- procfs_ctl_t cmd[2];
- cmd[0] = PCKILL;
- cmd[1] = signo;
- win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd));
- }
- return win;
- }
- /* Find the pid of the process that started this one. Returns the
- parent process pid, or zero. */
- static int
- proc_parent_pid (procinfo *pi)
- {
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return 0;
- return pi->prstatus.pr_ppid;
- }
- /* Convert a target address (a.k.a. CORE_ADDR) into a host address
- (a.k.a void pointer)! */
- static void *
- procfs_address_to_host_pointer (CORE_ADDR addr)
- {
- struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
- void *ptr;
- gdb_assert (sizeof (ptr) == TYPE_LENGTH (ptr_type));
- gdbarch_address_to_pointer (target_gdbarch (), ptr_type,
- (gdb_byte *) &ptr, addr);
- return ptr;
- }
- static int
- proc_set_watchpoint (procinfo *pi, CORE_ADDR addr, int len, int wflags)
- {
- struct {
- procfs_ctl_t cmd;
- char watch[sizeof (prwatch_t)];
- } arg;
- prwatch_t pwatch;
- /* NOTE: cagney/2003-02-01: Even more horrible hack. Need to
- convert a target address into something that can be stored in a
- native data structure. */
- pwatch.pr_vaddr = (uintptr_t) procfs_address_to_host_pointer (addr);
- pwatch.pr_size = len;
- pwatch.pr_wflags = wflags;
- arg.cmd = PCWATCH;
- memcpy (arg.watch, &pwatch, sizeof (prwatch_t));
- return (write (pi->ctl_fd, &arg, sizeof (arg)) == sizeof (arg));
- }
- /* =============== END, non-thread part of /proc "MODULE" =============== */
- /* =================== Thread "MODULE" =================== */
- /* Returns the number of threads for the process. */
- static int
- proc_get_nthreads (procinfo *pi)
- {
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return 0;
- /* Only works for the process procinfo, because the LWP procinfos do not
- get prstatus filled in. */
- if (pi->tid != 0) /* Find the parent process procinfo. */
- pi = find_procinfo_or_die (pi->pid, 0);
- return pi->prstatus.pr_nlwp;
- }
- /* Return the ID of the thread that had an event of interest.
- (ie. the one that hit a breakpoint or other traced event). All
- other things being equal, this should be the ID of a thread that is
- currently executing. */
- static int
- proc_get_current_thread (procinfo *pi)
- {
- /* Note: this should be applied to the root procinfo for the
- process, not to the procinfo for an LWP. If applied to the
- procinfo for an LWP, it will simply return that LWP's ID. In
- that case, find the parent process procinfo. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- if (!pi->status_valid)
- if (!proc_get_status (pi))
- return 0;
- return pi->prstatus.pr_lwp.pr_lwpid;
- }
- /* Discover the IDs of all the threads within the process, and create
- a procinfo for each of them (chained to the parent). Returns
- non-zero for success, zero for failure. */
- static int
- proc_delete_dead_threads (procinfo *parent, procinfo *thread, void *ignore)
- {
- if (thread && parent) /* sanity */
- {
- thread->status_valid = 0;
- if (!proc_get_status (thread))
- destroy_one_procinfo (&parent->thread_list, thread);
- }
- return 0; /* keep iterating */
- }
- static int
- proc_update_threads (procinfo *pi)
- {
- char pathname[MAX_PROC_NAME_SIZE + 16];
- struct dirent *direntry;
- procinfo *thread;
- gdb_dir_up dirp;
- int lwpid;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- proc_iterate_over_threads (pi, proc_delete_dead_threads, NULL);
- /* Note: this brute-force method was originally devised for Unixware
- (support removed since), and will also work on Solaris 2.6 and
- 2.7. The original comment mentioned the existence of a much
- simpler and more elegant way to do this on Solaris, but didn't
- point out what that was. */
- strcpy (pathname, pi->pathname);
- strcat (pathname, "/lwp");
- dirp.reset (opendir (pathname));
- if (dirp == NULL)
- proc_error (pi, "update_threads, opendir", __LINE__);
- while ((direntry = readdir (dirp.get ())) != NULL)
- if (direntry->d_name[0] != '.') /* skip '.' and '..' */
- {
- lwpid = atoi (&direntry->d_name[0]);
- thread = create_procinfo (pi->pid, lwpid);
- if (thread == NULL)
- proc_error (pi, "update_threads, create_procinfo", __LINE__);
- }
- pi->threads_valid = 1;
- return 1;
- }
- /* Given a pointer to a function, call that function once for each lwp
- in the procinfo list, until the function returns non-zero, in which
- event return the value returned by the function.
- Note: this function does NOT call update_threads. If you want to
- discover new threads first, you must call that function explicitly.
- This function just makes a quick pass over the currently-known
- procinfos.
- PI is the parent process procinfo. FUNC is the per-thread
- function. PTR is an opaque parameter for function. Returns the
- first non-zero return value from the callee, or zero. */
- static int
- proc_iterate_over_threads (procinfo *pi,
- int (*func) (procinfo *, procinfo *, void *),
- void *ptr)
- {
- procinfo *thread, *next;
- int retval = 0;
- /* We should never have to apply this operation to any procinfo
- except the one for the main process. If that ever changes for
- any reason, then take out the following clause and replace it
- with one that makes sure the ctl_fd is open. */
- if (pi->tid != 0)
- pi = find_procinfo_or_die (pi->pid, 0);
- for (thread = pi->thread_list; thread != NULL; thread = next)
- {
- next = thread->next; /* In case thread is destroyed. */
- retval = (*func) (pi, thread, ptr);
- if (retval != 0)
- break;
- }
- return retval;
- }
- /* =================== END, Thread "MODULE" =================== */
- /* =================== END, /proc "MODULE" =================== */
- /* =================== GDB "MODULE" =================== */
- /* Here are all of the gdb target vector functions and their
- friends. */
- static void do_attach (ptid_t ptid);
- static void do_detach ();
- static void proc_trace_syscalls_1 (procinfo *pi, int syscallnum,
- int entry_or_exit, int mode, int from_tty);
- /* Sets up the inferior to be debugged. Registers to trace signals,
- hardware faults, and syscalls. Note: does not set RLC flag: caller
- may want to customize that. Returns zero for success (note!
- unlike most functions in this module); on failure, returns the LINE
- NUMBER where it failed! */
- static int
- procfs_debug_inferior (procinfo *pi)
- {
- fltset_t traced_faults;
- sigset_t traced_signals;
- sysset_t *traced_syscall_entries;
- sysset_t *traced_syscall_exits;
- int status;
- /* Register to trace hardware faults in the child. */
- prfillset (&traced_faults); /* trace all faults... */
- prdelset (&traced_faults, FLTPAGE); /* except page fault. */
- if (!proc_set_traced_faults (pi, &traced_faults))
- return __LINE__;
- /* Initially, register to trace all signals in the child. */
- prfillset (&traced_signals);
- if (!proc_set_traced_signals (pi, &traced_signals))
- return __LINE__;
- /* Register to trace the 'exit' system call (on entry). */
- traced_syscall_entries = XNEW (sysset_t);
- premptyset (traced_syscall_entries);
- praddset (traced_syscall_entries, SYS_exit);
- praddset (traced_syscall_entries, SYS_lwp_exit);
- status = proc_set_traced_sysentry (pi, traced_syscall_entries);
- xfree (traced_syscall_entries);
- if (!status)
- return __LINE__;
- /* Method for tracing exec syscalls. */
- traced_syscall_exits = XNEW (sysset_t);
- premptyset (traced_syscall_exits);
- praddset (traced_syscall_exits, SYS_execve);
- praddset (traced_syscall_exits, SYS_lwp_create);
- praddset (traced_syscall_exits, SYS_lwp_exit);
- status = proc_set_traced_sysexit (pi, traced_syscall_exits);
- xfree (traced_syscall_exits);
- if (!status)
- return __LINE__;
- return 0;
- }
- void
- procfs_target::attach (const char *args, int from_tty)
- {
- int pid;
- pid = parse_pid_to_attach (args);
- if (pid == getpid ())
- error (_("Attaching GDB to itself is not a good idea..."));
- /* Push the target if needed, ensure it gets un-pushed it if attach fails. */
- inferior *inf = current_inferior ();
- target_unpush_up unpusher;
- if (!inf->target_is_pushed (this))
- {
- inf->push_target (this);
- unpusher.reset (this);
- }
- target_announce_attach (from_tty, pid);
- do_attach (ptid_t (pid));
- /* Everything went fine, keep the target pushed. */
- unpusher.release ();
- }
- void
- procfs_target::detach (inferior *inf, int from_tty)
- {
- target_announce_detach (from_tty);
- do_detach ();
- switch_to_no_thread ();
- detach_inferior (inf);
- maybe_unpush_target ();
- }
- static void
- do_attach (ptid_t ptid)
- {
- procinfo *pi;
- struct inferior *inf;
- int fail;
- int lwpid;
- pi = create_procinfo (ptid.pid (), 0);
- if (pi == NULL)
- perror (_("procfs: out of memory in 'attach'"));
- if (!open_procinfo_files (pi, FD_CTL))
- {
- gdb_printf (gdb_stderr, "procfs:%d -- ", __LINE__);
- xsnprintf (errmsg, sizeof (errmsg),
- "do_attach: couldn't open /proc file for process %d",
- ptid.pid ());
- dead_procinfo (pi, errmsg, NOKILL);
- }
- /* Stop the process (if it isn't already stopped). */
- if (proc_flags (pi) & (PR_STOPPED | PR_ISTOP))
- {
- pi->was_stopped = 1;
- proc_prettyprint_why (proc_why (pi), proc_what (pi), 1);
- }
- else
- {
- pi->was_stopped = 0;
- /* Set the process to run again when we close it. */
- if (!proc_set_run_on_last_close (pi))
- dead_procinfo (pi, "do_attach: couldn't set RLC.", NOKILL);
- /* Now stop the process. */
- if (!proc_stop_process (pi))
- dead_procinfo (pi, "do_attach: couldn't stop the process.", NOKILL);
- pi->ignore_next_sigstop = 1;
- }
- /* Save some of the /proc state to be restored if we detach. */
- if (!proc_get_traced_faults (pi, &pi->saved_fltset))
- dead_procinfo (pi, "do_attach: couldn't save traced faults.", NOKILL);
- if (!proc_get_traced_signals (pi, &pi->saved_sigset))
- dead_procinfo (pi, "do_attach: couldn't save traced signals.", NOKILL);
- if (!proc_get_traced_sysentry (pi, pi->saved_entryset))
- dead_procinfo (pi, "do_attach: couldn't save traced syscall entries.",
- NOKILL);
- if (!proc_get_traced_sysexit (pi, pi->saved_exitset))
- dead_procinfo (pi, "do_attach: couldn't save traced syscall exits.",
- NOKILL);
- if (!proc_get_held_signals (pi, &pi->saved_sighold))
- dead_procinfo (pi, "do_attach: couldn't save held signals.", NOKILL);
- fail = procfs_debug_inferior (pi);
- if (fail != 0)
- dead_procinfo (pi, "do_attach: failed in procfs_debug_inferior", NOKILL);
- inf = current_inferior ();
- inferior_appeared (inf, pi->pid);
- /* Let GDB know that the inferior was attached. */
- inf->attach_flag = 1;
- /* Create a procinfo for the current lwp. */
- lwpid = proc_get_current_thread (pi);
- create_procinfo (pi->pid, lwpid);
- /* Add it to gdb's thread list. */
- ptid = ptid_t (pi->pid, lwpid, 0);
- thread_info *thr = add_thread (&the_procfs_target, ptid);
- switch_to_thread (thr);
- }
- static void
- do_detach ()
- {
- procinfo *pi;
- /* Find procinfo for the main process. */
- pi = find_procinfo_or_die (inferior_ptid.pid (),
- 0); /* FIXME: threads */
- if (!proc_set_traced_signals (pi, &pi->saved_sigset))
- proc_warn (pi, "do_detach, set_traced_signal", __LINE__);
- if (!proc_set_traced_faults (pi, &pi->saved_fltset))
- proc_warn (pi, "do_detach, set_traced_faults", __LINE__);
- if (!proc_set_traced_sysentry (pi, pi->saved_entryset))
- proc_warn (pi, "do_detach, set_traced_sysentry", __LINE__);
- if (!proc_set_traced_sysexit (pi, pi->saved_exitset))
- proc_warn (pi, "do_detach, set_traced_sysexit", __LINE__);
- if (!proc_set_held_signals (pi, &pi->saved_sighold))
- proc_warn (pi, "do_detach, set_held_signals", __LINE__);
- if (proc_flags (pi) & (PR_STOPPED | PR_ISTOP))
- if (!(pi->was_stopped)
- || query (_("Was stopped when attached, make it runnable again? ")))
- {
- /* Clear any pending signal. */
- if (!proc_clear_current_fault (pi))
- proc_warn (pi, "do_detach, clear_current_fault", __LINE__);
- if (!proc_clear_current_signal (pi))
- proc_warn (pi, "do_detach, clear_current_signal", __LINE__);
- if (!proc_set_run_on_last_close (pi))
- proc_warn (pi, "do_detach, set_rlc", __LINE__);
- }
- destroy_procinfo (pi);
- }
- /* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
- for all registers.
- NOTE: Since the /proc interface cannot give us individual
- registers, we pay no attention to REGNUM, and just fetch them all.
- This results in the possibility that we will do unnecessarily many
- fetches, since we may be called repeatedly for individual
- registers. So we cache the results, and mark the cache invalid
- when the process is resumed. */
- void
- procfs_target::fetch_registers (struct regcache *regcache, int regnum)
- {
- gdb_gregset_t *gregs;
- procinfo *pi;
- ptid_t ptid = regcache->ptid ();
- int pid = ptid.pid ();
- int tid = ptid.lwp ();
- struct gdbarch *gdbarch = regcache->arch ();
- pi = find_procinfo_or_die (pid, tid);
- if (pi == NULL)
- error (_("procfs: fetch_registers failed to find procinfo for %s"),
- target_pid_to_str (ptid).c_str ());
- gregs = proc_get_gregs (pi);
- if (gregs == NULL)
- proc_error (pi, "fetch_registers, get_gregs", __LINE__);
- supply_gregset (regcache, (const gdb_gregset_t *) gregs);
- if (gdbarch_fp0_regnum (gdbarch) >= 0) /* Do we have an FPU? */
- {
- gdb_fpregset_t *fpregs;
- if ((regnum >= 0 && regnum < gdbarch_fp0_regnum (gdbarch))
- || regnum == gdbarch_pc_regnum (gdbarch)
- || regnum == gdbarch_sp_regnum (gdbarch))
- return; /* Not a floating point register. */
- fpregs = proc_get_fpregs (pi);
- if (fpregs == NULL)
- proc_error (pi, "fetch_registers, get_fpregs", __LINE__);
- supply_fpregset (regcache, (const gdb_fpregset_t *) fpregs);
- }
- }
- /* Store register REGNUM back into the inferior. If REGNUM is -1, do
- this for all registers.
- NOTE: Since the /proc interface will not read individual registers,
- we will cache these requests until the process is resumed, and only
- then write them back to the inferior process.
- FIXME: is that a really bad idea? Have to think about cases where
- writing one register might affect the value of others, etc. */
- void
- procfs_target::store_registers (struct regcache *regcache, int regnum)
- {
- gdb_gregset_t *gregs;
- procinfo *pi;
- ptid_t ptid = regcache->ptid ();
- int pid = ptid.pid ();
- int tid = ptid.lwp ();
- struct gdbarch *gdbarch = regcache->arch ();
- pi = find_procinfo_or_die (pid, tid);
- if (pi == NULL)
- error (_("procfs: store_registers: failed to find procinfo for %s"),
- target_pid_to_str (ptid).c_str ());
- gregs = proc_get_gregs (pi);
- if (gregs == NULL)
- proc_error (pi, "store_registers, get_gregs", __LINE__);
- fill_gregset (regcache, gregs, regnum);
- if (!proc_set_gregs (pi))
- proc_error (pi, "store_registers, set_gregs", __LINE__);
- if (gdbarch_fp0_regnum (gdbarch) >= 0) /* Do we have an FPU? */
- {
- gdb_fpregset_t *fpregs;
- if ((regnum >= 0 && regnum < gdbarch_fp0_regnum (gdbarch))
- || regnum == gdbarch_pc_regnum (gdbarch)
- || regnum == gdbarch_sp_regnum (gdbarch))
- return; /* Not a floating point register. */
- fpregs = proc_get_fpregs (pi);
- if (fpregs == NULL)
- proc_error (pi, "store_registers, get_fpregs", __LINE__);
- fill_fpregset (regcache, fpregs, regnum);
- if (!proc_set_fpregs (pi))
- proc_error (pi, "store_registers, set_fpregs", __LINE__);
- }
- }
- /* Retrieve the next stop event from the child process. If child has
- not stopped yet, wait for it to stop. Translate /proc eventcodes
- (or possibly wait eventcodes) into gdb internal event codes.
- Returns the id of process (and possibly thread) that incurred the
- event. Event codes are returned through a pointer parameter. */
- ptid_t
- procfs_target::wait (ptid_t ptid, struct target_waitstatus *status,
- target_wait_flags options)
- {
- /* First cut: loosely based on original version 2.1. */
- procinfo *pi;
- int wstat;
- int temp_tid;
- ptid_t retval, temp_ptid;
- int why, what, flags;
- int retry = 0;
- wait_again:
- retry++;
- wstat = 0;
- retval = ptid_t (-1);
- /* Find procinfo for main process. */
- /* procfs_target currently only supports one inferior. */
- inferior *inf = current_inferior ();
- pi = find_procinfo_or_die (inf->pid, 0);
- if (pi)
- {
- /* We must assume that the status is stale now... */
- pi->status_valid = 0;
- pi->gregs_valid = 0;
- pi->fpregs_valid = 0;
- #if 0 /* just try this out... */
- flags = proc_flags (pi);
- why = proc_why (pi);
- if ((flags & PR_STOPPED) && (why == PR_REQUESTED))
- pi->status_valid = 0; /* re-read again, IMMEDIATELY... */
- #endif
- /* If child is not stopped, wait for it to stop. */
- if (!(proc_flags (pi) & (PR_STOPPED | PR_ISTOP))
- && !proc_wait_for_stop (pi))
- {
- /* wait_for_stop failed: has the child terminated? */
- if (errno == ENOENT)
- {
- int wait_retval;
- /* /proc file not found; presumably child has terminated. */
- wait_retval = ::wait (&wstat); /* "wait" for the child's exit. */
- /* Wrong child? */
- if (wait_retval != inf->pid)
- error (_("procfs: couldn't stop "
- "process %d: wait returned %d."),
- inf->pid, wait_retval);
- /* FIXME: might I not just use waitpid?
- Or try find_procinfo to see if I know about this child? */
- retval = ptid_t (wait_retval);
- }
- else if (errno == EINTR)
- goto wait_again;
- else
- {
- /* Unknown error from wait_for_stop. */
- proc_error (pi, "target_wait (wait_for_stop)", __LINE__);
- }
- }
- else
- {
- /* This long block is reached if either:
- a) the child was already stopped, or
- b) we successfully waited for the child with wait_for_stop.
- This block will analyze the /proc status, and translate it
- into a waitstatus for GDB.
- If we actually had to call wait because the /proc file
- is gone (child terminated), then we skip this block,
- because we already have a waitstatus. */
- flags = proc_flags (pi);
- why = proc_why (pi);
- what = proc_what (pi);
- if (flags & (PR_STOPPED | PR_ISTOP))
- {
- /* If it's running async (for single_thread control),
- set it back to normal again. */
- if (flags & PR_ASYNC)
- if (!proc_unset_async (pi))
- proc_error (pi, "target_wait, unset_async", __LINE__);
- if (info_verbose)
- proc_prettyprint_why (why, what, 1);
- /* The 'pid' we will return to GDB is composed of
- the process ID plus the lwp ID. */
- retval = ptid_t (pi->pid, proc_get_current_thread (pi), 0);
- switch (why) {
- case PR_SIGNALLED:
- wstat = (what << 8) | 0177;
- break;
- case PR_SYSENTRY:
- if (what == SYS_lwp_exit)
- {
- if (print_thread_events)
- gdb_printf (_("[%s exited]\n"),
- target_pid_to_str (retval).c_str ());
- delete_thread (find_thread_ptid (this, retval));
- target_continue_no_signal (ptid);
- goto wait_again;
- }
- else if (what == SYS_exit)
- {
- /* Handle SYS_exit call only. */
- /* Stopped at entry to SYS_exit.
- Make it runnable, resume it, then use
- the wait system call to get its exit code.
- Proc_run_process always clears the current
- fault and signal.
- Then return its exit status. */
- pi->status_valid = 0;
- wstat = 0;
- /* FIXME: what we should do is return
- TARGET_WAITKIND_SPURIOUS. */
- if (!proc_run_process (pi, 0, 0))
- proc_error (pi, "target_wait, run_process", __LINE__);
- if (inf->attach_flag)
- {
- /* Don't call wait: simulate waiting for exit,
- return a "success" exit code. Bogus: what if
- it returns something else? */
- wstat = 0;
- retval = ptid_t (inf->pid); /* ? ? ? */
- }
- else
- {
- int temp = ::wait (&wstat);
- /* FIXME: shouldn't I make sure I get the right
- event from the right process? If (for
- instance) I have killed an earlier inferior
- process but failed to clean up after it
- somehow, I could get its termination event
- here. */
- /* If wait returns -1, that's what we return
- to GDB. */
- if (temp < 0)
- retval = ptid_t (temp);
- }
- }
- else
- {
- gdb_printf (_("procfs: trapped on entry to "));
- proc_prettyprint_syscall (proc_what (pi), 0);
- gdb_printf ("\n");
- long i, nsysargs, *sysargs;
- nsysargs = proc_nsysarg (pi);
- sysargs = proc_sysargs (pi);
- if (nsysargs > 0 && sysargs != NULL)
- {
- gdb_printf (_("%ld syscall arguments:\n"),
- nsysargs);
- for (i = 0; i < nsysargs; i++)
- gdb_printf ("#%ld: 0x%08lx\n",
- i, sysargs[i]);
- }
- /* How to keep going without returning to wfi: */
- target_continue_no_signal (ptid);
- goto wait_again;
- }
- break;
- case PR_SYSEXIT:
- if (what == SYS_execve)
- {
- /* Hopefully this is our own "fork-child" execing
- the real child. Hoax this event into a trap, and
- GDB will see the child about to execute its start
- address. */
- wstat = (SIGTRAP << 8) | 0177;
- }
- else if (what == SYS_lwp_create)
- {
- /* This syscall is somewhat like fork/exec. We
- will get the event twice: once for the parent
- LWP, and once for the child. We should already
- know about the parent LWP, but the child will
- be new to us. So, whenever we get this event,
- if it represents a new thread, simply add the
- thread to the list. */
- /* If not in procinfo list, add it. */
- temp_tid = proc_get_current_thread (pi);
- if (!find_procinfo (pi->pid, temp_tid))
- create_procinfo (pi->pid, temp_tid);
- temp_ptid = ptid_t (pi->pid, temp_tid, 0);
- /* If not in GDB's thread list, add it. */
- if (!in_thread_list (this, temp_ptid))
- add_thread (this, temp_ptid);
- target_continue_no_signal (ptid);
- goto wait_again;
- }
- else if (what == SYS_lwp_exit)
- {
- if (print_thread_events)
- gdb_printf (_("[%s exited]\n"),
- target_pid_to_str (retval).c_str ());
- delete_thread (find_thread_ptid (this, retval));
- status->set_spurious ();
- return retval;
- }
- else
- {
- gdb_printf (_("procfs: trapped on exit from "));
- proc_prettyprint_syscall (proc_what (pi), 0);
- gdb_printf ("\n");
- long i, nsysargs, *sysargs;
- nsysargs = proc_nsysarg (pi);
- sysargs = proc_sysargs (pi);
- if (nsysargs > 0 && sysargs != NULL)
- {
- gdb_printf (_("%ld syscall arguments:\n"),
- nsysargs);
- for (i = 0; i < nsysargs; i++)
- gdb_printf ("#%ld: 0x%08lx\n",
- i, sysargs[i]);
- }
- target_continue_no_signal (ptid);
- goto wait_again;
- }
- break;
- case PR_REQUESTED:
- #if 0 /* FIXME */
- wstat = (SIGSTOP << 8) | 0177;
- break;
- #else
- if (retry < 5)
- {
- gdb_printf (_("Retry #%d:\n"), retry);
- pi->status_valid = 0;
- goto wait_again;
- }
- else
- {
- /* If not in procinfo list, add it. */
- temp_tid = proc_get_current_thread (pi);
- if (!find_procinfo (pi->pid, temp_tid))
- create_procinfo (pi->pid, temp_tid);
- /* If not in GDB's thread list, add it. */
- temp_ptid = ptid_t (pi->pid, temp_tid, 0);
- if (!in_thread_list (this, temp_ptid))
- add_thread (this, temp_ptid);
- status->set_stopped (GDB_SIGNAL_0);
- return retval;
- }
- #endif
- case PR_JOBCONTROL:
- wstat = (what << 8) | 0177;
- break;
- case PR_FAULTED:
- {
- int signo = pi->prstatus.pr_lwp.pr_info.si_signo;
- if (signo != 0)
- wstat = (signo << 8) | 0177;
- }
- break;
- default: /* switch (why) unmatched */
- gdb_printf ("procfs:%d -- ", __LINE__);
- gdb_printf (_("child stopped for unknown reason:\n"));
- proc_prettyprint_why (why, what, 1);
- error (_("... giving up..."));
- break;
- }
- /* Got this far without error: If retval isn't in the
- threads database, add it. */
- if (retval.pid () > 0
- && !in_thread_list (this, retval))
- {
- /* We have a new thread. We need to add it both to
- GDB's list and to our own. If we don't create a
- procinfo, resume may be unhappy later. */
- add_thread (this, retval);
- if (find_procinfo (retval.pid (),
- retval.lwp ()) == NULL)
- create_procinfo (retval.pid (),
- retval.lwp ());
- }
- }
- else /* Flags do not indicate STOPPED. */
- {
- /* surely this can't happen... */
- gdb_printf ("procfs:%d -- process not stopped.\n",
- __LINE__);
- proc_prettyprint_flags (flags, 1);
- error (_("procfs: ...giving up..."));
- }
- }
- if (status)
- *status = host_status_to_waitstatus (wstat);
- }
- return retval;
- }
- /* Perform a partial transfer to/from the specified object. For
- memory transfers, fall back to the old memory xfer functions. */
- enum target_xfer_status
- procfs_target::xfer_partial (enum target_object object,
- const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf, ULONGEST offset,
- ULONGEST len, ULONGEST *xfered_len)
- {
- switch (object)
- {
- case TARGET_OBJECT_MEMORY:
- return procfs_xfer_memory (readbuf, writebuf, offset, len, xfered_len);
- case TARGET_OBJECT_AUXV:
- return memory_xfer_auxv (this, object, annex, readbuf, writebuf,
- offset, len, xfered_len);
- default:
- return this->beneath ()->xfer_partial (object, annex,
- readbuf, writebuf, offset, len,
- xfered_len);
- }
- }
- /* Helper for procfs_xfer_partial that handles memory transfers.
- Arguments are like target_xfer_partial. */
- static enum target_xfer_status
- procfs_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf,
- ULONGEST memaddr, ULONGEST len, ULONGEST *xfered_len)
- {
- procinfo *pi;
- int nbytes;
- /* Find procinfo for main process. */
- pi = find_procinfo_or_die (inferior_ptid.pid (), 0);
- if (pi->as_fd == 0 && open_procinfo_files (pi, FD_AS) == 0)
- {
- proc_warn (pi, "xfer_memory, open_proc_files", __LINE__);
- return TARGET_XFER_E_IO;
- }
- if (lseek (pi->as_fd, (off_t) memaddr, SEEK_SET) != (off_t) memaddr)
- return TARGET_XFER_E_IO;
- if (writebuf != NULL)
- {
- PROCFS_NOTE ("write memory:\n");
- nbytes = write (pi->as_fd, writebuf, len);
- }
- else
- {
- PROCFS_NOTE ("read memory:\n");
- nbytes = read (pi->as_fd, readbuf, len);
- }
- if (nbytes <= 0)
- return TARGET_XFER_E_IO;
- *xfered_len = nbytes;
- return TARGET_XFER_OK;
- }
- /* Called by target_resume before making child runnable. Mark cached
- registers and status's invalid. If there are "dirty" caches that
- need to be written back to the child process, do that.
- File descriptors are also cached. As they are a limited resource,
- we cannot hold onto them indefinitely. However, as they are
- expensive to open, we don't want to throw them away
- indiscriminately either. As a compromise, we will keep the file
- descriptors for the parent process, but discard any file
- descriptors we may have accumulated for the threads.
- As this function is called by iterate_over_threads, it always
- returns zero (so that iterate_over_threads will keep
- iterating). */
- static int
- invalidate_cache (procinfo *parent, procinfo *pi, void *ptr)
- {
- /* About to run the child; invalidate caches and do any other
- cleanup. */
- if (parent != NULL)
- {
- /* The presence of a parent indicates that this is an LWP.
- Close any file descriptors that it might have open.
- We don't do this to the master (parent) procinfo. */
- close_procinfo_files (pi);
- }
- pi->gregs_valid = 0;
- pi->fpregs_valid = 0;
- pi->status_valid = 0;
- pi->threads_valid = 0;
- return 0;
- }
- /* Make the child process runnable. Normally we will then call
- procfs_wait and wait for it to stop again (unless gdb is async).
- If STEP is true, then arrange for the child to stop again after
- executing a single instruction. If SIGNO is zero, then cancel any
- pending signal; if non-zero, then arrange for the indicated signal
- to be delivered to the child when it runs. If PID is -1, then
- allow any child thread to run; if non-zero, then allow only the
- indicated thread to run. (not implemented yet). */
- void
- procfs_target::resume (ptid_t ptid, int step, enum gdb_signal signo)
- {
- procinfo *pi, *thread;
- int native_signo;
- /* FIXME: Check/reword. */
- /* prrun.prflags |= PRCFAULT; clear current fault.
- PRCFAULT may be replaced by a PCCFAULT call (proc_clear_current_fault)
- This basically leaves PRSTEP and PRCSIG.
- PRCSIG is like PCSSIG (proc_clear_current_signal).
- So basically PR_STEP is the sole argument that must be passed
- to proc_run_process. */
- /* Find procinfo for main process. */
- pi = find_procinfo_or_die (inferior_ptid.pid (), 0);
- /* First cut: ignore pid argument. */
- errno = 0;
- /* Convert signal to host numbering. */
- if (signo == 0 || (signo == GDB_SIGNAL_STOP && pi->ignore_next_sigstop))
- native_signo = 0;
- else
- native_signo = gdb_signal_to_host (signo);
- pi->ignore_next_sigstop = 0;
- /* Running the process voids all cached registers and status. */
- /* Void the threads' caches first. */
- proc_iterate_over_threads (pi, invalidate_cache, NULL);
- /* Void the process procinfo's caches. */
- invalidate_cache (NULL, pi, NULL);
- if (ptid.pid () != -1)
- {
- /* Resume a specific thread, presumably suppressing the
- others. */
- thread = find_procinfo (ptid.pid (), ptid.lwp ());
- if (thread != NULL)
- {
- if (thread->tid != 0)
- {
- /* We're to resume a specific thread, and not the
- others. Set the child process's PR_ASYNC flag. */
- if (!proc_set_async (pi))
- proc_error (pi, "target_resume, set_async", __LINE__);
- pi = thread; /* Substitute the thread's procinfo
- for run. */
- }
- }
- }
- if (!proc_run_process (pi, step, native_signo))
- {
- if (errno == EBUSY)
- warning (_("resume: target already running. "
- "Pretend to resume, and hope for the best!"));
- else
- proc_error (pi, "target_resume", __LINE__);
- }
- }
- /* Set up to trace signals in the child process. */
- void
- procfs_target::pass_signals (gdb::array_view<const unsigned char> pass_signals)
- {
- sigset_t signals;
- procinfo *pi = find_procinfo_or_die (inferior_ptid.pid (), 0);
- int signo;
- prfillset (&signals);
- for (signo = 0; signo < NSIG; signo++)
- {
- int target_signo = gdb_signal_from_host (signo);
- if (target_signo < pass_signals.size () && pass_signals[target_signo])
- prdelset (&signals, signo);
- }
- if (!proc_set_traced_signals (pi, &signals))
- proc_error (pi, "pass_signals", __LINE__);
- }
- /* Print status information about the child process. */
- void
- procfs_target::files_info ()
- {
- struct inferior *inf = current_inferior ();
- gdb_printf (_("\tUsing the running image of %s %s via /proc.\n"),
- inf->attach_flag? "attached": "child",
- target_pid_to_str (inferior_ptid).c_str ());
- }
- /* Make it die. Wait for it to die. Clean up after it. Note: this
- should only be applied to the real process, not to an LWP, because
- of the check for parent-process. If we need this to work for an
- LWP, it needs some more logic. */
- static void
- unconditionally_kill_inferior (procinfo *pi)
- {
- int parent_pid;
- parent_pid = proc_parent_pid (pi);
- if (!proc_kill (pi, SIGKILL))
- proc_error (pi, "unconditionally_kill, proc_kill", __LINE__);
- destroy_procinfo (pi);
- /* If pi is GDB's child, wait for it to die. */
- if (parent_pid == getpid ())
- /* FIXME: should we use waitpid to make sure we get the right event?
- Should we check the returned event? */
- {
- #if 0
- int status, ret;
- ret = waitpid (pi->pid, &status, 0);
- #else
- wait (NULL);
- #endif
- }
- }
- /* We're done debugging it, and we want it to go away. Then we want
- GDB to forget all about it. */
- void
- procfs_target::kill ()
- {
- if (inferior_ptid != null_ptid) /* ? */
- {
- /* Find procinfo for main process. */
- procinfo *pi = find_procinfo (inferior_ptid.pid (), 0);
- if (pi)
- unconditionally_kill_inferior (pi);
- target_mourn_inferior (inferior_ptid);
- }
- }
- /* Forget we ever debugged this thing! */
- void
- procfs_target::mourn_inferior ()
- {
- procinfo *pi;
- if (inferior_ptid != null_ptid)
- {
- /* Find procinfo for main process. */
- pi = find_procinfo (inferior_ptid.pid (), 0);
- if (pi)
- destroy_procinfo (pi);
- }
- generic_mourn_inferior ();
- maybe_unpush_target ();
- }
- /* When GDB forks to create a runnable inferior process, this function
- is called on the parent side of the fork. It's job is to do
- whatever is necessary to make the child ready to be debugged, and
- then wait for the child to synchronize. */
- void
- procfs_target::procfs_init_inferior (int pid)
- {
- procinfo *pi;
- int fail;
- int lwpid;
- pi = create_procinfo (pid, 0);
- if (pi == NULL)
- perror (_("procfs: out of memory in 'init_inferior'"));
- if (!open_procinfo_files (pi, FD_CTL))
- proc_error (pi, "init_inferior, open_proc_files", __LINE__);
- /*
- xmalloc // done
- open_procinfo_files // done
- link list // done
- prfillset (trace)
- procfs_notice_signals
- prfillset (fault)
- prdelset (FLTPAGE)
- */
- /* If not stopped yet, wait for it to stop. */
- if (!(proc_flags (pi) & PR_STOPPED) && !(proc_wait_for_stop (pi)))
- dead_procinfo (pi, "init_inferior: wait_for_stop failed", KILL);
- /* Save some of the /proc state to be restored if we detach. */
- /* FIXME: Why? In case another debugger was debugging it?
- We're it's parent, for Ghu's sake! */
- if (!proc_get_traced_signals (pi, &pi->saved_sigset))
- proc_error (pi, "init_inferior, get_traced_signals", __LINE__);
- if (!proc_get_held_signals (pi, &pi->saved_sighold))
- proc_error (pi, "init_inferior, get_held_signals", __LINE__);
- if (!proc_get_traced_faults (pi, &pi->saved_fltset))
- proc_error (pi, "init_inferior, get_traced_faults", __LINE__);
- if (!proc_get_traced_sysentry (pi, pi->saved_entryset))
- proc_error (pi, "init_inferior, get_traced_sysentry", __LINE__);
- if (!proc_get_traced_sysexit (pi, pi->saved_exitset))
- proc_error (pi, "init_inferior, get_traced_sysexit", __LINE__);
- fail = procfs_debug_inferior (pi);
- if (fail != 0)
- proc_error (pi, "init_inferior (procfs_debug_inferior)", fail);
- /* FIXME: logically, we should really be turning OFF run-on-last-close,
- and possibly even turning ON kill-on-last-close at this point. But
- I can't make that change without careful testing which I don't have
- time to do right now... */
- /* Turn on run-on-last-close flag so that the child
- will die if GDB goes away for some reason. */
- if (!proc_set_run_on_last_close (pi))
- proc_error (pi, "init_inferior, set_RLC", __LINE__);
- /* We now have have access to the lwpid of the main thread/lwp. */
- lwpid = proc_get_current_thread (pi);
- /* Create a procinfo for the main lwp. */
- create_procinfo (pid, lwpid);
- /* We already have a main thread registered in the thread table at
- this point, but it didn't have any lwp info yet. Notify the core
- about it. This changes inferior_ptid as well. */
- thread_change_ptid (this, ptid_t (pid), ptid_t (pid, lwpid, 0));
- gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
- }
- /* When GDB forks to create a new process, this function is called on
- the child side of the fork before GDB exec's the user program. Its
- job is to make the child minimally debuggable, so that the parent
- GDB process can connect to the child and take over. This function
- should do only the minimum to make that possible, and to
- synchronize with the parent process. The parent process should
- take care of the details. */
- static void
- procfs_set_exec_trap (void)
- {
- /* This routine called on the child side (inferior side)
- after GDB forks the inferior. It must use only local variables,
- because it may be sharing data space with its parent. */
- procinfo *pi;
- sysset_t *exitset;
- pi = create_procinfo (getpid (), 0);
- if (pi == NULL)
- perror_with_name (_("procfs: create_procinfo failed in child."));
- if (open_procinfo_files (pi, FD_CTL) == 0)
- {
- proc_warn (pi, "set_exec_trap, open_proc_files", __LINE__);
- gdb_flush (gdb_stderr);
- /* No need to call "dead_procinfo", because we're going to
- exit. */
- _exit (127);
- }
- exitset = XNEW (sysset_t);
- premptyset (exitset);
- praddset (exitset, SYS_execve);
- if (!proc_set_traced_sysexit (pi, exitset))
- {
- proc_warn (pi, "set_exec_trap, set_traced_sysexit", __LINE__);
- gdb_flush (gdb_stderr);
- _exit (127);
- }
- /* FIXME: should this be done in the parent instead? */
- /* Turn off inherit on fork flag so that all grand-children
- of gdb start with tracing flags cleared. */
- if (!proc_unset_inherit_on_fork (pi))
- proc_warn (pi, "set_exec_trap, unset_inherit", __LINE__);
- /* Turn off run on last close flag, so that the child process
- cannot run away just because we close our handle on it.
- We want it to wait for the parent to attach. */
- if (!proc_unset_run_on_last_close (pi))
- proc_warn (pi, "set_exec_trap, unset_RLC", __LINE__);
- /* FIXME: No need to destroy the procinfo --
- we have our own address space, and we're about to do an exec! */
- /*destroy_procinfo (pi);*/
- }
- /* Dummy function to be sure fork_inferior uses fork(2) and not vfork(2).
- This avoids a possible deadlock gdb and its vfork'ed child. */
- static void
- procfs_pre_trace (void)
- {
- }
- /* This function is called BEFORE gdb forks the inferior process. Its
- only real responsibility is to set things up for the fork, and tell
- GDB which two functions to call after the fork (one for the parent,
- and one for the child).
- This function does a complicated search for a unix shell program,
- which it then uses to parse arguments and environment variables to
- be sent to the child. I wonder whether this code could not be
- abstracted out and shared with other unix targets such as
- inf-ptrace? */
- void
- procfs_target::create_inferior (const char *exec_file,
- const std::string &allargs,
- char **env, int from_tty)
- {
- const char *shell_file = get_shell ();
- char *tryname;
- int pid;
- if (strchr (shell_file, '/') == NULL)
- {
- /* We will be looking down the PATH to find shell_file. If we
- just do this the normal way (via execlp, which operates by
- attempting an exec for each element of the PATH until it
- finds one which succeeds), then there will be an exec for
- each failed attempt, each of which will cause a PR_SYSEXIT
- stop, and we won't know how to distinguish the PR_SYSEXIT's
- for these failed execs with the ones for successful execs
- (whether the exec has succeeded is stored at that time in the
- carry bit or some such architecture-specific and
- non-ABI-specified place).
- So I can't think of anything better than to search the PATH
- now. This has several disadvantages: (1) There is a race
- condition; if we find a file now and it is deleted before we
- exec it, we lose, even if the deletion leaves a valid file
- further down in the PATH, (2) there is no way to know exactly
- what an executable (in the sense of "capable of being
- exec'd") file is. Using access() loses because it may lose
- if the caller is the superuser; failing to use it loses if
- there are ACLs or some such. */
- const char *p;
- const char *p1;
- /* FIXME-maybe: might want "set path" command so user can change what
- path is used from within GDB. */
- const char *path = getenv ("PATH");
- int len;
- struct stat statbuf;
- if (path == NULL)
- path = "/bin:/usr/bin";
- tryname = (char *) alloca (strlen (path) + strlen (shell_file) + 2);
- for (p = path; p != NULL; p = p1 ? p1 + 1: NULL)
- {
- p1 = strchr (p, ':');
- if (p1 != NULL)
- len = p1 - p;
- else
- len = strlen (p);
- strncpy (tryname, p, len);
- tryname[len] = '\0';
- strcat (tryname, "/");
- strcat (tryname, shell_file);
- if (access (tryname, X_OK) < 0)
- continue;
- if (stat (tryname, &statbuf) < 0)
- continue;
- if (!S_ISREG (statbuf.st_mode))
- /* We certainly need to reject directories. I'm not quite
- as sure about FIFOs, sockets, etc., but I kind of doubt
- that people want to exec() these things. */
- continue;
- break;
- }
- if (p == NULL)
- /* Not found. This must be an error rather than merely passing
- the file to execlp(), because execlp() would try all the
- exec()s, causing GDB to get confused. */
- error (_("procfs:%d -- Can't find shell %s in PATH"),
- __LINE__, shell_file);
- shell_file = tryname;
- }
- inferior *inf = current_inferior ();
- if (!inf->target_is_pushed (this))
- inf->push_target (this);
- pid = fork_inferior (exec_file, allargs, env, procfs_set_exec_trap,
- NULL, procfs_pre_trace, shell_file, NULL);
- /* We have something that executes now. We'll be running through
- the shell at this point (if startup-with-shell is true), but the
- pid shouldn't change. */
- thread_info *thr = add_thread_silent (this, ptid_t (pid));
- switch_to_thread (thr);
- procfs_init_inferior (pid);
- }
- /* Callback for update_thread_list. Calls "add_thread". */
- static int
- procfs_notice_thread (procinfo *pi, procinfo *thread, void *ptr)
- {
- ptid_t gdb_threadid = ptid_t (pi->pid, thread->tid, 0);
- thread_info *thr = find_thread_ptid (&the_procfs_target, gdb_threadid);
- if (thr == NULL || thr->state == THREAD_EXITED)
- add_thread (&the_procfs_target, gdb_threadid);
- return 0;
- }
- /* Query all the threads that the target knows about, and give them
- back to GDB to add to its list. */
- void
- procfs_target::update_thread_list ()
- {
- procinfo *pi;
- prune_threads ();
- /* Find procinfo for main process. */
- pi = find_procinfo_or_die (inferior_ptid.pid (), 0);
- proc_update_threads (pi);
- proc_iterate_over_threads (pi, procfs_notice_thread, NULL);
- }
- /* Return true if the thread is still 'alive'. This guy doesn't
- really seem to be doing his job. Got to investigate how to tell
- when a thread is really gone. */
- bool
- procfs_target::thread_alive (ptid_t ptid)
- {
- int proc, thread;
- procinfo *pi;
- proc = ptid.pid ();
- thread = ptid.lwp ();
- /* If I don't know it, it ain't alive! */
- pi = find_procinfo (proc, thread);
- if (pi == NULL)
- return false;
- /* If I can't get its status, it ain't alive!
- What's more, I need to forget about it! */
- if (!proc_get_status (pi))
- {
- destroy_procinfo (pi);
- return false;
- }
- /* I couldn't have got its status if it weren't alive, so it's
- alive. */
- return true;
- }
- /* Convert PTID to a string. */
- std::string
- procfs_target::pid_to_str (ptid_t ptid)
- {
- if (ptid.lwp () == 0)
- return string_printf ("process %d", ptid.pid ());
- else
- return string_printf ("LWP %ld", ptid.lwp ());
- }
- /* Accepts an integer PID; Returns a string representing a file that
- can be opened to get the symbols for the child process. */
- char *
- procfs_target::pid_to_exec_file (int pid)
- {
- static char buf[PATH_MAX];
- char name[PATH_MAX];
- /* Solaris 11 introduced /proc/<proc-id>/execname. */
- xsnprintf (name, sizeof (name), "/proc/%d/execname", pid);
- scoped_fd fd (gdb_open_cloexec (name, O_RDONLY, 0));
- if (fd.get () < 0 || read (fd.get (), buf, PATH_MAX - 1) < 0)
- {
- /* If that fails, fall back to /proc/<proc-id>/path/a.out introduced in
- Solaris 10. */
- ssize_t len;
- xsnprintf (name, sizeof (name), "/proc/%d/path/a.out", pid);
- len = readlink (name, buf, PATH_MAX - 1);
- if (len <= 0)
- strcpy (buf, name);
- else
- buf[len] = '\0';
- }
- return buf;
- }
- /* Insert a watchpoint. */
- static int
- procfs_set_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rwflag,
- int after)
- {
- int pflags = 0;
- procinfo *pi;
- pi = find_procinfo_or_die (ptid.pid () == -1 ?
- inferior_ptid.pid () : ptid.pid (),
- 0);
- /* Translate from GDB's flags to /proc's. */
- if (len > 0) /* len == 0 means delete watchpoint. */
- {
- switch (rwflag) { /* FIXME: need an enum! */
- case hw_write: /* default watchpoint (write) */
- pflags = WA_WRITE;
- break;
- case hw_read: /* read watchpoint */
- pflags = WA_READ;
- break;
- case hw_access: /* access watchpoint */
- pflags = WA_READ | WA_WRITE;
- break;
- case hw_execute: /* execution HW breakpoint */
- pflags = WA_EXEC;
- break;
- default: /* Something weird. Return error. */
- return -1;
- }
- if (after) /* Stop after r/w access is completed. */
- pflags |= WA_TRAPAFTER;
- }
- if (!proc_set_watchpoint (pi, addr, len, pflags))
- {
- if (errno == E2BIG) /* Typical error for no resources. */
- return -1; /* fail */
- /* GDB may try to remove the same watchpoint twice.
- If a remove request returns no match, don't error. */
- if (errno == ESRCH && len == 0)
- return 0; /* ignore */
- proc_error (pi, "set_watchpoint", __LINE__);
- }
- return 0;
- }
- /* Return non-zero if we can set a hardware watchpoint of type TYPE. TYPE
- is one of bp_hardware_watchpoint, bp_read_watchpoint, bp_write_watchpoint,
- or bp_hardware_watchpoint. CNT is the number of watchpoints used so
- far. */
- int
- procfs_target::can_use_hw_breakpoint (enum bptype type, int cnt, int othertype)
- {
- /* Due to the way that proc_set_watchpoint() is implemented, host
- and target pointers must be of the same size. If they are not,
- we can't use hardware watchpoints. This limitation is due to the
- fact that proc_set_watchpoint() calls
- procfs_address_to_host_pointer(); a close inspection of
- procfs_address_to_host_pointer will reveal that an internal error
- will be generated when the host and target pointer sizes are
- different. */
- struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
- if (sizeof (void *) != TYPE_LENGTH (ptr_type))
- return 0;
- /* Other tests here??? */
- return 1;
- }
- /* Returns non-zero if process is stopped on a hardware watchpoint
- fault, else returns zero. */
- bool
- procfs_target::stopped_by_watchpoint ()
- {
- procinfo *pi;
- pi = find_procinfo_or_die (inferior_ptid.pid (), 0);
- if (proc_flags (pi) & (PR_STOPPED | PR_ISTOP))
- if (proc_why (pi) == PR_FAULTED)
- if (proc_what (pi) == FLTWATCH)
- return true;
- return false;
- }
- /* Returns 1 if the OS knows the position of the triggered watchpoint,
- and sets *ADDR to that address. Returns 0 if OS cannot report that
- address. This function is only called if
- procfs_stopped_by_watchpoint returned 1, thus no further checks are
- done. The function also assumes that ADDR is not NULL. */
- bool
- procfs_target::stopped_data_address (CORE_ADDR *addr)
- {
- procinfo *pi;
- pi = find_procinfo_or_die (inferior_ptid.pid (), 0);
- return proc_watchpoint_address (pi, addr);
- }
- int
- procfs_target::insert_watchpoint (CORE_ADDR addr, int len,
- enum target_hw_bp_type type,
- struct expression *cond)
- {
- if (!target_have_steppable_watchpoint ()
- && !gdbarch_have_nonsteppable_watchpoint (target_gdbarch ()))
- /* When a hardware watchpoint fires off the PC will be left at
- the instruction following the one which caused the
- watchpoint. It will *NOT* be necessary for GDB to step over
- the watchpoint. */
- return procfs_set_watchpoint (inferior_ptid, addr, len, type, 1);
- else
- /* When a hardware watchpoint fires off the PC will be left at
- the instruction which caused the watchpoint. It will be
- necessary for GDB to step over the watchpoint. */
- return procfs_set_watchpoint (inferior_ptid, addr, len, type, 0);
- }
- int
- procfs_target::remove_watchpoint (CORE_ADDR addr, int len,
- enum target_hw_bp_type type,
- struct expression *cond)
- {
- return procfs_set_watchpoint (inferior_ptid, addr, 0, 0, 0);
- }
- int
- procfs_target::region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
- {
- /* The man page for proc(4) on Solaris 2.6 and up says that the
- system can support "thousands" of hardware watchpoints, but gives
- no method for finding out how many; It doesn't say anything about
- the allowed size for the watched area either. So we just tell
- GDB 'yes'. */
- return 1;
- }
- /* Memory Mappings Functions: */
- /* Call a callback function once for each mapping, passing it the
- mapping, an optional secondary callback function, and some optional
- opaque data. Quit and return the first non-zero value returned
- from the callback.
- PI is the procinfo struct for the process to be mapped. FUNC is
- the callback function to be called by this iterator. DATA is the
- optional opaque data to be passed to the callback function.
- CHILD_FUNC is the optional secondary function pointer to be passed
- to the child function. Returns the first non-zero return value
- from the callback function, or zero. */
- static int
- iterate_over_mappings (procinfo *pi, find_memory_region_ftype child_func,
- void *data,
- int (*func) (struct prmap *map,
- find_memory_region_ftype child_func,
- void *data))
- {
- char pathname[MAX_PROC_NAME_SIZE];
- struct prmap *prmaps;
- struct prmap *prmap;
- int funcstat;
- int nmap;
- struct stat sbuf;
- /* Get the number of mappings, allocate space,
- and read the mappings into prmaps. */
- /* Open map fd. */
- xsnprintf (pathname, sizeof (pathname), "/proc/%d/map", pi->pid);
- scoped_fd map_fd (open (pathname, O_RDONLY));
- if (map_fd.get () < 0)
- proc_error (pi, "iterate_over_mappings (open)", __LINE__);
- /* Use stat to determine the file size, and compute
- the number of prmap_t objects it contains. */
- if (fstat (map_fd.get (), &sbuf) != 0)
- proc_error (pi, "iterate_over_mappings (fstat)", __LINE__);
- nmap = sbuf.st_size / sizeof (prmap_t);
- prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
- if (read (map_fd.get (), (char *) prmaps, nmap * sizeof (*prmaps))
- != (nmap * sizeof (*prmaps)))
- proc_error (pi, "iterate_over_mappings (read)", __LINE__);
- for (prmap = prmaps; nmap > 0; prmap++, nmap--)
- {
- funcstat = (*func) (prmap, child_func, data);
- if (funcstat != 0)
- return funcstat;
- }
- return 0;
- }
- /* Implements the to_find_memory_regions method. Calls an external
- function for each memory region.
- Returns the integer value returned by the callback. */
- static int
- find_memory_regions_callback (struct prmap *map,
- find_memory_region_ftype func, void *data)
- {
- return (*func) ((CORE_ADDR) map->pr_vaddr,
- map->pr_size,
- (map->pr_mflags & MA_READ) != 0,
- (map->pr_mflags & MA_WRITE) != 0,
- (map->pr_mflags & MA_EXEC) != 0,
- 1, /* MODIFIED is unknown, pass it as true. */
- data);
- }
- /* External interface. Calls a callback function once for each
- mapped memory region in the child process, passing as arguments:
- CORE_ADDR virtual_address,
- unsigned long size,
- int read, TRUE if region is readable by the child
- int write, TRUE if region is writable by the child
- int execute TRUE if region is executable by the child.
- Stops iterating and returns the first non-zero value returned by
- the callback. */
- int
- procfs_target::find_memory_regions (find_memory_region_ftype func, void *data)
- {
- procinfo *pi = find_procinfo_or_die (inferior_ptid.pid (), 0);
- return iterate_over_mappings (pi, func, data,
- find_memory_regions_callback);
- }
- /* Returns an ascii representation of a memory mapping's flags. */
- static char *
- mappingflags (long flags)
- {
- static char asciiflags[8];
- strcpy (asciiflags, "-------");
- if (flags & MA_STACK)
- asciiflags[1] = 's';
- if (flags & MA_BREAK)
- asciiflags[2] = 'b';
- if (flags & MA_SHARED)
- asciiflags[3] = 's';
- if (flags & MA_READ)
- asciiflags[4] = 'r';
- if (flags & MA_WRITE)
- asciiflags[5] = 'w';
- if (flags & MA_EXEC)
- asciiflags[6] = 'x';
- return (asciiflags);
- }
- /* Callback function, does the actual work for 'info proc
- mappings'. */
- static int
- info_mappings_callback (struct prmap *map, find_memory_region_ftype ignore,
- void *unused)
- {
- unsigned int pr_off;
- pr_off = (unsigned int) map->pr_offset;
- if (gdbarch_addr_bit (target_gdbarch ()) == 32)
- gdb_printf ("\t%#10lx %#10lx %#10lx %#10x %7s\n",
- (unsigned long) map->pr_vaddr,
- (unsigned long) map->pr_vaddr + map->pr_size - 1,
- (unsigned long) map->pr_size,
- pr_off,
- mappingflags (map->pr_mflags));
- else
- gdb_printf (" %#18lx %#18lx %#10lx %#10x %7s\n",
- (unsigned long) map->pr_vaddr,
- (unsigned long) map->pr_vaddr + map->pr_size - 1,
- (unsigned long) map->pr_size,
- pr_off,
- mappingflags (map->pr_mflags));
- return 0;
- }
- /* Implement the "info proc mappings" subcommand. */
- static void
- info_proc_mappings (procinfo *pi, int summary)
- {
- if (summary)
- return; /* No output for summary mode. */
- gdb_printf (_("Mapped address spaces:\n\n"));
- if (gdbarch_ptr_bit (target_gdbarch ()) == 32)
- gdb_printf ("\t%10s %10s %10s %10s %7s\n",
- "Start Addr",
- " End Addr",
- " Size",
- " Offset",
- "Flags");
- else
- gdb_printf (" %18s %18s %10s %10s %7s\n",
- "Start Addr",
- " End Addr",
- " Size",
- " Offset",
- "Flags");
- iterate_over_mappings (pi, NULL, NULL, info_mappings_callback);
- gdb_printf ("\n");
- }
- /* Implement the "info proc" command. */
- bool
- procfs_target::info_proc (const char *args, enum info_proc_what what)
- {
- procinfo *process = NULL;
- procinfo *thread = NULL;
- char *tmp = NULL;
- int pid = 0;
- int tid = 0;
- int mappings = 0;
- switch (what)
- {
- case IP_MINIMAL:
- break;
- case IP_MAPPINGS:
- case IP_ALL:
- mappings = 1;
- break;
- default:
- error (_("Not supported on this target."));
- }
- gdb_argv built_argv (args);
- for (char *arg : built_argv)
- {
- if (isdigit (arg[0]))
- {
- pid = strtoul (arg, &tmp, 10);
- if (*tmp == '/')
- tid = strtoul (++tmp, NULL, 10);
- }
- else if (arg[0] == '/')
- {
- tid = strtoul (arg + 1, NULL, 10);
- }
- }
- procinfo_up temporary_procinfo;
- if (pid == 0)
- pid = inferior_ptid.pid ();
- if (pid == 0)
- error (_("No current process: you must name one."));
- else
- {
- /* Have pid, will travel.
- First see if it's a process we're already debugging. */
- process = find_procinfo (pid, 0);
- if (process == NULL)
- {
- /* No. So open a procinfo for it, but
- remember to close it again when finished. */
- process = create_procinfo (pid, 0);
- temporary_procinfo.reset (process);
- if (!open_procinfo_files (process, FD_CTL))
- proc_error (process, "info proc, open_procinfo_files", __LINE__);
- }
- }
- if (tid != 0)
- thread = create_procinfo (pid, tid);
- if (process)
- {
- gdb_printf (_("process %d flags:\n"), process->pid);
- proc_prettyprint_flags (proc_flags (process), 1);
- if (proc_flags (process) & (PR_STOPPED | PR_ISTOP))
- proc_prettyprint_why (proc_why (process), proc_what (process), 1);
- if (proc_get_nthreads (process) > 1)
- gdb_printf ("Process has %d threads.\n",
- proc_get_nthreads (process));
- }
- if (thread)
- {
- gdb_printf (_("thread %d flags:\n"), thread->tid);
- proc_prettyprint_flags (proc_flags (thread), 1);
- if (proc_flags (thread) & (PR_STOPPED | PR_ISTOP))
- proc_prettyprint_why (proc_why (thread), proc_what (thread), 1);
- }
- if (mappings)
- info_proc_mappings (process, 0);
- return true;
- }
- /* Modify the status of the system call identified by SYSCALLNUM in
- the set of syscalls that are currently traced/debugged.
- If ENTRY_OR_EXIT is set to PR_SYSENTRY, then the entry syscalls set
- will be updated. Otherwise, the exit syscalls set will be updated.
- If MODE is FLAG_SET, then traces will be enabled. Otherwise, they
- will be disabled. */
- static void
- proc_trace_syscalls_1 (procinfo *pi, int syscallnum, int entry_or_exit,
- int mode, int from_tty)
- {
- sysset_t *sysset;
- if (entry_or_exit == PR_SYSENTRY)
- sysset = proc_get_traced_sysentry (pi, NULL);
- else
- sysset = proc_get_traced_sysexit (pi, NULL);
- if (sysset == NULL)
- proc_error (pi, "proc-trace, get_traced_sysset", __LINE__);
- if (mode == FLAG_SET)
- praddset (sysset, syscallnum);
- else
- prdelset (sysset, syscallnum);
- if (entry_or_exit == PR_SYSENTRY)
- {
- if (!proc_set_traced_sysentry (pi, sysset))
- proc_error (pi, "proc-trace, set_traced_sysentry", __LINE__);
- }
- else
- {
- if (!proc_set_traced_sysexit (pi, sysset))
- proc_error (pi, "proc-trace, set_traced_sysexit", __LINE__);
- }
- }
- static void
- proc_trace_syscalls (const char *args, int from_tty, int entry_or_exit, int mode)
- {
- procinfo *pi;
- if (inferior_ptid.pid () <= 0)
- error (_("you must be debugging a process to use this command."));
- if (args == NULL || args[0] == 0)
- error_no_arg (_("system call to trace"));
- pi = find_procinfo_or_die (inferior_ptid.pid (), 0);
- if (isdigit (args[0]))
- {
- const int syscallnum = atoi (args);
- proc_trace_syscalls_1 (pi, syscallnum, entry_or_exit, mode, from_tty);
- }
- }
- static void
- proc_trace_sysentry_cmd (const char *args, int from_tty)
- {
- proc_trace_syscalls (args, from_tty, PR_SYSENTRY, FLAG_SET);
- }
- static void
- proc_trace_sysexit_cmd (const char *args, int from_tty)
- {
- proc_trace_syscalls (args, from_tty, PR_SYSEXIT, FLAG_SET);
- }
- static void
- proc_untrace_sysentry_cmd (const char *args, int from_tty)
- {
- proc_trace_syscalls (args, from_tty, PR_SYSENTRY, FLAG_RESET);
- }
- static void
- proc_untrace_sysexit_cmd (const char *args, int from_tty)
- {
- proc_trace_syscalls (args, from_tty, PR_SYSEXIT, FLAG_RESET);
- }
- void _initialize_procfs ();
- void
- _initialize_procfs ()
- {
- add_com ("proc-trace-entry", no_class, proc_trace_sysentry_cmd,
- _("Give a trace of entries into the syscall."));
- add_com ("proc-trace-exit", no_class, proc_trace_sysexit_cmd,
- _("Give a trace of exits from the syscall."));
- add_com ("proc-untrace-entry", no_class, proc_untrace_sysentry_cmd,
- _("Cancel a trace of entries into the syscall."));
- add_com ("proc-untrace-exit", no_class, proc_untrace_sysexit_cmd,
- _("Cancel a trace of exits from the syscall."));
- add_inf_child_target (&the_procfs_target);
- }
- /* =================== END, GDB "MODULE" =================== */
- /* miscellaneous stubs: */
- /* The following satisfy a few random symbols mostly created by the
- solaris threads implementation, which I will chase down later. */
- /* Return a pid for which we guarantee we will be able to find a
- 'live' procinfo. */
- ptid_t
- procfs_first_available (void)
- {
- return ptid_t (procinfo_list ? procinfo_list->pid : -1);
- }
- /* =================== GCORE .NOTE "MODULE" =================== */
- static void
- procfs_do_thread_registers (bfd *obfd, ptid_t ptid,
- gdb::unique_xmalloc_ptr<char> ¬e_data,
- int *note_size, enum gdb_signal stop_signal)
- {
- struct regcache *regcache = get_thread_regcache (&the_procfs_target, ptid);
- gdb_gregset_t gregs;
- gdb_fpregset_t fpregs;
- unsigned long merged_pid;
- merged_pid = ptid.lwp () << 16 | ptid.pid ();
- /* This part is the old method for fetching registers.
- It should be replaced by the newer one using regsets
- once it is implemented in this platform:
- gdbarch_iterate_over_regset_sections(). */
- target_fetch_registers (regcache, -1);
- fill_gregset (regcache, &gregs, -1);
- note_data.reset (elfcore_write_lwpstatus (obfd,
- note_data.release (),
- note_size,
- merged_pid,
- stop_signal,
- &gregs));
- fill_fpregset (regcache, &fpregs, -1);
- note_data.reset (elfcore_write_prfpreg (obfd,
- note_data.release (),
- note_size,
- &fpregs,
- sizeof (fpregs)));
- }
- struct procfs_corefile_thread_data
- {
- procfs_corefile_thread_data (bfd *obfd,
- gdb::unique_xmalloc_ptr<char> ¬e_data,
- int *note_size, gdb_signal stop_signal)
- : obfd (obfd), note_data (note_data), note_size (note_size),
- stop_signal (stop_signal)
- {}
- bfd *obfd;
- gdb::unique_xmalloc_ptr<char> ¬e_data;
- int *note_size;
- enum gdb_signal stop_signal;
- };
- static int
- procfs_corefile_thread_callback (procinfo *pi, procinfo *thread, void *data)
- {
- struct procfs_corefile_thread_data *args
- = (struct procfs_corefile_thread_data *) data;
- if (pi != NULL)
- {
- ptid_t ptid = ptid_t (pi->pid, thread->tid, 0);
- procfs_do_thread_registers (args->obfd, ptid,
- args->note_data,
- args->note_size,
- args->stop_signal);
- }
- return 0;
- }
- static int
- find_signalled_thread (struct thread_info *info, void *data)
- {
- if (info->stop_signal () != GDB_SIGNAL_0
- && info->ptid.pid () == inferior_ptid.pid ())
- return 1;
- return 0;
- }
- static enum gdb_signal
- find_stop_signal (void)
- {
- struct thread_info *info =
- iterate_over_threads (find_signalled_thread, NULL);
- if (info)
- return info->stop_signal ();
- else
- return GDB_SIGNAL_0;
- }
- gdb::unique_xmalloc_ptr<char>
- procfs_target::make_corefile_notes (bfd *obfd, int *note_size)
- {
- gdb_gregset_t gregs;
- char fname[16] = {'\0'};
- char psargs[80] = {'\0'};
- procinfo *pi = find_procinfo_or_die (inferior_ptid.pid (), 0);
- gdb::unique_xmalloc_ptr<char> note_data;
- enum gdb_signal stop_signal;
- if (get_exec_file (0))
- {
- strncpy (fname, lbasename (get_exec_file (0)), sizeof (fname));
- fname[sizeof (fname) - 1] = 0;
- strncpy (psargs, get_exec_file (0), sizeof (psargs));
- psargs[sizeof (psargs) - 1] = 0;
- const std::string &inf_args = current_inferior ()->args ();
- if (!inf_args.empty () &&
- inf_args.length () < ((int) sizeof (psargs) - (int) strlen (psargs)))
- {
- strncat (psargs, " ",
- sizeof (psargs) - strlen (psargs));
- strncat (psargs, inf_args.c_str (),
- sizeof (psargs) - strlen (psargs));
- }
- }
- note_data.reset (elfcore_write_prpsinfo (obfd,
- note_data.release (),
- note_size,
- fname,
- psargs));
- stop_signal = find_stop_signal ();
- fill_gregset (get_current_regcache (), &gregs, -1);
- note_data.reset (elfcore_write_pstatus (obfd, note_data.release (), note_size,
- inferior_ptid.pid (),
- stop_signal, &gregs));
- procfs_corefile_thread_data thread_args (obfd, note_data, note_size,
- stop_signal);
- proc_iterate_over_threads (pi, procfs_corefile_thread_callback,
- &thread_args);
- gdb::optional<gdb::byte_vector> auxv =
- target_read_alloc (current_inferior ()->top_target (),
- TARGET_OBJECT_AUXV, NULL);
- if (auxv && !auxv->empty ())
- note_data.reset (elfcore_write_note (obfd, note_data.release (), note_size,
- "CORE", NT_AUXV, auxv->data (),
- auxv->size ()));
- return note_data;
- }
- /* =================== END GCORE .NOTE "MODULE" =================== */
|