12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402 |
- /* Target-dependent code for FreeBSD, architecture-independent.
- Copyright (C) 2002-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "defs.h"
- #include "auxv.h"
- #include "gdbcore.h"
- #include "inferior.h"
- #include "objfiles.h"
- #include "regcache.h"
- #include "regset.h"
- #include "gdbthread.h"
- #include "objfiles.h"
- #include "xml-syscall.h"
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include "elf-bfd.h"
- #include "fbsd-tdep.h"
- #include "gcore-elf.h"
- /* This enum is derived from FreeBSD's <sys/signal.h>. */
- enum
- {
- FREEBSD_SIGHUP = 1,
- FREEBSD_SIGINT = 2,
- FREEBSD_SIGQUIT = 3,
- FREEBSD_SIGILL = 4,
- FREEBSD_SIGTRAP = 5,
- FREEBSD_SIGABRT = 6,
- FREEBSD_SIGEMT = 7,
- FREEBSD_SIGFPE = 8,
- FREEBSD_SIGKILL = 9,
- FREEBSD_SIGBUS = 10,
- FREEBSD_SIGSEGV = 11,
- FREEBSD_SIGSYS = 12,
- FREEBSD_SIGPIPE = 13,
- FREEBSD_SIGALRM = 14,
- FREEBSD_SIGTERM = 15,
- FREEBSD_SIGURG = 16,
- FREEBSD_SIGSTOP = 17,
- FREEBSD_SIGTSTP = 18,
- FREEBSD_SIGCONT = 19,
- FREEBSD_SIGCHLD = 20,
- FREEBSD_SIGTTIN = 21,
- FREEBSD_SIGTTOU = 22,
- FREEBSD_SIGIO = 23,
- FREEBSD_SIGXCPU = 24,
- FREEBSD_SIGXFSZ = 25,
- FREEBSD_SIGVTALRM = 26,
- FREEBSD_SIGPROF = 27,
- FREEBSD_SIGWINCH = 28,
- FREEBSD_SIGINFO = 29,
- FREEBSD_SIGUSR1 = 30,
- FREEBSD_SIGUSR2 = 31,
- FREEBSD_SIGTHR = 32,
- FREEBSD_SIGLIBRT = 33,
- FREEBSD_SIGRTMIN = 65,
- FREEBSD_SIGRTMAX = 126,
- };
- /* Constants for values of si_code as defined in FreeBSD's
- <sys/signal.h>. */
- #define FBSD_SI_USER 0x10001
- #define FBSD_SI_QUEUE 0x10002
- #define FBSD_SI_TIMER 0x10003
- #define FBSD_SI_ASYNCIO 0x10004
- #define FBSD_SI_MESGQ 0x10005
- #define FBSD_SI_KERNEL 0x10006
- #define FBSD_SI_LWP 0x10007
- #define FBSD_ILL_ILLOPC 1
- #define FBSD_ILL_ILLOPN 2
- #define FBSD_ILL_ILLADR 3
- #define FBSD_ILL_ILLTRP 4
- #define FBSD_ILL_PRVOPC 5
- #define FBSD_ILL_PRVREG 6
- #define FBSD_ILL_COPROC 7
- #define FBSD_ILL_BADSTK 8
- #define FBSD_BUS_ADRALN 1
- #define FBSD_BUS_ADRERR 2
- #define FBSD_BUS_OBJERR 3
- #define FBSD_BUS_OOMERR 100
- #define FBSD_SEGV_MAPERR 1
- #define FBSD_SEGV_ACCERR 2
- #define FBSD_SEGV_PKUERR 100
- #define FBSD_FPE_INTOVF 1
- #define FBSD_FPE_INTDIV 2
- #define FBSD_FPE_FLTDIV 3
- #define FBSD_FPE_FLTOVF 4
- #define FBSD_FPE_FLTUND 5
- #define FBSD_FPE_FLTRES 6
- #define FBSD_FPE_FLTINV 7
- #define FBSD_FPE_FLTSUB 8
- #define FBSD_TRAP_BRKPT 1
- #define FBSD_TRAP_TRACE 2
- #define FBSD_TRAP_DTRACE 3
- #define FBSD_TRAP_CAP 4
- #define FBSD_CLD_EXITED 1
- #define FBSD_CLD_KILLED 2
- #define FBSD_CLD_DUMPED 3
- #define FBSD_CLD_TRAPPED 4
- #define FBSD_CLD_STOPPED 5
- #define FBSD_CLD_CONTINUED 6
- #define FBSD_POLL_IN 1
- #define FBSD_POLL_OUT 2
- #define FBSD_POLL_MSG 3
- #define FBSD_POLL_ERR 4
- #define FBSD_POLL_PRI 5
- #define FBSD_POLL_HUP 6
- /* FreeBSD kernels 12.0 and later include a copy of the
- 'ptrace_lwpinfo' structure returned by the PT_LWPINFO ptrace
- operation in an ELF core note (NT_FREEBSD_PTLWPINFO) for each LWP.
- The constants below define the offset of field members and flags in
- this structure used by methods in this file. Note that the
- 'ptrace_lwpinfo' struct in the note is preceded by a 4 byte integer
- containing the size of the structure. */
- #define LWPINFO_OFFSET 0x4
- /* Offsets in ptrace_lwpinfo. */
- #define LWPINFO_PL_FLAGS 0x8
- #define LWPINFO64_PL_SIGINFO 0x30
- #define LWPINFO32_PL_SIGINFO 0x2c
- /* Flags in pl_flags. */
- #define PL_FLAG_SI 0x20 /* siginfo is valid */
- /* Sizes of siginfo_t. */
- #define SIZE64_SIGINFO_T 80
- #define SIZE32_SIGINFO_T 64
- /* Offsets in data structure used in NT_FREEBSD_PROCSTAT_VMMAP core
- dump notes. See <sys/user.h> for the definition of struct
- kinfo_vmentry. This data structure should have the same layout on
- all architectures.
- Note that FreeBSD 7.0 used an older version of this structure
- (struct kinfo_vmentry), but the NT_FREEBSD_PROCSTAT_VMMAP core
- dump note wasn't introduced until FreeBSD 9.2. As a result, the
- core dump note has always used the 7.1 and later structure
- format. */
- #define KVE_STRUCTSIZE 0x0
- #define KVE_START 0x8
- #define KVE_END 0x10
- #define KVE_OFFSET 0x18
- #define KVE_FLAGS 0x2c
- #define KVE_PROTECTION 0x38
- #define KVE_PATH 0x88
- /* Flags in the 'kve_protection' field in struct kinfo_vmentry. These
- match the KVME_PROT_* constants in <sys/user.h>. */
- #define KINFO_VME_PROT_READ 0x00000001
- #define KINFO_VME_PROT_WRITE 0x00000002
- #define KINFO_VME_PROT_EXEC 0x00000004
- /* Flags in the 'kve_flags' field in struct kinfo_vmentry. These
- match the KVME_FLAG_* constants in <sys/user.h>. */
- #define KINFO_VME_FLAG_COW 0x00000001
- #define KINFO_VME_FLAG_NEEDS_COPY 0x00000002
- #define KINFO_VME_FLAG_NOCOREDUMP 0x00000004
- #define KINFO_VME_FLAG_SUPER 0x00000008
- #define KINFO_VME_FLAG_GROWS_UP 0x00000010
- #define KINFO_VME_FLAG_GROWS_DOWN 0x00000020
- /* Offsets in data structure used in NT_FREEBSD_PROCSTAT_FILES core
- dump notes. See <sys/user.h> for the definition of struct
- kinfo_file. This data structure should have the same layout on all
- architectures.
- Note that FreeBSD 7.0 used an older version of this structure
- (struct kinfo_ofile), but the NT_FREEBSD_PROCSTAT_FILES core dump
- note wasn't introduced until FreeBSD 9.2. As a result, the core
- dump note has always used the 7.1 and later structure format. */
- #define KF_STRUCTSIZE 0x0
- #define KF_TYPE 0x4
- #define KF_FD 0x8
- #define KF_FLAGS 0x10
- #define KF_OFFSET 0x18
- #define KF_VNODE_TYPE 0x20
- #define KF_SOCK_DOMAIN 0x24
- #define KF_SOCK_TYPE 0x28
- #define KF_SOCK_PROTOCOL 0x2c
- #define KF_SA_LOCAL 0x30
- #define KF_SA_PEER 0xb0
- #define KF_PATH 0x170
- /* Constants for the 'kf_type' field in struct kinfo_file. These
- match the KF_TYPE_* constants in <sys/user.h>. */
- #define KINFO_FILE_TYPE_VNODE 1
- #define KINFO_FILE_TYPE_SOCKET 2
- #define KINFO_FILE_TYPE_PIPE 3
- #define KINFO_FILE_TYPE_FIFO 4
- #define KINFO_FILE_TYPE_KQUEUE 5
- #define KINFO_FILE_TYPE_CRYPTO 6
- #define KINFO_FILE_TYPE_MQUEUE 7
- #define KINFO_FILE_TYPE_SHM 8
- #define KINFO_FILE_TYPE_SEM 9
- #define KINFO_FILE_TYPE_PTS 10
- #define KINFO_FILE_TYPE_PROCDESC 11
- /* Special values for the 'kf_fd' field in struct kinfo_file. These
- match the KF_FD_TYPE_* constants in <sys/user.h>. */
- #define KINFO_FILE_FD_TYPE_CWD -1
- #define KINFO_FILE_FD_TYPE_ROOT -2
- #define KINFO_FILE_FD_TYPE_JAIL -3
- #define KINFO_FILE_FD_TYPE_TRACE -4
- #define KINFO_FILE_FD_TYPE_TEXT -5
- #define KINFO_FILE_FD_TYPE_CTTY -6
- /* Flags in the 'kf_flags' field in struct kinfo_file. These match
- the KF_FLAG_* constants in <sys/user.h>. */
- #define KINFO_FILE_FLAG_READ 0x00000001
- #define KINFO_FILE_FLAG_WRITE 0x00000002
- #define KINFO_FILE_FLAG_APPEND 0x00000004
- #define KINFO_FILE_FLAG_ASYNC 0x00000008
- #define KINFO_FILE_FLAG_FSYNC 0x00000010
- #define KINFO_FILE_FLAG_NONBLOCK 0x00000020
- #define KINFO_FILE_FLAG_DIRECT 0x00000040
- #define KINFO_FILE_FLAG_HASLOCK 0x00000080
- #define KINFO_FILE_FLAG_EXEC 0x00004000
- /* Constants for the 'kf_vnode_type' field in struct kinfo_file.
- These match the KF_VTYPE_* constants in <sys/user.h>. */
- #define KINFO_FILE_VTYPE_VREG 1
- #define KINFO_FILE_VTYPE_VDIR 2
- #define KINFO_FILE_VTYPE_VCHR 4
- #define KINFO_FILE_VTYPE_VLNK 5
- #define KINFO_FILE_VTYPE_VSOCK 6
- #define KINFO_FILE_VTYPE_VFIFO 7
- /* Constants for socket address families. These match AF_* constants
- in <sys/socket.h>. */
- #define FBSD_AF_UNIX 1
- #define FBSD_AF_INET 2
- #define FBSD_AF_INET6 28
- /* Constants for socket types. These match SOCK_* constants in
- <sys/socket.h>. */
- #define FBSD_SOCK_STREAM 1
- #define FBSD_SOCK_DGRAM 2
- #define FBSD_SOCK_SEQPACKET 5
- /* Constants for IP protocols. These match IPPROTO_* constants in
- <netinet/in.h>. */
- #define FBSD_IPPROTO_ICMP 1
- #define FBSD_IPPROTO_TCP 6
- #define FBSD_IPPROTO_UDP 17
- #define FBSD_IPPROTO_SCTP 132
- /* Socket address structures. These have the same layout on all
- FreeBSD architectures. In addition, multibyte fields such as IP
- addresses are always stored in network byte order. */
- struct fbsd_sockaddr_in
- {
- uint8_t sin_len;
- uint8_t sin_family;
- uint8_t sin_port[2];
- uint8_t sin_addr[4];
- char sin_zero[8];
- };
- struct fbsd_sockaddr_in6
- {
- uint8_t sin6_len;
- uint8_t sin6_family;
- uint8_t sin6_port[2];
- uint32_t sin6_flowinfo;
- uint8_t sin6_addr[16];
- uint32_t sin6_scope_id;
- };
- struct fbsd_sockaddr_un
- {
- uint8_t sun_len;
- uint8_t sun_family;
- char sun_path[104];
- };
- /* Number of 32-bit words in a signal set. This matches _SIG_WORDS in
- <sys/_sigset.h> and is the same value on all architectures. */
- #define SIG_WORDS 4
- /* Offsets in data structure used in NT_FREEBSD_PROCSTAT_PROC core
- dump notes. See <sys/user.h> for the definition of struct
- kinfo_proc. This data structure has different layouts on different
- architectures mostly due to ILP32 vs LP64. However, FreeBSD/i386
- uses a 32-bit time_t while all other architectures use a 64-bit
- time_t.
- The core dump note actually contains one kinfo_proc structure for
- each thread, but all of the process-wide data can be obtained from
- the first structure. One result of this note's format is that some
- of the process-wide status available in the native target method
- from the kern.proc.pid.<pid> sysctl such as ki_stat and ki_siglist
- is not available from a core dump. Instead, the per-thread data
- structures contain the value of these fields for individual
- threads. */
- struct kinfo_proc_layout
- {
- /* Offsets of struct kinfo_proc members. */
- int ki_layout;
- int ki_pid;
- int ki_ppid;
- int ki_pgid;
- int ki_tpgid;
- int ki_sid;
- int ki_tdev_freebsd11;
- int ki_sigignore;
- int ki_sigcatch;
- int ki_uid;
- int ki_ruid;
- int ki_svuid;
- int ki_rgid;
- int ki_svgid;
- int ki_ngroups;
- int ki_groups;
- int ki_size;
- int ki_rssize;
- int ki_tsize;
- int ki_dsize;
- int ki_ssize;
- int ki_start;
- int ki_nice;
- int ki_comm;
- int ki_tdev;
- int ki_rusage;
- int ki_rusage_ch;
- /* Offsets of struct rusage members. */
- int ru_utime;
- int ru_stime;
- int ru_maxrss;
- int ru_minflt;
- int ru_majflt;
- };
- const struct kinfo_proc_layout kinfo_proc_layout_32 =
- {
- .ki_layout = 0x4,
- .ki_pid = 0x28,
- .ki_ppid = 0x2c,
- .ki_pgid = 0x30,
- .ki_tpgid = 0x34,
- .ki_sid = 0x38,
- .ki_tdev_freebsd11 = 0x44,
- .ki_sigignore = 0x68,
- .ki_sigcatch = 0x78,
- .ki_uid = 0x88,
- .ki_ruid = 0x8c,
- .ki_svuid = 0x90,
- .ki_rgid = 0x94,
- .ki_svgid = 0x98,
- .ki_ngroups = 0x9c,
- .ki_groups = 0xa0,
- .ki_size = 0xe0,
- .ki_rssize = 0xe4,
- .ki_tsize = 0xec,
- .ki_dsize = 0xf0,
- .ki_ssize = 0xf4,
- .ki_start = 0x118,
- .ki_nice = 0x145,
- .ki_comm = 0x17f,
- .ki_tdev = 0x1f0,
- .ki_rusage = 0x220,
- .ki_rusage_ch = 0x278,
- .ru_utime = 0x0,
- .ru_stime = 0x10,
- .ru_maxrss = 0x20,
- .ru_minflt = 0x30,
- .ru_majflt = 0x34,
- };
- const struct kinfo_proc_layout kinfo_proc_layout_i386 =
- {
- .ki_layout = 0x4,
- .ki_pid = 0x28,
- .ki_ppid = 0x2c,
- .ki_pgid = 0x30,
- .ki_tpgid = 0x34,
- .ki_sid = 0x38,
- .ki_tdev_freebsd11 = 0x44,
- .ki_sigignore = 0x68,
- .ki_sigcatch = 0x78,
- .ki_uid = 0x88,
- .ki_ruid = 0x8c,
- .ki_svuid = 0x90,
- .ki_rgid = 0x94,
- .ki_svgid = 0x98,
- .ki_ngroups = 0x9c,
- .ki_groups = 0xa0,
- .ki_size = 0xe0,
- .ki_rssize = 0xe4,
- .ki_tsize = 0xec,
- .ki_dsize = 0xf0,
- .ki_ssize = 0xf4,
- .ki_start = 0x118,
- .ki_nice = 0x135,
- .ki_comm = 0x16f,
- .ki_tdev = 0x1e0,
- .ki_rusage = 0x210,
- .ki_rusage_ch = 0x258,
- .ru_utime = 0x0,
- .ru_stime = 0x8,
- .ru_maxrss = 0x10,
- .ru_minflt = 0x20,
- .ru_majflt = 0x24,
- };
- const struct kinfo_proc_layout kinfo_proc_layout_64 =
- {
- .ki_layout = 0x4,
- .ki_pid = 0x48,
- .ki_ppid = 0x4c,
- .ki_pgid = 0x50,
- .ki_tpgid = 0x54,
- .ki_sid = 0x58,
- .ki_tdev_freebsd11 = 0x64,
- .ki_sigignore = 0x88,
- .ki_sigcatch = 0x98,
- .ki_uid = 0xa8,
- .ki_ruid = 0xac,
- .ki_svuid = 0xb0,
- .ki_rgid = 0xb4,
- .ki_svgid = 0xb8,
- .ki_ngroups = 0xbc,
- .ki_groups = 0xc0,
- .ki_size = 0x100,
- .ki_rssize = 0x108,
- .ki_tsize = 0x118,
- .ki_dsize = 0x120,
- .ki_ssize = 0x128,
- .ki_start = 0x150,
- .ki_nice = 0x185,
- .ki_comm = 0x1bf,
- .ki_tdev = 0x230,
- .ki_rusage = 0x260,
- .ki_rusage_ch = 0x2f0,
- .ru_utime = 0x0,
- .ru_stime = 0x10,
- .ru_maxrss = 0x20,
- .ru_minflt = 0x40,
- .ru_majflt = 0x48,
- };
- static struct gdbarch_data *fbsd_gdbarch_data_handle;
- struct fbsd_gdbarch_data
- {
- struct type *siginfo_type;
- };
- static void *
- init_fbsd_gdbarch_data (struct gdbarch *gdbarch)
- {
- return GDBARCH_OBSTACK_ZALLOC (gdbarch, struct fbsd_gdbarch_data);
- }
- static struct fbsd_gdbarch_data *
- get_fbsd_gdbarch_data (struct gdbarch *gdbarch)
- {
- return ((struct fbsd_gdbarch_data *)
- gdbarch_data (gdbarch, fbsd_gdbarch_data_handle));
- }
- struct fbsd_pspace_data
- {
- /* Offsets in the runtime linker's 'Obj_Entry' structure. */
- LONGEST off_linkmap = 0;
- LONGEST off_tlsindex = 0;
- bool rtld_offsets_valid = false;
- /* vDSO mapping range. */
- struct mem_range vdso_range {};
- /* Zero if the range hasn't been searched for, > 0 if a range was
- found, or < 0 if a range was not found. */
- int vdso_range_p = 0;
- };
- /* Per-program-space data for FreeBSD architectures. */
- static const struct program_space_key<fbsd_pspace_data>
- fbsd_pspace_data_handle;
- static struct fbsd_pspace_data *
- get_fbsd_pspace_data (struct program_space *pspace)
- {
- struct fbsd_pspace_data *data;
- data = fbsd_pspace_data_handle.get (pspace);
- if (data == NULL)
- data = fbsd_pspace_data_handle.emplace (pspace);
- return data;
- }
- /* This is how we want PTIDs from core files to be printed. */
- static std::string
- fbsd_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid)
- {
- if (ptid.lwp () != 0)
- return string_printf ("LWP %ld", ptid.lwp ());
- return normal_pid_to_str (ptid);
- }
- /* Extract the name assigned to a thread from a core. Returns the
- string in a static buffer. */
- static const char *
- fbsd_core_thread_name (struct gdbarch *gdbarch, struct thread_info *thr)
- {
- static char buf[80];
- struct bfd_section *section;
- bfd_size_type size;
- if (thr->ptid.lwp () != 0)
- {
- /* FreeBSD includes a NT_FREEBSD_THRMISC note for each thread
- whose contents are defined by a "struct thrmisc" declared in
- <sys/procfs.h> on FreeBSD. The per-thread name is stored as
- a null-terminated string as the first member of the
- structure. Rather than define the full structure here, just
- extract the null-terminated name from the start of the
- note. */
- thread_section_name section_name (".thrmisc", thr->ptid);
- section = bfd_get_section_by_name (core_bfd, section_name.c_str ());
- if (section != NULL && bfd_section_size (section) > 0)
- {
- /* Truncate the name if it is longer than "buf". */
- size = bfd_section_size (section);
- if (size > sizeof buf - 1)
- size = sizeof buf - 1;
- if (bfd_get_section_contents (core_bfd, section, buf, (file_ptr) 0,
- size)
- && buf[0] != '\0')
- {
- buf[size] = '\0';
- /* Note that each thread will report the process command
- as its thread name instead of an empty name if a name
- has not been set explicitly. Return a NULL name in
- that case. */
- if (strcmp (buf, elf_tdata (core_bfd)->core->program) != 0)
- return buf;
- }
- }
- }
- return NULL;
- }
- /* Implement the "core_xfer_siginfo" gdbarch method. */
- static LONGEST
- fbsd_core_xfer_siginfo (struct gdbarch *gdbarch, gdb_byte *readbuf,
- ULONGEST offset, ULONGEST len)
- {
- size_t siginfo_size;
- if (gdbarch_long_bit (gdbarch) == 32)
- siginfo_size = SIZE32_SIGINFO_T;
- else
- siginfo_size = SIZE64_SIGINFO_T;
- if (offset > siginfo_size)
- return -1;
- thread_section_name section_name (".note.freebsdcore.lwpinfo", inferior_ptid);
- asection *section = bfd_get_section_by_name (core_bfd, section_name.c_str ());
- if (section == NULL)
- return -1;
- gdb_byte buf[4];
- if (!bfd_get_section_contents (core_bfd, section, buf,
- LWPINFO_OFFSET + LWPINFO_PL_FLAGS, 4))
- return -1;
- int pl_flags = extract_signed_integer (buf, gdbarch_byte_order (gdbarch));
- if (!(pl_flags & PL_FLAG_SI))
- return -1;
- if (offset + len > siginfo_size)
- len = siginfo_size - offset;
- ULONGEST siginfo_offset;
- if (gdbarch_long_bit (gdbarch) == 32)
- siginfo_offset = LWPINFO_OFFSET + LWPINFO32_PL_SIGINFO;
- else
- siginfo_offset = LWPINFO_OFFSET + LWPINFO64_PL_SIGINFO;
- if (!bfd_get_section_contents (core_bfd, section, readbuf,
- siginfo_offset + offset, len))
- return -1;
- return len;
- }
- 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;
- }
- /* Return a byte_vector containing the contents of a core dump note
- for the target object of type OBJECT. If STRUCTSIZE is non-zero,
- the data is prefixed with a 32-bit integer size to match the format
- used in FreeBSD NT_PROCSTAT_* notes. */
- static gdb::optional<gdb::byte_vector>
- fbsd_make_note_desc (enum target_object object, uint32_t structsize)
- {
- gdb::optional<gdb::byte_vector> buf =
- target_read_alloc (current_inferior ()->top_target (), object, NULL);
- if (!buf || buf->empty ())
- return {};
- if (structsize == 0)
- return buf;
- gdb::byte_vector desc (sizeof (structsize) + buf->size ());
- memcpy (desc.data (), &structsize, sizeof (structsize));
- memcpy (desc.data () + sizeof (structsize), buf->data (), buf->size ());
- return desc;
- }
- /* Create appropriate note sections for a corefile, returning them in
- allocated memory. */
- static gdb::unique_xmalloc_ptr<char>
- fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
- {
- gdb::unique_xmalloc_ptr<char> note_data;
- Elf_Internal_Ehdr *i_ehdrp;
- struct thread_info *curr_thr, *signalled_thr;
- /* Put a "FreeBSD" label in the ELF header. */
- i_ehdrp = elf_elfheader (obfd);
- i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
- gdb_assert (gdbarch_iterate_over_regset_sections_p (gdbarch));
- if (get_exec_file (0))
- {
- const char *fname = lbasename (get_exec_file (0));
- std::string psargs = fname;
- const std::string &infargs = current_inferior ()->args ();
- if (!infargs.empty ())
- psargs += ' ' + infargs;
- note_data.reset (elfcore_write_prpsinfo (obfd, note_data.release (),
- note_size, fname,
- psargs.c_str ()));
- }
- /* Thread register information. */
- try
- {
- update_thread_list ();
- }
- catch (const gdb_exception_error &e)
- {
- exception_print (gdb_stderr, e);
- }
- /* Like the kernel, prefer dumping the signalled thread first.
- "First thread" is what tools use to infer the signalled thread.
- In case there's more than one signalled thread, prefer the
- current thread, if it is signalled. */
- curr_thr = inferior_thread ();
- if (curr_thr->stop_signal () != GDB_SIGNAL_0)
- signalled_thr = curr_thr;
- else
- {
- signalled_thr = iterate_over_threads (find_signalled_thread, NULL);
- if (signalled_thr == NULL)
- signalled_thr = curr_thr;
- }
- enum gdb_signal stop_signal = signalled_thr->stop_signal ();
- gcore_elf_build_thread_register_notes (gdbarch, signalled_thr, stop_signal,
- obfd, ¬e_data, note_size);
- for (thread_info *thr : current_inferior ()->non_exited_threads ())
- {
- if (thr == signalled_thr)
- continue;
- gcore_elf_build_thread_register_notes (gdbarch, thr, stop_signal,
- obfd, ¬e_data, note_size);
- }
- /* Auxiliary vector. */
- uint32_t structsize = gdbarch_ptr_bit (gdbarch) / 4; /* Elf_Auxinfo */
- gdb::optional<gdb::byte_vector> note_desc =
- fbsd_make_note_desc (TARGET_OBJECT_AUXV, structsize);
- if (note_desc && !note_desc->empty ())
- {
- note_data.reset (elfcore_write_note (obfd, note_data.release (),
- note_size, "FreeBSD",
- NT_FREEBSD_PROCSTAT_AUXV,
- note_desc->data (),
- note_desc->size ()));
- if (!note_data)
- return NULL;
- }
- /* Virtual memory mappings. */
- note_desc = fbsd_make_note_desc (TARGET_OBJECT_FREEBSD_VMMAP, 0);
- if (note_desc && !note_desc->empty ())
- {
- note_data.reset (elfcore_write_note (obfd, note_data.release (),
- note_size, "FreeBSD",
- NT_FREEBSD_PROCSTAT_VMMAP,
- note_desc->data (),
- note_desc->size ()));
- if (!note_data)
- return NULL;
- }
- note_desc = fbsd_make_note_desc (TARGET_OBJECT_FREEBSD_PS_STRINGS, 0);
- if (note_desc && !note_desc->empty ())
- {
- note_data.reset (elfcore_write_note (obfd, note_data.release (),
- note_size, "FreeBSD",
- NT_FREEBSD_PROCSTAT_PSSTRINGS,
- note_desc->data (),
- note_desc->size ()));
- if (!note_data)
- return NULL;
- }
- /* Include the target description when possible. */
- gcore_elf_make_tdesc_note (obfd, ¬e_data, note_size);
- return note_data;
- }
- /* Helper function to generate the file descriptor description for a
- single open file in 'info proc files'. */
- static const char *
- fbsd_file_fd (int kf_fd)
- {
- switch (kf_fd)
- {
- case KINFO_FILE_FD_TYPE_CWD:
- return "cwd";
- case KINFO_FILE_FD_TYPE_ROOT:
- return "root";
- case KINFO_FILE_FD_TYPE_JAIL:
- return "jail";
- case KINFO_FILE_FD_TYPE_TRACE:
- return "trace";
- case KINFO_FILE_FD_TYPE_TEXT:
- return "text";
- case KINFO_FILE_FD_TYPE_CTTY:
- return "ctty";
- default:
- return int_string (kf_fd, 10, 1, 0, 0);
- }
- }
- /* Helper function to generate the file type for a single open file in
- 'info proc files'. */
- static const char *
- fbsd_file_type (int kf_type, int kf_vnode_type)
- {
- switch (kf_type)
- {
- case KINFO_FILE_TYPE_VNODE:
- switch (kf_vnode_type)
- {
- case KINFO_FILE_VTYPE_VREG:
- return "file";
- case KINFO_FILE_VTYPE_VDIR:
- return "dir";
- case KINFO_FILE_VTYPE_VCHR:
- return "chr";
- case KINFO_FILE_VTYPE_VLNK:
- return "link";
- case KINFO_FILE_VTYPE_VSOCK:
- return "socket";
- case KINFO_FILE_VTYPE_VFIFO:
- return "fifo";
- default:
- {
- char *str = get_print_cell ();
- xsnprintf (str, PRINT_CELL_SIZE, "vn:%d", kf_vnode_type);
- return str;
- }
- }
- case KINFO_FILE_TYPE_SOCKET:
- return "socket";
- case KINFO_FILE_TYPE_PIPE:
- return "pipe";
- case KINFO_FILE_TYPE_FIFO:
- return "fifo";
- case KINFO_FILE_TYPE_KQUEUE:
- return "kqueue";
- case KINFO_FILE_TYPE_CRYPTO:
- return "crypto";
- case KINFO_FILE_TYPE_MQUEUE:
- return "mqueue";
- case KINFO_FILE_TYPE_SHM:
- return "shm";
- case KINFO_FILE_TYPE_SEM:
- return "sem";
- case KINFO_FILE_TYPE_PTS:
- return "pts";
- case KINFO_FILE_TYPE_PROCDESC:
- return "proc";
- default:
- return int_string (kf_type, 10, 1, 0, 0);
- }
- }
- /* Helper function to generate the file flags for a single open file in
- 'info proc files'. */
- static const char *
- fbsd_file_flags (int kf_flags)
- {
- static char file_flags[10];
- file_flags[0] = (kf_flags & KINFO_FILE_FLAG_READ) ? 'r' : '-';
- file_flags[1] = (kf_flags & KINFO_FILE_FLAG_WRITE) ? 'w' : '-';
- file_flags[2] = (kf_flags & KINFO_FILE_FLAG_EXEC) ? 'x' : '-';
- file_flags[3] = (kf_flags & KINFO_FILE_FLAG_APPEND) ? 'a' : '-';
- file_flags[4] = (kf_flags & KINFO_FILE_FLAG_ASYNC) ? 's' : '-';
- file_flags[5] = (kf_flags & KINFO_FILE_FLAG_FSYNC) ? 'f' : '-';
- file_flags[6] = (kf_flags & KINFO_FILE_FLAG_NONBLOCK) ? 'n' : '-';
- file_flags[7] = (kf_flags & KINFO_FILE_FLAG_DIRECT) ? 'd' : '-';
- file_flags[8] = (kf_flags & KINFO_FILE_FLAG_HASLOCK) ? 'l' : '-';
- file_flags[9] = '\0';
- return file_flags;
- }
- /* Helper function to generate the name of an IP protocol. */
- static const char *
- fbsd_ipproto (int protocol)
- {
- switch (protocol)
- {
- case FBSD_IPPROTO_ICMP:
- return "icmp";
- case FBSD_IPPROTO_TCP:
- return "tcp";
- case FBSD_IPPROTO_UDP:
- return "udp";
- case FBSD_IPPROTO_SCTP:
- return "sctp";
- default:
- {
- char *str = get_print_cell ();
- xsnprintf (str, PRINT_CELL_SIZE, "ip<%d>", protocol);
- return str;
- }
- }
- }
- /* Helper function to print out an IPv4 socket address. */
- static void
- fbsd_print_sockaddr_in (const void *sockaddr)
- {
- const struct fbsd_sockaddr_in *sin =
- reinterpret_cast<const struct fbsd_sockaddr_in *> (sockaddr);
- char buf[INET_ADDRSTRLEN];
- if (inet_ntop (AF_INET, sin->sin_addr, buf, sizeof buf) == nullptr)
- error (_("Failed to format IPv4 address"));
- gdb_printf ("%s:%u", buf,
- (sin->sin_port[0] << 8) | sin->sin_port[1]);
- }
- /* Helper function to print out an IPv6 socket address. */
- static void
- fbsd_print_sockaddr_in6 (const void *sockaddr)
- {
- const struct fbsd_sockaddr_in6 *sin6 =
- reinterpret_cast<const struct fbsd_sockaddr_in6 *> (sockaddr);
- char buf[INET6_ADDRSTRLEN];
- if (inet_ntop (AF_INET6, sin6->sin6_addr, buf, sizeof buf) == nullptr)
- error (_("Failed to format IPv6 address"));
- gdb_printf ("%s.%u", buf,
- (sin6->sin6_port[0] << 8) | sin6->sin6_port[1]);
- }
- /* See fbsd-tdep.h. */
- void
- fbsd_info_proc_files_header ()
- {
- gdb_printf (_("Open files:\n\n"));
- gdb_printf (" %6s %6s %10s %9s %s\n",
- "FD", "Type", "Offset", "Flags ", "Name");
- }
- /* See fbsd-tdep.h. */
- void
- fbsd_info_proc_files_entry (int kf_type, int kf_fd, int kf_flags,
- LONGEST kf_offset, int kf_vnode_type,
- int kf_sock_domain, int kf_sock_type,
- int kf_sock_protocol, const void *kf_sa_local,
- const void *kf_sa_peer, const void *kf_path)
- {
- gdb_printf (" %6s %6s %10s %8s ",
- fbsd_file_fd (kf_fd),
- fbsd_file_type (kf_type, kf_vnode_type),
- kf_offset > -1 ? hex_string (kf_offset) : "-",
- fbsd_file_flags (kf_flags));
- if (kf_type == KINFO_FILE_TYPE_SOCKET)
- {
- switch (kf_sock_domain)
- {
- case FBSD_AF_UNIX:
- {
- switch (kf_sock_type)
- {
- case FBSD_SOCK_STREAM:
- gdb_printf ("unix stream:");
- break;
- case FBSD_SOCK_DGRAM:
- gdb_printf ("unix dgram:");
- break;
- case FBSD_SOCK_SEQPACKET:
- gdb_printf ("unix seqpacket:");
- break;
- default:
- gdb_printf ("unix <%d>:", kf_sock_type);
- break;
- }
- /* For local sockets, print out the first non-nul path
- rather than both paths. */
- const struct fbsd_sockaddr_un *saddr_un
- = reinterpret_cast<const struct fbsd_sockaddr_un *> (kf_sa_local);
- if (saddr_un->sun_path[0] == 0)
- saddr_un = reinterpret_cast<const struct fbsd_sockaddr_un *>
- (kf_sa_peer);
- gdb_printf ("%s", saddr_un->sun_path);
- break;
- }
- case FBSD_AF_INET:
- gdb_printf ("%s4 ", fbsd_ipproto (kf_sock_protocol));
- fbsd_print_sockaddr_in (kf_sa_local);
- gdb_printf (" -> ");
- fbsd_print_sockaddr_in (kf_sa_peer);
- break;
- case FBSD_AF_INET6:
- gdb_printf ("%s6 ", fbsd_ipproto (kf_sock_protocol));
- fbsd_print_sockaddr_in6 (kf_sa_local);
- gdb_printf (" -> ");
- fbsd_print_sockaddr_in6 (kf_sa_peer);
- break;
- }
- }
- else
- gdb_printf ("%s", reinterpret_cast<const char *> (kf_path));
- gdb_printf ("\n");
- }
- /* Implement "info proc files" for a corefile. */
- static void
- fbsd_core_info_proc_files (struct gdbarch *gdbarch)
- {
- asection *section
- = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.files");
- if (section == NULL)
- {
- warning (_("unable to find open files in core file"));
- return;
- }
- size_t note_size = bfd_section_size (section);
- if (note_size < 4)
- error (_("malformed core note - too short for header"));
- gdb::def_vector<unsigned char> contents (note_size);
- if (!bfd_get_section_contents (core_bfd, section, contents.data (),
- 0, note_size))
- error (_("could not get core note contents"));
- unsigned char *descdata = contents.data ();
- unsigned char *descend = descdata + note_size;
- /* Skip over the structure size. */
- descdata += 4;
- fbsd_info_proc_files_header ();
- while (descdata + KF_PATH < descend)
- {
- ULONGEST structsize = bfd_get_32 (core_bfd, descdata + KF_STRUCTSIZE);
- if (structsize < KF_PATH)
- error (_("malformed core note - file structure too small"));
- LONGEST type = bfd_get_signed_32 (core_bfd, descdata + KF_TYPE);
- LONGEST fd = bfd_get_signed_32 (core_bfd, descdata + KF_FD);
- LONGEST flags = bfd_get_signed_32 (core_bfd, descdata + KF_FLAGS);
- LONGEST offset = bfd_get_signed_64 (core_bfd, descdata + KF_OFFSET);
- LONGEST vnode_type = bfd_get_signed_32 (core_bfd,
- descdata + KF_VNODE_TYPE);
- LONGEST sock_domain = bfd_get_signed_32 (core_bfd,
- descdata + KF_SOCK_DOMAIN);
- LONGEST sock_type = bfd_get_signed_32 (core_bfd, descdata + KF_SOCK_TYPE);
- LONGEST sock_protocol = bfd_get_signed_32 (core_bfd,
- descdata + KF_SOCK_PROTOCOL);
- fbsd_info_proc_files_entry (type, fd, flags, offset, vnode_type,
- sock_domain, sock_type, sock_protocol,
- descdata + KF_SA_LOCAL, descdata + KF_SA_PEER,
- descdata + KF_PATH);
- descdata += structsize;
- }
- }
- /* Helper function to generate mappings flags for a single VM map
- entry in 'info proc mappings'. */
- static const char *
- fbsd_vm_map_entry_flags (int kve_flags, int kve_protection)
- {
- static char vm_flags[9];
- vm_flags[0] = (kve_protection & KINFO_VME_PROT_READ) ? 'r' : '-';
- vm_flags[1] = (kve_protection & KINFO_VME_PROT_WRITE) ? 'w' : '-';
- vm_flags[2] = (kve_protection & KINFO_VME_PROT_EXEC) ? 'x' : '-';
- vm_flags[3] = ' ';
- vm_flags[4] = (kve_flags & KINFO_VME_FLAG_COW) ? 'C' : '-';
- vm_flags[5] = (kve_flags & KINFO_VME_FLAG_NEEDS_COPY) ? 'N' : '-';
- vm_flags[6] = (kve_flags & KINFO_VME_FLAG_SUPER) ? 'S' : '-';
- vm_flags[7] = (kve_flags & KINFO_VME_FLAG_GROWS_UP) ? 'U'
- : (kve_flags & KINFO_VME_FLAG_GROWS_DOWN) ? 'D' : '-';
- vm_flags[8] = '\0';
- return vm_flags;
- }
- /* See fbsd-tdep.h. */
- void
- fbsd_info_proc_mappings_header (int addr_bit)
- {
- gdb_printf (_("Mapped address spaces:\n\n"));
- if (addr_bit == 64)
- {
- gdb_printf (" %18s %18s %10s %10s %9s %s\n",
- "Start Addr",
- " End Addr",
- " Size", " Offset", "Flags ", "File");
- }
- else
- {
- gdb_printf ("\t%10s %10s %10s %10s %9s %s\n",
- "Start Addr",
- " End Addr",
- " Size", " Offset", "Flags ", "File");
- }
- }
- /* See fbsd-tdep.h. */
- void
- fbsd_info_proc_mappings_entry (int addr_bit, ULONGEST kve_start,
- ULONGEST kve_end, ULONGEST kve_offset,
- int kve_flags, int kve_protection,
- const void *kve_path)
- {
- if (addr_bit == 64)
- {
- gdb_printf (" %18s %18s %10s %10s %9s %s\n",
- hex_string (kve_start),
- hex_string (kve_end),
- hex_string (kve_end - kve_start),
- hex_string (kve_offset),
- fbsd_vm_map_entry_flags (kve_flags, kve_protection),
- reinterpret_cast<const char *> (kve_path));
- }
- else
- {
- gdb_printf ("\t%10s %10s %10s %10s %9s %s\n",
- hex_string (kve_start),
- hex_string (kve_end),
- hex_string (kve_end - kve_start),
- hex_string (kve_offset),
- fbsd_vm_map_entry_flags (kve_flags, kve_protection),
- reinterpret_cast<const char *> (kve_path));
- }
- }
- /* Implement "info proc mappings" for a corefile. */
- static void
- fbsd_core_info_proc_mappings (struct gdbarch *gdbarch)
- {
- asection *section;
- unsigned char *descdata, *descend;
- size_t note_size;
- section = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.vmmap");
- if (section == NULL)
- {
- warning (_("unable to find mappings in core file"));
- return;
- }
- note_size = bfd_section_size (section);
- if (note_size < 4)
- error (_("malformed core note - too short for header"));
- gdb::def_vector<unsigned char> contents (note_size);
- if (!bfd_get_section_contents (core_bfd, section, contents.data (),
- 0, note_size))
- error (_("could not get core note contents"));
- descdata = contents.data ();
- descend = descdata + note_size;
- /* Skip over the structure size. */
- descdata += 4;
- fbsd_info_proc_mappings_header (gdbarch_addr_bit (gdbarch));
- while (descdata + KVE_PATH < descend)
- {
- ULONGEST structsize = bfd_get_32 (core_bfd, descdata + KVE_STRUCTSIZE);
- if (structsize < KVE_PATH)
- error (_("malformed core note - vmmap entry too small"));
- ULONGEST start = bfd_get_64 (core_bfd, descdata + KVE_START);
- ULONGEST end = bfd_get_64 (core_bfd, descdata + KVE_END);
- ULONGEST offset = bfd_get_64 (core_bfd, descdata + KVE_OFFSET);
- LONGEST flags = bfd_get_signed_32 (core_bfd, descdata + KVE_FLAGS);
- LONGEST prot = bfd_get_signed_32 (core_bfd, descdata + KVE_PROTECTION);
- fbsd_info_proc_mappings_entry (gdbarch_addr_bit (gdbarch), start, end,
- offset, flags, prot, descdata + KVE_PATH);
- descdata += structsize;
- }
- }
- /* Fetch the pathname of a vnode for a single file descriptor from the
- file table core note. */
- static gdb::unique_xmalloc_ptr<char>
- fbsd_core_vnode_path (struct gdbarch *gdbarch, int fd)
- {
- asection *section;
- unsigned char *descdata, *descend;
- size_t note_size;
- section = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.files");
- if (section == NULL)
- return nullptr;
- note_size = bfd_section_size (section);
- if (note_size < 4)
- error (_("malformed core note - too short for header"));
- gdb::def_vector<unsigned char> contents (note_size);
- if (!bfd_get_section_contents (core_bfd, section, contents.data (),
- 0, note_size))
- error (_("could not get core note contents"));
- descdata = contents.data ();
- descend = descdata + note_size;
- /* Skip over the structure size. */
- descdata += 4;
- while (descdata + KF_PATH < descend)
- {
- ULONGEST structsize;
- structsize = bfd_get_32 (core_bfd, descdata + KF_STRUCTSIZE);
- if (structsize < KF_PATH)
- error (_("malformed core note - file structure too small"));
- if (bfd_get_32 (core_bfd, descdata + KF_TYPE) == KINFO_FILE_TYPE_VNODE
- && bfd_get_signed_32 (core_bfd, descdata + KF_FD) == fd)
- {
- char *path = (char *) descdata + KF_PATH;
- return make_unique_xstrdup (path);
- }
- descdata += structsize;
- }
- return nullptr;
- }
- /* Helper function to read a struct timeval. */
- static void
- fbsd_core_fetch_timeval (struct gdbarch *gdbarch, unsigned char *data,
- LONGEST &sec, ULONGEST &usec)
- {
- if (gdbarch_addr_bit (gdbarch) == 64)
- {
- sec = bfd_get_signed_64 (core_bfd, data);
- usec = bfd_get_64 (core_bfd, data + 8);
- }
- else if (bfd_get_arch (core_bfd) == bfd_arch_i386)
- {
- sec = bfd_get_signed_32 (core_bfd, data);
- usec = bfd_get_32 (core_bfd, data + 4);
- }
- else
- {
- sec = bfd_get_signed_64 (core_bfd, data);
- usec = bfd_get_32 (core_bfd, data + 8);
- }
- }
- /* Print out the contents of a signal set. */
- static void
- fbsd_print_sigset (const char *descr, unsigned char *sigset)
- {
- gdb_printf ("%s: ", descr);
- for (int i = 0; i < SIG_WORDS; i++)
- gdb_printf ("%08x ",
- (unsigned int) bfd_get_32 (core_bfd, sigset + i * 4));
- gdb_printf ("\n");
- }
- /* Implement "info proc status" for a corefile. */
- static void
- fbsd_core_info_proc_status (struct gdbarch *gdbarch)
- {
- const struct kinfo_proc_layout *kp;
- asection *section;
- unsigned char *descdata;
- int addr_bit, long_bit;
- size_t note_size;
- ULONGEST value;
- LONGEST sec;
- section = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.proc");
- if (section == NULL)
- {
- warning (_("unable to find process info in core file"));
- return;
- }
- addr_bit = gdbarch_addr_bit (gdbarch);
- if (addr_bit == 64)
- kp = &kinfo_proc_layout_64;
- else if (bfd_get_arch (core_bfd) == bfd_arch_i386)
- kp = &kinfo_proc_layout_i386;
- else
- kp = &kinfo_proc_layout_32;
- long_bit = gdbarch_long_bit (gdbarch);
- /*
- * Ensure that the note is large enough for all of the fields fetched
- * by this function. In particular, the note must contain the 32-bit
- * structure size, then it must be long enough to access the last
- * field used (ki_rusage_ch.ru_majflt) which is the size of a long.
- */
- note_size = bfd_section_size (section);
- if (note_size < (4 + kp->ki_rusage_ch + kp->ru_majflt
- + long_bit / TARGET_CHAR_BIT))
- error (_("malformed core note - too short"));
- gdb::def_vector<unsigned char> contents (note_size);
- if (!bfd_get_section_contents (core_bfd, section, contents.data (),
- 0, note_size))
- error (_("could not get core note contents"));
- descdata = contents.data ();
- /* Skip over the structure size. */
- descdata += 4;
- /* Verify 'ki_layout' is 0. */
- if (bfd_get_32 (core_bfd, descdata + kp->ki_layout) != 0)
- {
- warning (_("unsupported process information in core file"));
- return;
- }
- gdb_printf ("Name: %.19s\n", descdata + kp->ki_comm);
- gdb_printf ("Process ID: %s\n",
- pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_pid)));
- gdb_printf ("Parent process: %s\n",
- pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_ppid)));
- gdb_printf ("Process group: %s\n",
- pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_pgid)));
- gdb_printf ("Session id: %s\n",
- pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_sid)));
- /* FreeBSD 12.0 and later store a 64-bit dev_t at 'ki_tdev'. Older
- kernels store a 32-bit dev_t at 'ki_tdev_freebsd11'. In older
- kernels the 64-bit 'ki_tdev' field is in a reserved section of
- the structure that is cleared to zero. Assume that a zero value
- in ki_tdev indicates a core dump from an older kernel and use the
- value in 'ki_tdev_freebsd11' instead. */
- value = bfd_get_64 (core_bfd, descdata + kp->ki_tdev);
- if (value == 0)
- value = bfd_get_32 (core_bfd, descdata + kp->ki_tdev_freebsd11);
- gdb_printf ("TTY: %s\n", pulongest (value));
- gdb_printf ("TTY owner process group: %s\n",
- pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_tpgid)));
- gdb_printf ("User IDs (real, effective, saved): %s %s %s\n",
- pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_ruid)),
- pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_uid)),
- pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_svuid)));
- gdb_printf ("Group IDs (real, effective, saved): %s %s %s\n",
- pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_rgid)),
- pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_groups)),
- pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_svgid)));
- gdb_printf ("Groups: ");
- uint16_t ngroups = bfd_get_16 (core_bfd, descdata + kp->ki_ngroups);
- for (int i = 0; i < ngroups; i++)
- gdb_printf ("%s ",
- pulongest (bfd_get_32 (core_bfd,
- descdata + kp->ki_groups + i * 4)));
- gdb_printf ("\n");
- value = bfd_get (long_bit, core_bfd,
- descdata + kp->ki_rusage + kp->ru_minflt);
- gdb_printf ("Minor faults (no memory page): %s\n", pulongest (value));
- value = bfd_get (long_bit, core_bfd,
- descdata + kp->ki_rusage_ch + kp->ru_minflt);
- gdb_printf ("Minor faults, children: %s\n", pulongest (value));
- value = bfd_get (long_bit, core_bfd,
- descdata + kp->ki_rusage + kp->ru_majflt);
- gdb_printf ("Major faults (memory page faults): %s\n",
- pulongest (value));
- value = bfd_get (long_bit, core_bfd,
- descdata + kp->ki_rusage_ch + kp->ru_majflt);
- gdb_printf ("Major faults, children: %s\n", pulongest (value));
- fbsd_core_fetch_timeval (gdbarch,
- descdata + kp->ki_rusage + kp->ru_utime,
- sec, value);
- gdb_printf ("utime: %s.%06d\n", plongest (sec), (int) value);
- fbsd_core_fetch_timeval (gdbarch,
- descdata + kp->ki_rusage + kp->ru_stime,
- sec, value);
- gdb_printf ("stime: %s.%06d\n", plongest (sec), (int) value);
- fbsd_core_fetch_timeval (gdbarch,
- descdata + kp->ki_rusage_ch + kp->ru_utime,
- sec, value);
- gdb_printf ("utime, children: %s.%06d\n", plongest (sec), (int) value);
- fbsd_core_fetch_timeval (gdbarch,
- descdata + kp->ki_rusage_ch + kp->ru_stime,
- sec, value);
- gdb_printf ("stime, children: %s.%06d\n", plongest (sec), (int) value);
- gdb_printf ("'nice' value: %d\n",
- (int) bfd_get_signed_8 (core_bfd, descdata + kp->ki_nice));
- fbsd_core_fetch_timeval (gdbarch, descdata + kp->ki_start, sec, value);
- gdb_printf ("Start time: %s.%06d\n", plongest (sec), (int) value);
- gdb_printf ("Virtual memory size: %s kB\n",
- pulongest (bfd_get (addr_bit, core_bfd,
- descdata + kp->ki_size) / 1024));
- gdb_printf ("Data size: %s pages\n",
- pulongest (bfd_get (addr_bit, core_bfd,
- descdata + kp->ki_dsize)));
- gdb_printf ("Stack size: %s pages\n",
- pulongest (bfd_get (addr_bit, core_bfd,
- descdata + kp->ki_ssize)));
- gdb_printf ("Text size: %s pages\n",
- pulongest (bfd_get (addr_bit, core_bfd,
- descdata + kp->ki_tsize)));
- gdb_printf ("Resident set size: %s pages\n",
- pulongest (bfd_get (addr_bit, core_bfd,
- descdata + kp->ki_rssize)));
- gdb_printf ("Maximum RSS: %s pages\n",
- pulongest (bfd_get (long_bit, core_bfd,
- descdata + kp->ki_rusage
- + kp->ru_maxrss)));
- fbsd_print_sigset ("Ignored Signals", descdata + kp->ki_sigignore);
- fbsd_print_sigset ("Caught Signals", descdata + kp->ki_sigcatch);
- }
- /* Implement the "core_info_proc" gdbarch method. */
- static void
- fbsd_core_info_proc (struct gdbarch *gdbarch, const char *args,
- enum info_proc_what what)
- {
- bool do_cmdline = false;
- bool do_cwd = false;
- bool do_exe = false;
- bool do_files = false;
- bool do_mappings = false;
- bool do_status = false;
- int pid;
- switch (what)
- {
- case IP_MINIMAL:
- do_cmdline = true;
- do_cwd = true;
- do_exe = true;
- break;
- case IP_MAPPINGS:
- do_mappings = true;
- break;
- case IP_STATUS:
- case IP_STAT:
- do_status = true;
- break;
- case IP_CMDLINE:
- do_cmdline = true;
- break;
- case IP_EXE:
- do_exe = true;
- break;
- case IP_CWD:
- do_cwd = true;
- break;
- case IP_FILES:
- do_files = true;
- break;
- case IP_ALL:
- do_cmdline = true;
- do_cwd = true;
- do_exe = true;
- do_files = true;
- do_mappings = true;
- do_status = true;
- break;
- default:
- return;
- }
- pid = bfd_core_file_pid (core_bfd);
- if (pid != 0)
- gdb_printf (_("process %d\n"), pid);
- if (do_cmdline)
- {
- const char *cmdline;
- cmdline = bfd_core_file_failing_command (core_bfd);
- if (cmdline)
- gdb_printf ("cmdline = '%s'\n", cmdline);
- else
- warning (_("Command line unavailable"));
- }
- if (do_cwd)
- {
- gdb::unique_xmalloc_ptr<char> cwd =
- fbsd_core_vnode_path (gdbarch, KINFO_FILE_FD_TYPE_CWD);
- if (cwd)
- gdb_printf ("cwd = '%s'\n", cwd.get ());
- else
- warning (_("unable to read current working directory"));
- }
- if (do_exe)
- {
- gdb::unique_xmalloc_ptr<char> exe =
- fbsd_core_vnode_path (gdbarch, KINFO_FILE_FD_TYPE_TEXT);
- if (exe)
- gdb_printf ("exe = '%s'\n", exe.get ());
- else
- warning (_("unable to read executable path name"));
- }
- if (do_files)
- fbsd_core_info_proc_files (gdbarch);
- if (do_mappings)
- fbsd_core_info_proc_mappings (gdbarch);
- if (do_status)
- fbsd_core_info_proc_status (gdbarch);
- }
- /* Print descriptions of FreeBSD-specific AUXV entries to FILE. */
- static void
- fbsd_print_auxv_entry (struct gdbarch *gdbarch, struct ui_file *file,
- CORE_ADDR type, CORE_ADDR val)
- {
- const char *name = "???";
- const char *description = "";
- enum auxv_format format = AUXV_FORMAT_HEX;
- switch (type)
- {
- case AT_NULL:
- case AT_IGNORE:
- case AT_EXECFD:
- case AT_PHDR:
- case AT_PHENT:
- case AT_PHNUM:
- case AT_PAGESZ:
- case AT_BASE:
- case AT_FLAGS:
- case AT_ENTRY:
- case AT_NOTELF:
- case AT_UID:
- case AT_EUID:
- case AT_GID:
- case AT_EGID:
- default_print_auxv_entry (gdbarch, file, type, val);
- return;
- #define _TAGNAME(tag) #tag
- #define TAGNAME(tag) _TAGNAME(AT_##tag)
- #define TAG(tag, text, kind) \
- case AT_FREEBSD_##tag: name = TAGNAME(tag); description = text; format = kind; break
- TAG (EXECPATH, _("Executable path"), AUXV_FORMAT_STR);
- TAG (CANARY, _("Canary for SSP"), AUXV_FORMAT_HEX);
- TAG (CANARYLEN, ("Length of the SSP canary"), AUXV_FORMAT_DEC);
- TAG (OSRELDATE, _("OSRELDATE"), AUXV_FORMAT_DEC);
- TAG (NCPUS, _("Number of CPUs"), AUXV_FORMAT_DEC);
- TAG (PAGESIZES, _("Pagesizes"), AUXV_FORMAT_HEX);
- TAG (PAGESIZESLEN, _("Number of pagesizes"), AUXV_FORMAT_DEC);
- TAG (TIMEKEEP, _("Pointer to timehands"), AUXV_FORMAT_HEX);
- TAG (STACKPROT, _("Initial stack protection"), AUXV_FORMAT_HEX);
- TAG (EHDRFLAGS, _("ELF header e_flags"), AUXV_FORMAT_HEX);
- TAG (HWCAP, _("Machine-dependent CPU capability hints"), AUXV_FORMAT_HEX);
- TAG (HWCAP2, _("Extension of AT_HWCAP"), AUXV_FORMAT_HEX);
- TAG (BSDFLAGS, _("ELF BSD flags"), AUXV_FORMAT_HEX);
- TAG (ARGC, _("Argument count"), AUXV_FORMAT_DEC);
- TAG (ARGV, _("Argument vector"), AUXV_FORMAT_HEX);
- TAG (ENVC, _("Environment count"), AUXV_FORMAT_DEC);
- TAG (ENVV, _("Environment vector"), AUXV_FORMAT_HEX);
- TAG (PS_STRINGS, _("Pointer to ps_strings"), AUXV_FORMAT_HEX);
- TAG (FXRNG, _("Pointer to root RNG seed version"), AUXV_FORMAT_HEX);
- TAG (KPRELOAD, _("Base address of vDSO"), AUXV_FORMAT_HEX);
- }
- fprint_auxv_entry (file, name, description, format, type, val);
- }
- /* Implement the "get_siginfo_type" gdbarch method. */
- static struct type *
- fbsd_get_siginfo_type (struct gdbarch *gdbarch)
- {
- struct fbsd_gdbarch_data *fbsd_gdbarch_data;
- struct type *int_type, *int32_type, *uint32_type, *long_type, *void_ptr_type;
- struct type *uid_type, *pid_type;
- struct type *sigval_type, *reason_type;
- struct type *siginfo_type;
- struct type *type;
- fbsd_gdbarch_data = get_fbsd_gdbarch_data (gdbarch);
- if (fbsd_gdbarch_data->siginfo_type != NULL)
- return fbsd_gdbarch_data->siginfo_type;
- int_type = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch),
- 0, "int");
- int32_type = arch_integer_type (gdbarch, 32, 0, "int32_t");
- uint32_type = arch_integer_type (gdbarch, 32, 1, "uint32_t");
- long_type = arch_integer_type (gdbarch, gdbarch_long_bit (gdbarch),
- 0, "long");
- void_ptr_type = lookup_pointer_type (builtin_type (gdbarch)->builtin_void);
- /* union sigval */
- sigval_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION);
- sigval_type->set_name (xstrdup ("sigval"));
- append_composite_type_field (sigval_type, "sival_int", int_type);
- append_composite_type_field (sigval_type, "sival_ptr", void_ptr_type);
- /* __pid_t */
- pid_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF,
- TYPE_LENGTH (int32_type) * TARGET_CHAR_BIT, "__pid_t");
- TYPE_TARGET_TYPE (pid_type) = int32_type;
- pid_type->set_target_is_stub (true);
- /* __uid_t */
- uid_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF,
- TYPE_LENGTH (uint32_type) * TARGET_CHAR_BIT,
- "__uid_t");
- TYPE_TARGET_TYPE (uid_type) = uint32_type;
- pid_type->set_target_is_stub (true);
- /* _reason */
- reason_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION);
- /* _fault */
- type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
- append_composite_type_field (type, "si_trapno", int_type);
- append_composite_type_field (reason_type, "_fault", type);
- /* _timer */
- type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
- append_composite_type_field (type, "si_timerid", int_type);
- append_composite_type_field (type, "si_overrun", int_type);
- append_composite_type_field (reason_type, "_timer", type);
- /* _mesgq */
- type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
- append_composite_type_field (type, "si_mqd", int_type);
- append_composite_type_field (reason_type, "_mesgq", type);
- /* _poll */
- type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
- append_composite_type_field (type, "si_band", long_type);
- append_composite_type_field (reason_type, "_poll", type);
- /* __spare__ */
- type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
- append_composite_type_field (type, "__spare1__", long_type);
- append_composite_type_field (type, "__spare2__",
- init_vector_type (int_type, 7));
- append_composite_type_field (reason_type, "__spare__", type);
- /* struct siginfo */
- siginfo_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
- siginfo_type->set_name (xstrdup ("siginfo"));
- append_composite_type_field (siginfo_type, "si_signo", int_type);
- append_composite_type_field (siginfo_type, "si_errno", int_type);
- append_composite_type_field (siginfo_type, "si_code", int_type);
- append_composite_type_field (siginfo_type, "si_pid", pid_type);
- append_composite_type_field (siginfo_type, "si_uid", uid_type);
- append_composite_type_field (siginfo_type, "si_status", int_type);
- append_composite_type_field (siginfo_type, "si_addr", void_ptr_type);
- append_composite_type_field (siginfo_type, "si_value", sigval_type);
- append_composite_type_field (siginfo_type, "_reason", reason_type);
- fbsd_gdbarch_data->siginfo_type = siginfo_type;
- return siginfo_type;
- }
- /* Implement the "gdb_signal_from_target" gdbarch method. */
- static enum gdb_signal
- fbsd_gdb_signal_from_target (struct gdbarch *gdbarch, int signal)
- {
- switch (signal)
- {
- case 0:
- return GDB_SIGNAL_0;
- case FREEBSD_SIGHUP:
- return GDB_SIGNAL_HUP;
- case FREEBSD_SIGINT:
- return GDB_SIGNAL_INT;
- case FREEBSD_SIGQUIT:
- return GDB_SIGNAL_QUIT;
- case FREEBSD_SIGILL:
- return GDB_SIGNAL_ILL;
- case FREEBSD_SIGTRAP:
- return GDB_SIGNAL_TRAP;
- case FREEBSD_SIGABRT:
- return GDB_SIGNAL_ABRT;
- case FREEBSD_SIGEMT:
- return GDB_SIGNAL_EMT;
- case FREEBSD_SIGFPE:
- return GDB_SIGNAL_FPE;
- case FREEBSD_SIGKILL:
- return GDB_SIGNAL_KILL;
- case FREEBSD_SIGBUS:
- return GDB_SIGNAL_BUS;
- case FREEBSD_SIGSEGV:
- return GDB_SIGNAL_SEGV;
- case FREEBSD_SIGSYS:
- return GDB_SIGNAL_SYS;
- case FREEBSD_SIGPIPE:
- return GDB_SIGNAL_PIPE;
- case FREEBSD_SIGALRM:
- return GDB_SIGNAL_ALRM;
- case FREEBSD_SIGTERM:
- return GDB_SIGNAL_TERM;
- case FREEBSD_SIGURG:
- return GDB_SIGNAL_URG;
- case FREEBSD_SIGSTOP:
- return GDB_SIGNAL_STOP;
- case FREEBSD_SIGTSTP:
- return GDB_SIGNAL_TSTP;
- case FREEBSD_SIGCONT:
- return GDB_SIGNAL_CONT;
- case FREEBSD_SIGCHLD:
- return GDB_SIGNAL_CHLD;
- case FREEBSD_SIGTTIN:
- return GDB_SIGNAL_TTIN;
- case FREEBSD_SIGTTOU:
- return GDB_SIGNAL_TTOU;
- case FREEBSD_SIGIO:
- return GDB_SIGNAL_IO;
- case FREEBSD_SIGXCPU:
- return GDB_SIGNAL_XCPU;
- case FREEBSD_SIGXFSZ:
- return GDB_SIGNAL_XFSZ;
- case FREEBSD_SIGVTALRM:
- return GDB_SIGNAL_VTALRM;
- case FREEBSD_SIGPROF:
- return GDB_SIGNAL_PROF;
- case FREEBSD_SIGWINCH:
- return GDB_SIGNAL_WINCH;
- case FREEBSD_SIGINFO:
- return GDB_SIGNAL_INFO;
- case FREEBSD_SIGUSR1:
- return GDB_SIGNAL_USR1;
- case FREEBSD_SIGUSR2:
- return GDB_SIGNAL_USR2;
- /* SIGTHR is the same as SIGLWP on FreeBSD. */
- case FREEBSD_SIGTHR:
- return GDB_SIGNAL_LWP;
- case FREEBSD_SIGLIBRT:
- return GDB_SIGNAL_LIBRT;
- }
- if (signal >= FREEBSD_SIGRTMIN && signal <= FREEBSD_SIGRTMAX)
- {
- int offset = signal - FREEBSD_SIGRTMIN;
- return (enum gdb_signal) ((int) GDB_SIGNAL_REALTIME_65 + offset);
- }
- return GDB_SIGNAL_UNKNOWN;
- }
- /* Implement the "gdb_signal_to_target" gdbarch method. */
- static int
- fbsd_gdb_signal_to_target (struct gdbarch *gdbarch,
- enum gdb_signal signal)
- {
- switch (signal)
- {
- case GDB_SIGNAL_0:
- return 0;
- case GDB_SIGNAL_HUP:
- return FREEBSD_SIGHUP;
- case GDB_SIGNAL_INT:
- return FREEBSD_SIGINT;
- case GDB_SIGNAL_QUIT:
- return FREEBSD_SIGQUIT;
- case GDB_SIGNAL_ILL:
- return FREEBSD_SIGILL;
- case GDB_SIGNAL_TRAP:
- return FREEBSD_SIGTRAP;
- case GDB_SIGNAL_ABRT:
- return FREEBSD_SIGABRT;
- case GDB_SIGNAL_EMT:
- return FREEBSD_SIGEMT;
- case GDB_SIGNAL_FPE:
- return FREEBSD_SIGFPE;
- case GDB_SIGNAL_KILL:
- return FREEBSD_SIGKILL;
- case GDB_SIGNAL_BUS:
- return FREEBSD_SIGBUS;
- case GDB_SIGNAL_SEGV:
- return FREEBSD_SIGSEGV;
- case GDB_SIGNAL_SYS:
- return FREEBSD_SIGSYS;
- case GDB_SIGNAL_PIPE:
- return FREEBSD_SIGPIPE;
- case GDB_SIGNAL_ALRM:
- return FREEBSD_SIGALRM;
- case GDB_SIGNAL_TERM:
- return FREEBSD_SIGTERM;
- case GDB_SIGNAL_URG:
- return FREEBSD_SIGURG;
- case GDB_SIGNAL_STOP:
- return FREEBSD_SIGSTOP;
- case GDB_SIGNAL_TSTP:
- return FREEBSD_SIGTSTP;
- case GDB_SIGNAL_CONT:
- return FREEBSD_SIGCONT;
- case GDB_SIGNAL_CHLD:
- return FREEBSD_SIGCHLD;
- case GDB_SIGNAL_TTIN:
- return FREEBSD_SIGTTIN;
- case GDB_SIGNAL_TTOU:
- return FREEBSD_SIGTTOU;
- case GDB_SIGNAL_IO:
- return FREEBSD_SIGIO;
- case GDB_SIGNAL_XCPU:
- return FREEBSD_SIGXCPU;
- case GDB_SIGNAL_XFSZ:
- return FREEBSD_SIGXFSZ;
- case GDB_SIGNAL_VTALRM:
- return FREEBSD_SIGVTALRM;
- case GDB_SIGNAL_PROF:
- return FREEBSD_SIGPROF;
- case GDB_SIGNAL_WINCH:
- return FREEBSD_SIGWINCH;
- case GDB_SIGNAL_INFO:
- return FREEBSD_SIGINFO;
- case GDB_SIGNAL_USR1:
- return FREEBSD_SIGUSR1;
- case GDB_SIGNAL_USR2:
- return FREEBSD_SIGUSR2;
- case GDB_SIGNAL_LWP:
- return FREEBSD_SIGTHR;
- case GDB_SIGNAL_LIBRT:
- return FREEBSD_SIGLIBRT;
- }
- if (signal >= GDB_SIGNAL_REALTIME_65
- && signal <= GDB_SIGNAL_REALTIME_126)
- {
- int offset = signal - GDB_SIGNAL_REALTIME_65;
- return FREEBSD_SIGRTMIN + offset;
- }
- return -1;
- }
- /* Implement the "get_syscall_number" gdbarch method. */
- static LONGEST
- fbsd_get_syscall_number (struct gdbarch *gdbarch, thread_info *thread)
- {
- /* FreeBSD doesn't use gdbarch_get_syscall_number since FreeBSD
- native targets fetch the system call number from the
- 'pl_syscall_code' member of struct ptrace_lwpinfo in fbsd_wait.
- However, system call catching requires this function to be
- set. */
- internal_error (__FILE__, __LINE__, _("fbsd_get_sycall_number called"));
- }
- /* Read an integer symbol value from the current target. */
- static LONGEST
- fbsd_read_integer_by_name (struct gdbarch *gdbarch, const char *name)
- {
- bound_minimal_symbol ms = lookup_minimal_symbol (name, NULL, NULL);
- if (ms.minsym == NULL)
- error (_("Unable to resolve symbol '%s'"), name);
- gdb_byte buf[4];
- if (target_read_memory (BMSYMBOL_VALUE_ADDRESS (ms), buf, sizeof buf) != 0)
- error (_("Unable to read value of '%s'"), name);
- return extract_signed_integer (buf, gdbarch_byte_order (gdbarch));
- }
- /* Lookup offsets of fields in the runtime linker's 'Obj_Entry'
- structure needed to determine the TLS index of an object file. */
- static void
- fbsd_fetch_rtld_offsets (struct gdbarch *gdbarch, struct fbsd_pspace_data *data)
- {
- try
- {
- /* Fetch offsets from debug symbols in rtld. */
- struct symbol *obj_entry_sym
- = lookup_symbol_in_language ("Struct_Obj_Entry", NULL, STRUCT_DOMAIN,
- language_c, NULL).symbol;
- if (obj_entry_sym == NULL)
- error (_("Unable to find Struct_Obj_Entry symbol"));
- data->off_linkmap = lookup_struct_elt (obj_entry_sym->type (),
- "linkmap", 0).offset / 8;
- data->off_tlsindex = lookup_struct_elt (obj_entry_sym->type (),
- "tlsindex", 0).offset / 8;
- data->rtld_offsets_valid = true;
- return;
- }
- catch (const gdb_exception_error &e)
- {
- data->off_linkmap = -1;
- }
- try
- {
- /* Fetch offsets from global variables in libthr. Note that
- this does not work for single-threaded processes that are not
- linked against libthr. */
- data->off_linkmap = fbsd_read_integer_by_name (gdbarch,
- "_thread_off_linkmap");
- data->off_tlsindex = fbsd_read_integer_by_name (gdbarch,
- "_thread_off_tlsindex");
- data->rtld_offsets_valid = true;
- return;
- }
- catch (const gdb_exception_error &e)
- {
- data->off_linkmap = -1;
- }
- }
- /* Helper function to read the TLS index of an object file associated
- with a link map entry at LM_ADDR. */
- static LONGEST
- fbsd_get_tls_index (struct gdbarch *gdbarch, CORE_ADDR lm_addr)
- {
- struct fbsd_pspace_data *data = get_fbsd_pspace_data (current_program_space);
- if (!data->rtld_offsets_valid)
- fbsd_fetch_rtld_offsets (gdbarch, data);
- if (data->off_linkmap == -1)
- throw_error (TLS_GENERIC_ERROR,
- _("Cannot fetch runtime linker structure offsets"));
- /* Simulate container_of to convert from LM_ADDR to the Obj_Entry
- pointer and then compute the offset of the tlsindex member. */
- CORE_ADDR tlsindex_addr = lm_addr - data->off_linkmap + data->off_tlsindex;
- gdb_byte buf[4];
- if (target_read_memory (tlsindex_addr, buf, sizeof buf) != 0)
- throw_error (TLS_GENERIC_ERROR,
- _("Cannot find thread-local variables on this target"));
- return extract_signed_integer (buf, gdbarch_byte_order (gdbarch));
- }
- /* See fbsd-tdep.h. */
- CORE_ADDR
- fbsd_get_thread_local_address (struct gdbarch *gdbarch, CORE_ADDR dtv_addr,
- CORE_ADDR lm_addr, CORE_ADDR offset)
- {
- LONGEST tls_index = fbsd_get_tls_index (gdbarch, lm_addr);
- gdb_byte buf[gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT];
- if (target_read_memory (dtv_addr, buf, sizeof buf) != 0)
- throw_error (TLS_GENERIC_ERROR,
- _("Cannot find thread-local variables on this target"));
- const struct builtin_type *builtin = builtin_type (gdbarch);
- CORE_ADDR addr = gdbarch_pointer_to_address (gdbarch,
- builtin->builtin_data_ptr, buf);
- addr += (tls_index + 1) * TYPE_LENGTH (builtin->builtin_data_ptr);
- if (target_read_memory (addr, buf, sizeof buf) != 0)
- throw_error (TLS_GENERIC_ERROR,
- _("Cannot find thread-local variables on this target"));
- addr = gdbarch_pointer_to_address (gdbarch, builtin->builtin_data_ptr, buf);
- return addr + offset;
- }
- /* See fbsd-tdep.h. */
- CORE_ADDR
- fbsd_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- struct bound_minimal_symbol msym = lookup_bound_minimal_symbol ("_rtld_bind");
- if (msym.minsym != nullptr && BMSYMBOL_VALUE_ADDRESS (msym) == pc)
- return frame_unwind_caller_pc (get_current_frame ());
- return 0;
- }
- /* Return description of signal code or nullptr. */
- static const char *
- fbsd_signal_cause (enum gdb_signal siggnal, int code)
- {
- /* Signal-independent causes. */
- switch (code)
- {
- case FBSD_SI_USER:
- return _("Sent by kill()");
- case FBSD_SI_QUEUE:
- return _("Sent by sigqueue()");
- case FBSD_SI_TIMER:
- return _("Timer expired");
- case FBSD_SI_ASYNCIO:
- return _("Asynchronous I/O request completed");
- case FBSD_SI_MESGQ:
- return _("Message arrived on empty message queue");
- case FBSD_SI_KERNEL:
- return _("Sent by kernel");
- case FBSD_SI_LWP:
- return _("Sent by thr_kill()");
- }
- switch (siggnal)
- {
- case GDB_SIGNAL_ILL:
- switch (code)
- {
- case FBSD_ILL_ILLOPC:
- return _("Illegal opcode");
- case FBSD_ILL_ILLOPN:
- return _("Illegal operand");
- case FBSD_ILL_ILLADR:
- return _("Illegal addressing mode");
- case FBSD_ILL_ILLTRP:
- return _("Illegal trap");
- case FBSD_ILL_PRVOPC:
- return _("Privileged opcode");
- case FBSD_ILL_PRVREG:
- return _("Privileged register");
- case FBSD_ILL_COPROC:
- return _("Coprocessor error");
- case FBSD_ILL_BADSTK:
- return _("Internal stack error");
- }
- break;
- case GDB_SIGNAL_BUS:
- switch (code)
- {
- case FBSD_BUS_ADRALN:
- return _("Invalid address alignment");
- case FBSD_BUS_ADRERR:
- return _("Address not present");
- case FBSD_BUS_OBJERR:
- return _("Object-specific hardware error");
- case FBSD_BUS_OOMERR:
- return _("Out of memory");
- }
- break;
- case GDB_SIGNAL_SEGV:
- switch (code)
- {
- case FBSD_SEGV_MAPERR:
- return _("Address not mapped to object");
- case FBSD_SEGV_ACCERR:
- return _("Invalid permissions for mapped object");
- case FBSD_SEGV_PKUERR:
- return _("PKU violation");
- }
- break;
- case GDB_SIGNAL_FPE:
- switch (code)
- {
- case FBSD_FPE_INTOVF:
- return _("Integer overflow");
- case FBSD_FPE_INTDIV:
- return _("Integer divide by zero");
- case FBSD_FPE_FLTDIV:
- return _("Floating point divide by zero");
- case FBSD_FPE_FLTOVF:
- return _("Floating point overflow");
- case FBSD_FPE_FLTUND:
- return _("Floating point underflow");
- case FBSD_FPE_FLTRES:
- return _("Floating point inexact result");
- case FBSD_FPE_FLTINV:
- return _("Invalid floating point operation");
- case FBSD_FPE_FLTSUB:
- return _("Subscript out of range");
- }
- break;
- case GDB_SIGNAL_TRAP:
- switch (code)
- {
- case FBSD_TRAP_BRKPT:
- return _("Breakpoint");
- case FBSD_TRAP_TRACE:
- return _("Trace trap");
- case FBSD_TRAP_DTRACE:
- return _("DTrace-induced trap");
- case FBSD_TRAP_CAP:
- return _("Capability violation");
- }
- break;
- case GDB_SIGNAL_CHLD:
- switch (code)
- {
- case FBSD_CLD_EXITED:
- return _("Child has exited");
- case FBSD_CLD_KILLED:
- return _("Child has terminated abnormally");
- case FBSD_CLD_DUMPED:
- return _("Child has dumped core");
- case FBSD_CLD_TRAPPED:
- return _("Traced child has trapped");
- case FBSD_CLD_STOPPED:
- return _("Child has stopped");
- case FBSD_CLD_CONTINUED:
- return _("Stopped child has continued");
- }
- break;
- case GDB_SIGNAL_POLL:
- switch (code)
- {
- case FBSD_POLL_IN:
- return _("Data input available");
- case FBSD_POLL_OUT:
- return _("Output buffers available");
- case FBSD_POLL_MSG:
- return _("Input message available");
- case FBSD_POLL_ERR:
- return _("I/O error");
- case FBSD_POLL_PRI:
- return _("High priority input available");
- case FBSD_POLL_HUP:
- return _("Device disconnected");
- }
- break;
- }
- return nullptr;
- }
- /* Report additional details for a signal stop. */
- static void
- fbsd_report_signal_info (struct gdbarch *gdbarch, struct ui_out *uiout,
- enum gdb_signal siggnal)
- {
- LONGEST code, mqd, pid, status, timerid, uid;
- try
- {
- code = parse_and_eval_long ("$_siginfo.si_code");
- pid = parse_and_eval_long ("$_siginfo.si_pid");
- uid = parse_and_eval_long ("$_siginfo.si_uid");
- status = parse_and_eval_long ("$_siginfo.si_status");
- timerid = parse_and_eval_long ("$_siginfo._reason._timer.si_timerid");
- mqd = parse_and_eval_long ("$_siginfo._reason._mesgq.si_mqd");
- }
- catch (const gdb_exception_error &e)
- {
- return;
- }
- const char *meaning = fbsd_signal_cause (siggnal, code);
- if (meaning == nullptr)
- return;
- uiout->text (".\n");
- uiout->field_string ("sigcode-meaning", meaning);
- switch (code)
- {
- case FBSD_SI_USER:
- case FBSD_SI_QUEUE:
- case FBSD_SI_LWP:
- uiout->text (" from pid ");
- uiout->field_string ("sending-pid", plongest (pid));
- uiout->text (" and user ");
- uiout->field_string ("sending-uid", plongest (uid));
- return;
- case FBSD_SI_TIMER:
- uiout->text (": timerid ");
- uiout->field_string ("timerid", plongest (timerid));
- return;
- case FBSD_SI_MESGQ:
- uiout->text (": message queue ");
- uiout->field_string ("message-queue", plongest (mqd));
- return;
- case FBSD_SI_ASYNCIO:
- return;
- }
- if (siggnal == GDB_SIGNAL_CHLD)
- {
- uiout->text (": pid ");
- uiout->field_string ("child-pid", plongest (pid));
- uiout->text (", uid ");
- uiout->field_string ("child-uid", plongest (uid));
- if (code == FBSD_CLD_EXITED)
- {
- uiout->text (", exit status ");
- uiout->field_string ("exit-status", plongest (status));
- }
- else
- {
- uiout->text (", signal ");
- uiout->field_string ("signal", plongest (status));
- }
- }
- }
- /* Search a list of struct kinfo_vmmap entries in the ENTRIES buffer
- of LEN bytes to find the length of the entry starting at ADDR.
- Returns the length of the entry or zero if no entry was found. */
- static ULONGEST
- fbsd_vmmap_length (struct gdbarch *gdbarch, unsigned char *entries, size_t len,
- CORE_ADDR addr)
- {
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- unsigned char *descdata = entries;
- unsigned char *descend = descdata + len;
- /* Skip over the structure size. */
- descdata += 4;
- while (descdata + KVE_PATH < descend)
- {
- ULONGEST structsize = extract_unsigned_integer (descdata
- + KVE_STRUCTSIZE, 4,
- byte_order);
- if (structsize < KVE_PATH)
- return false;
- ULONGEST start = extract_unsigned_integer (descdata + KVE_START, 8,
- byte_order);
- ULONGEST end = extract_unsigned_integer (descdata + KVE_END, 8,
- byte_order);
- if (start == addr)
- return end - start;
- descdata += structsize;
- }
- return 0;
- }
- /* Helper for fbsd_vsyscall_range that does the real work of finding
- the vDSO's address range. */
- static bool
- fbsd_vdso_range (struct gdbarch *gdbarch, struct mem_range *range)
- {
- struct target_ops *ops = current_inferior ()->top_target ();
- if (target_auxv_search (ops, AT_FREEBSD_KPRELOAD, &range->start) <= 0)
- return false;
- if (!target_has_execution ())
- {
- /* Search for the ending address in the NT_PROCSTAT_VMMAP note. */
- asection *section = bfd_get_section_by_name (core_bfd,
- ".note.freebsdcore.vmmap");
- if (section == nullptr)
- return false;
- size_t note_size = bfd_section_size (section);
- if (note_size < 4)
- return false;
- gdb::def_vector<unsigned char> contents (note_size);
- if (!bfd_get_section_contents (core_bfd, section, contents.data (),
- 0, note_size))
- return false;
- range->length = fbsd_vmmap_length (gdbarch, contents.data (), note_size,
- range->start);
- }
- else
- {
- /* Fetch the list of address space entries from the running target. */
- gdb::optional<gdb::byte_vector> buf =
- target_read_alloc (ops, TARGET_OBJECT_FREEBSD_VMMAP, nullptr);
- if (!buf || buf->empty ())
- return false;
- range->length = fbsd_vmmap_length (gdbarch, buf->data (), buf->size (),
- range->start);
- }
- return range->length != 0;
- }
- /* Return the address range of the vDSO for the current inferior. */
- static int
- fbsd_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range)
- {
- struct fbsd_pspace_data *data = get_fbsd_pspace_data (current_program_space);
- if (data->vdso_range_p == 0)
- {
- if (fbsd_vdso_range (gdbarch, &data->vdso_range))
- data->vdso_range_p = 1;
- else
- data->vdso_range_p = -1;
- }
- if (data->vdso_range_p < 0)
- return 0;
- *range = data->vdso_range;
- return 1;
- }
- /* To be called from GDB_OSABI_FREEBSD handlers. */
- void
- fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
- {
- set_gdbarch_core_pid_to_str (gdbarch, fbsd_core_pid_to_str);
- set_gdbarch_core_thread_name (gdbarch, fbsd_core_thread_name);
- set_gdbarch_core_xfer_siginfo (gdbarch, fbsd_core_xfer_siginfo);
- set_gdbarch_make_corefile_notes (gdbarch, fbsd_make_corefile_notes);
- set_gdbarch_core_info_proc (gdbarch, fbsd_core_info_proc);
- set_gdbarch_print_auxv_entry (gdbarch, fbsd_print_auxv_entry);
- set_gdbarch_get_siginfo_type (gdbarch, fbsd_get_siginfo_type);
- set_gdbarch_gdb_signal_from_target (gdbarch, fbsd_gdb_signal_from_target);
- set_gdbarch_gdb_signal_to_target (gdbarch, fbsd_gdb_signal_to_target);
- set_gdbarch_report_signal_info (gdbarch, fbsd_report_signal_info);
- set_gdbarch_skip_solib_resolver (gdbarch, fbsd_skip_solib_resolver);
- set_gdbarch_vsyscall_range (gdbarch, fbsd_vsyscall_range);
- /* `catch syscall' */
- set_xml_syscall_file_name (gdbarch, "syscalls/freebsd.xml");
- set_gdbarch_get_syscall_number (gdbarch, fbsd_get_syscall_number);
- }
- void _initialize_fbsd_tdep ();
- void
- _initialize_fbsd_tdep ()
- {
- fbsd_gdbarch_data_handle =
- gdbarch_data_register_post_init (init_fbsd_gdbarch_data);
- }
|