1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215 |
- /* Memory breakpoint operations for the remote server for GDB.
- Copyright (C) 2002-2022 Free Software Foundation, Inc.
- Contributed by MontaVista Software.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "server.h"
- #include "regcache.h"
- #include "ax.h"
- #define MAX_BREAKPOINT_LEN 8
- /* Helper macro used in loops that append multiple items to a singly-linked
- list instead of inserting items at the head of the list, as, say, in the
- breakpoint lists. LISTPP is a pointer to the pointer that is the head of
- the new list. ITEMP is a pointer to the item to be added to the list.
- TAILP must be defined to be the same type as ITEMP, and initialized to
- NULL. */
- #define APPEND_TO_LIST(listpp, itemp, tailp) \
- do \
- { \
- if ((tailp) == NULL) \
- *(listpp) = (itemp); \
- else \
- (tailp)->next = (itemp); \
- (tailp) = (itemp); \
- } \
- while (0)
- /* GDB will never try to install multiple breakpoints at the same
- address. However, we can see GDB requesting to insert a breakpoint
- at an address is had already inserted one previously in a few
- situations.
- - The RSP documentation on Z packets says that to avoid potential
- problems with duplicate packets, the operations should be
- implemented in an idempotent way.
- - A breakpoint is set at ADDR, an address in a shared library.
- Then the shared library is unloaded. And then another, unrelated,
- breakpoint at ADDR is set. There is not breakpoint removal request
- between the first and the second breakpoint.
- - When GDB wants to update the target-side breakpoint conditions or
- commands, it re-inserts the breakpoint, with updated
- conditions/commands associated.
- Also, we need to keep track of internal breakpoints too, so we do
- need to be able to install multiple breakpoints at the same address
- transparently.
- We keep track of two different, and closely related structures. A
- raw breakpoint, which manages the low level, close to the metal
- aspect of a breakpoint. It holds the breakpoint address, and for
- software breakpoints, a buffer holding a copy of the instructions
- that would be in memory had not been a breakpoint there (we call
- that the shadow memory of the breakpoint). We occasionally need to
- temporarilly uninsert a breakpoint without the client knowing about
- it (e.g., to step over an internal breakpoint), so we keep an
- `inserted' state associated with this low level breakpoint
- structure. There can only be one such object for a given address.
- Then, we have (a bit higher level) breakpoints. This structure
- holds a callback to be called whenever a breakpoint is hit, a
- high-level type, and a link to a low level raw breakpoint. There
- can be many high-level breakpoints at the same address, and all of
- them will point to the same raw breakpoint, which is reference
- counted. */
- /* The low level, physical, raw breakpoint. */
- struct raw_breakpoint
- {
- struct raw_breakpoint *next;
- /* The low level type of the breakpoint (software breakpoint,
- watchpoint, etc.) */
- enum raw_bkpt_type raw_type;
- /* A reference count. Each high level breakpoint referencing this
- raw breakpoint accounts for one reference. */
- int refcount;
- /* The breakpoint's insertion address. There can only be one raw
- breakpoint for a given PC. */
- CORE_ADDR pc;
- /* The breakpoint's kind. This is target specific. Most
- architectures only use one specific instruction for breakpoints, while
- others may use more than one. E.g., on ARM, we need to use different
- breakpoint instructions on Thumb, Thumb-2, and ARM code. Likewise for
- hardware breakpoints -- some architectures (including ARM) need to
- setup debug registers differently depending on mode. */
- int kind;
- /* The breakpoint's shadow memory. */
- unsigned char old_data[MAX_BREAKPOINT_LEN];
- /* Positive if this breakpoint is currently inserted in the
- inferior. Negative if it was, but we've detected that it's now
- gone. Zero if not inserted. */
- int inserted;
- };
- /* The type of a breakpoint. */
- enum bkpt_type
- {
- /* A GDB breakpoint, requested with a Z0 packet. */
- gdb_breakpoint_Z0,
- /* A GDB hardware breakpoint, requested with a Z1 packet. */
- gdb_breakpoint_Z1,
- /* A GDB write watchpoint, requested with a Z2 packet. */
- gdb_breakpoint_Z2,
- /* A GDB read watchpoint, requested with a Z3 packet. */
- gdb_breakpoint_Z3,
- /* A GDB access watchpoint, requested with a Z4 packet. */
- gdb_breakpoint_Z4,
- /* A software single-step breakpoint. */
- single_step_breakpoint,
- /* Any other breakpoint type that doesn't require specific
- treatment goes here. E.g., an event breakpoint. */
- other_breakpoint,
- };
- struct point_cond_list
- {
- /* Pointer to the agent expression that is the breakpoint's
- conditional. */
- struct agent_expr *cond;
- /* Pointer to the next condition. */
- struct point_cond_list *next;
- };
- struct point_command_list
- {
- /* Pointer to the agent expression that is the breakpoint's
- commands. */
- struct agent_expr *cmd;
- /* Flag that is true if this command should run even while GDB is
- disconnected. */
- int persistence;
- /* Pointer to the next command. */
- struct point_command_list *next;
- };
- /* A high level (in gdbserver's perspective) breakpoint. */
- struct breakpoint
- {
- struct breakpoint *next;
- /* The breakpoint's type. */
- enum bkpt_type type;
- /* Link to this breakpoint's raw breakpoint. This is always
- non-NULL. */
- struct raw_breakpoint *raw;
- };
- /* Breakpoint requested by GDB. */
- struct gdb_breakpoint
- {
- struct breakpoint base;
- /* Pointer to the condition list that should be evaluated on
- the target or NULL if the breakpoint is unconditional or
- if GDB doesn't want us to evaluate the conditionals on the
- target's side. */
- struct point_cond_list *cond_list;
- /* Point to the list of commands to run when this is hit. */
- struct point_command_list *command_list;
- };
- /* Breakpoint used by GDBserver. */
- struct other_breakpoint
- {
- struct breakpoint base;
- /* Function to call when we hit this breakpoint. If it returns 1,
- the breakpoint shall be deleted; 0 or if this callback is NULL,
- it will be left inserted. */
- int (*handler) (CORE_ADDR);
- };
- /* Breakpoint for single step. */
- struct single_step_breakpoint
- {
- struct breakpoint base;
- /* Thread the reinsert breakpoint belongs to. */
- ptid_t ptid;
- };
- /* Return the breakpoint size from its kind. */
- static int
- bp_size (struct raw_breakpoint *bp)
- {
- int size = 0;
- the_target->sw_breakpoint_from_kind (bp->kind, &size);
- return size;
- }
- /* Return the breakpoint opcode from its kind. */
- static const gdb_byte *
- bp_opcode (struct raw_breakpoint *bp)
- {
- int size = 0;
- return the_target->sw_breakpoint_from_kind (bp->kind, &size);
- }
- /* See mem-break.h. */
- enum target_hw_bp_type
- raw_bkpt_type_to_target_hw_bp_type (enum raw_bkpt_type raw_type)
- {
- switch (raw_type)
- {
- case raw_bkpt_type_hw:
- return hw_execute;
- case raw_bkpt_type_write_wp:
- return hw_write;
- case raw_bkpt_type_read_wp:
- return hw_read;
- case raw_bkpt_type_access_wp:
- return hw_access;
- default:
- internal_error (__FILE__, __LINE__,
- "bad raw breakpoint type %d", (int) raw_type);
- }
- }
- /* See mem-break.h. */
- static enum bkpt_type
- Z_packet_to_bkpt_type (char z_type)
- {
- gdb_assert ('0' <= z_type && z_type <= '4');
- return (enum bkpt_type) (gdb_breakpoint_Z0 + (z_type - '0'));
- }
- /* See mem-break.h. */
- enum raw_bkpt_type
- Z_packet_to_raw_bkpt_type (char z_type)
- {
- switch (z_type)
- {
- case Z_PACKET_SW_BP:
- return raw_bkpt_type_sw;
- case Z_PACKET_HW_BP:
- return raw_bkpt_type_hw;
- case Z_PACKET_WRITE_WP:
- return raw_bkpt_type_write_wp;
- case Z_PACKET_READ_WP:
- return raw_bkpt_type_read_wp;
- case Z_PACKET_ACCESS_WP:
- return raw_bkpt_type_access_wp;
- default:
- gdb_assert_not_reached ("unhandled Z packet type.");
- }
- }
- /* Return true if breakpoint TYPE is a GDB breakpoint. */
- static int
- is_gdb_breakpoint (enum bkpt_type type)
- {
- return (type == gdb_breakpoint_Z0
- || type == gdb_breakpoint_Z1
- || type == gdb_breakpoint_Z2
- || type == gdb_breakpoint_Z3
- || type == gdb_breakpoint_Z4);
- }
- bool
- any_persistent_commands (process_info *proc)
- {
- struct breakpoint *bp;
- struct point_command_list *cl;
- for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
- {
- if (is_gdb_breakpoint (bp->type))
- {
- struct gdb_breakpoint *gdb_bp = (struct gdb_breakpoint *) bp;
- for (cl = gdb_bp->command_list; cl != NULL; cl = cl->next)
- if (cl->persistence)
- return true;
- }
- }
- return false;
- }
- /* Find low-level breakpoint of type TYPE at address ADDR that is not
- insert-disabled. Returns NULL if not found. */
- static struct raw_breakpoint *
- find_enabled_raw_code_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type)
- {
- struct process_info *proc = current_process ();
- struct raw_breakpoint *bp;
- for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
- if (bp->pc == addr
- && bp->raw_type == type
- && bp->inserted >= 0)
- return bp;
- return NULL;
- }
- /* Find low-level breakpoint of type TYPE at address ADDR. Returns
- NULL if not found. */
- static struct raw_breakpoint *
- find_raw_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type, int kind)
- {
- struct process_info *proc = current_process ();
- struct raw_breakpoint *bp;
- for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
- if (bp->pc == addr && bp->raw_type == type && bp->kind == kind)
- return bp;
- return NULL;
- }
- /* See mem-break.h. */
- int
- insert_memory_breakpoint (struct raw_breakpoint *bp)
- {
- unsigned char buf[MAX_BREAKPOINT_LEN];
- int err;
- /* Note that there can be fast tracepoint jumps installed in the
- same memory range, so to get at the original memory, we need to
- use read_inferior_memory, which masks those out. */
- err = read_inferior_memory (bp->pc, buf, bp_size (bp));
- if (err != 0)
- {
- threads_debug_printf ("Failed to read shadow memory of"
- " breakpoint at 0x%s (%s).",
- paddress (bp->pc), safe_strerror (err));
- }
- else
- {
- memcpy (bp->old_data, buf, bp_size (bp));
- err = the_target->write_memory (bp->pc, bp_opcode (bp),
- bp_size (bp));
- if (err != 0)
- threads_debug_printf ("Failed to insert breakpoint at 0x%s (%s).",
- paddress (bp->pc), safe_strerror (err));
- }
- return err != 0 ? -1 : 0;
- }
- /* See mem-break.h */
- int
- remove_memory_breakpoint (struct raw_breakpoint *bp)
- {
- unsigned char buf[MAX_BREAKPOINT_LEN];
- int err;
- /* Since there can be trap breakpoints inserted in the same address
- range, we use `target_write_memory', which takes care of
- layering breakpoints on top of fast tracepoints, and on top of
- the buffer we pass it. This works because the caller has already
- either unlinked the breakpoint or marked it uninserted. Also
- note that we need to pass the current shadow contents, because
- target_write_memory updates any shadow memory with what we pass
- here, and we want that to be a nop. */
- memcpy (buf, bp->old_data, bp_size (bp));
- err = target_write_memory (bp->pc, buf, bp_size (bp));
- if (err != 0)
- threads_debug_printf ("Failed to uninsert raw breakpoint "
- "at 0x%s (%s) while deleting it.",
- paddress (bp->pc), safe_strerror (err));
- return err != 0 ? -1 : 0;
- }
- /* Set a RAW breakpoint of type TYPE and kind KIND at WHERE. On
- success, a pointer to the new breakpoint is returned. On failure,
- returns NULL and writes the error code to *ERR. */
- static struct raw_breakpoint *
- set_raw_breakpoint_at (enum raw_bkpt_type type, CORE_ADDR where, int kind,
- int *err)
- {
- struct process_info *proc = current_process ();
- struct raw_breakpoint *bp;
- if (type == raw_bkpt_type_sw || type == raw_bkpt_type_hw)
- {
- bp = find_enabled_raw_code_breakpoint_at (where, type);
- if (bp != NULL && bp->kind != kind)
- {
- /* A different kind than previously seen. The previous
- breakpoint must be gone then. */
- threads_debug_printf
- ("Inconsistent breakpoint kind? Was %d, now %d.",
- bp->kind, kind);
- bp->inserted = -1;
- bp = NULL;
- }
- }
- else
- bp = find_raw_breakpoint_at (where, type, kind);
- gdb::unique_xmalloc_ptr<struct raw_breakpoint> bp_holder;
- if (bp == NULL)
- {
- bp_holder.reset (XCNEW (struct raw_breakpoint));
- bp = bp_holder.get ();
- bp->pc = where;
- bp->kind = kind;
- bp->raw_type = type;
- }
- if (!bp->inserted)
- {
- *err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp);
- if (*err != 0)
- {
- threads_debug_printf ("Failed to insert breakpoint at 0x%s (%d).",
- paddress (where), *err);
- return NULL;
- }
- bp->inserted = 1;
- }
- /* If the breakpoint was allocated above, we know we want to keep it
- now. */
- bp_holder.release ();
- /* Link the breakpoint in, if this is the first reference. */
- if (++bp->refcount == 1)
- {
- bp->next = proc->raw_breakpoints;
- proc->raw_breakpoints = bp;
- }
- return bp;
- }
- /* Notice that breakpoint traps are always installed on top of fast
- tracepoint jumps. This is even if the fast tracepoint is installed
- at a later time compared to when the breakpoint was installed.
- This means that a stopping breakpoint or tracepoint has higher
- "priority". In turn, this allows having fast and slow tracepoints
- (and breakpoints) at the same address behave correctly. */
- /* A fast tracepoint jump. */
- struct fast_tracepoint_jump
- {
- struct fast_tracepoint_jump *next;
- /* A reference count. GDB can install more than one fast tracepoint
- at the same address (each with its own action list, for
- example). */
- int refcount;
- /* The fast tracepoint's insertion address. There can only be one
- of these for a given PC. */
- CORE_ADDR pc;
- /* Non-zero if this fast tracepoint jump is currently inserted in
- the inferior. */
- int inserted;
- /* The length of the jump instruction. */
- int length;
- /* A poor-man's flexible array member, holding both the jump
- instruction to insert, and a copy of the instruction that would
- be in memory had not been a jump there (the shadow memory of the
- tracepoint jump). */
- unsigned char insn_and_shadow[0];
- };
- /* Fast tracepoint FP's jump instruction to insert. */
- #define fast_tracepoint_jump_insn(fp) \
- ((fp)->insn_and_shadow + 0)
- /* The shadow memory of fast tracepoint jump FP. */
- #define fast_tracepoint_jump_shadow(fp) \
- ((fp)->insn_and_shadow + (fp)->length)
- /* Return the fast tracepoint jump set at WHERE. */
- static struct fast_tracepoint_jump *
- find_fast_tracepoint_jump_at (CORE_ADDR where)
- {
- struct process_info *proc = current_process ();
- struct fast_tracepoint_jump *jp;
- for (jp = proc->fast_tracepoint_jumps; jp != NULL; jp = jp->next)
- if (jp->pc == where)
- return jp;
- return NULL;
- }
- int
- fast_tracepoint_jump_here (CORE_ADDR where)
- {
- struct fast_tracepoint_jump *jp = find_fast_tracepoint_jump_at (where);
- return (jp != NULL);
- }
- int
- delete_fast_tracepoint_jump (struct fast_tracepoint_jump *todel)
- {
- struct fast_tracepoint_jump *bp, **bp_link;
- int ret;
- struct process_info *proc = current_process ();
- bp = proc->fast_tracepoint_jumps;
- bp_link = &proc->fast_tracepoint_jumps;
- while (bp)
- {
- if (bp == todel)
- {
- if (--bp->refcount == 0)
- {
- struct fast_tracepoint_jump *prev_bp_link = *bp_link;
- unsigned char *buf;
- /* Unlink it. */
- *bp_link = bp->next;
- /* Since there can be breakpoints inserted in the same
- address range, we use `target_write_memory', which
- takes care of layering breakpoints on top of fast
- tracepoints, and on top of the buffer we pass it.
- This works because we've already unlinked the fast
- tracepoint jump above. Also note that we need to
- pass the current shadow contents, because
- target_write_memory updates any shadow memory with
- what we pass here, and we want that to be a nop. */
- buf = (unsigned char *) alloca (bp->length);
- memcpy (buf, fast_tracepoint_jump_shadow (bp), bp->length);
- ret = target_write_memory (bp->pc, buf, bp->length);
- if (ret != 0)
- {
- /* Something went wrong, relink the jump. */
- *bp_link = prev_bp_link;
- threads_debug_printf
- ("Failed to uninsert fast tracepoint jump "
- "at 0x%s (%s) while deleting it.",
- paddress (bp->pc), safe_strerror (ret));
- return ret;
- }
- free (bp);
- }
- return 0;
- }
- else
- {
- bp_link = &bp->next;
- bp = *bp_link;
- }
- }
- warning ("Could not find fast tracepoint jump in list.");
- return ENOENT;
- }
- void
- inc_ref_fast_tracepoint_jump (struct fast_tracepoint_jump *jp)
- {
- jp->refcount++;
- }
- struct fast_tracepoint_jump *
- set_fast_tracepoint_jump (CORE_ADDR where,
- unsigned char *insn, ULONGEST length)
- {
- struct process_info *proc = current_process ();
- struct fast_tracepoint_jump *jp;
- int err;
- unsigned char *buf;
- /* We refcount fast tracepoint jumps. Check if we already know
- about a jump at this address. */
- jp = find_fast_tracepoint_jump_at (where);
- if (jp != NULL)
- {
- jp->refcount++;
- return jp;
- }
- /* We don't, so create a new object. Double the length, because the
- flexible array member holds both the jump insn, and the
- shadow. */
- jp = (struct fast_tracepoint_jump *) xcalloc (1, sizeof (*jp) + (length * 2));
- jp->pc = where;
- jp->length = length;
- memcpy (fast_tracepoint_jump_insn (jp), insn, length);
- jp->refcount = 1;
- buf = (unsigned char *) alloca (length);
- /* Note that there can be trap breakpoints inserted in the same
- address range. To access the original memory contents, we use
- `read_inferior_memory', which masks out breakpoints. */
- err = read_inferior_memory (where, buf, length);
- if (err != 0)
- {
- threads_debug_printf ("Failed to read shadow memory of"
- " fast tracepoint at 0x%s (%s).",
- paddress (where), safe_strerror (err));
- free (jp);
- return NULL;
- }
- memcpy (fast_tracepoint_jump_shadow (jp), buf, length);
- /* Link the jump in. */
- jp->inserted = 1;
- jp->next = proc->fast_tracepoint_jumps;
- proc->fast_tracepoint_jumps = jp;
- /* Since there can be trap breakpoints inserted in the same address
- range, we use use `target_write_memory', which takes care of
- layering breakpoints on top of fast tracepoints, on top of the
- buffer we pass it. This works because we've already linked in
- the fast tracepoint jump above. Also note that we need to pass
- the current shadow contents, because target_write_memory
- updates any shadow memory with what we pass here, and we want
- that to be a nop. */
- err = target_write_memory (where, buf, length);
- if (err != 0)
- {
- threads_debug_printf
- ("Failed to insert fast tracepoint jump at 0x%s (%s).",
- paddress (where), safe_strerror (err));
- /* Unlink it. */
- proc->fast_tracepoint_jumps = jp->next;
- free (jp);
- return NULL;
- }
- return jp;
- }
- void
- uninsert_fast_tracepoint_jumps_at (CORE_ADDR pc)
- {
- struct fast_tracepoint_jump *jp;
- int err;
- jp = find_fast_tracepoint_jump_at (pc);
- if (jp == NULL)
- {
- /* This can happen when we remove all breakpoints while handling
- a step-over. */
- threads_debug_printf ("Could not find fast tracepoint jump at 0x%s "
- "in list (uninserting).",
- paddress (pc));
- return;
- }
- if (jp->inserted)
- {
- unsigned char *buf;
- jp->inserted = 0;
- /* Since there can be trap breakpoints inserted in the same
- address range, we use use `target_write_memory', which
- takes care of layering breakpoints on top of fast
- tracepoints, and on top of the buffer we pass it. This works
- because we've already marked the fast tracepoint fast
- tracepoint jump uninserted above. Also note that we need to
- pass the current shadow contents, because
- target_write_memory updates any shadow memory with what we
- pass here, and we want that to be a nop. */
- buf = (unsigned char *) alloca (jp->length);
- memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length);
- err = target_write_memory (jp->pc, buf, jp->length);
- if (err != 0)
- {
- jp->inserted = 1;
- threads_debug_printf ("Failed to uninsert fast tracepoint jump at"
- " 0x%s (%s).",
- paddress (pc), safe_strerror (err));
- }
- }
- }
- void
- reinsert_fast_tracepoint_jumps_at (CORE_ADDR where)
- {
- struct fast_tracepoint_jump *jp;
- int err;
- unsigned char *buf;
- jp = find_fast_tracepoint_jump_at (where);
- if (jp == NULL)
- {
- /* This can happen when we remove breakpoints when a tracepoint
- hit causes a tracing stop, while handling a step-over. */
- threads_debug_printf ("Could not find fast tracepoint jump at 0x%s "
- "in list (reinserting).",
- paddress (where));
- return;
- }
- if (jp->inserted)
- error ("Jump already inserted at reinsert time.");
- jp->inserted = 1;
- /* Since there can be trap breakpoints inserted in the same address
- range, we use `target_write_memory', which takes care of
- layering breakpoints on top of fast tracepoints, and on top of
- the buffer we pass it. This works because we've already marked
- the fast tracepoint jump inserted above. Also note that we need
- to pass the current shadow contents, because
- target_write_memory updates any shadow memory with what we pass
- here, and we want that to be a nop. */
- buf = (unsigned char *) alloca (jp->length);
- memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length);
- err = target_write_memory (where, buf, jp->length);
- if (err != 0)
- {
- jp->inserted = 0;
- threads_debug_printf ("Failed to reinsert fast tracepoint jump at"
- " 0x%s (%s).",
- paddress (where), safe_strerror (err));
- }
- }
- /* Set a high-level breakpoint of type TYPE, with low level type
- RAW_TYPE and kind KIND, at WHERE. On success, a pointer to the new
- breakpoint is returned. On failure, returns NULL and writes the
- error code to *ERR. HANDLER is called when the breakpoint is hit.
- HANDLER should return 1 if the breakpoint should be deleted, 0
- otherwise. */
- static struct breakpoint *
- set_breakpoint (enum bkpt_type type, enum raw_bkpt_type raw_type,
- CORE_ADDR where, int kind,
- int (*handler) (CORE_ADDR), int *err)
- {
- struct process_info *proc = current_process ();
- struct breakpoint *bp;
- struct raw_breakpoint *raw;
- raw = set_raw_breakpoint_at (raw_type, where, kind, err);
- if (raw == NULL)
- {
- /* warn? */
- return NULL;
- }
- if (is_gdb_breakpoint (type))
- {
- struct gdb_breakpoint *gdb_bp = XCNEW (struct gdb_breakpoint);
- bp = (struct breakpoint *) gdb_bp;
- gdb_assert (handler == NULL);
- }
- else if (type == other_breakpoint)
- {
- struct other_breakpoint *other_bp = XCNEW (struct other_breakpoint);
- other_bp->handler = handler;
- bp = (struct breakpoint *) other_bp;
- }
- else if (type == single_step_breakpoint)
- {
- struct single_step_breakpoint *ss_bp
- = XCNEW (struct single_step_breakpoint);
- bp = (struct breakpoint *) ss_bp;
- }
- else
- gdb_assert_not_reached ("unhandled breakpoint type");
- bp->type = type;
- bp->raw = raw;
- bp->next = proc->breakpoints;
- proc->breakpoints = bp;
- return bp;
- }
- /* Set breakpoint of TYPE on address WHERE with handler HANDLER. */
- static struct breakpoint *
- set_breakpoint_type_at (enum bkpt_type type, CORE_ADDR where,
- int (*handler) (CORE_ADDR))
- {
- int err_ignored;
- CORE_ADDR placed_address = where;
- int breakpoint_kind = target_breakpoint_kind_from_pc (&placed_address);
- return set_breakpoint (type, raw_bkpt_type_sw,
- placed_address, breakpoint_kind, handler,
- &err_ignored);
- }
- /* See mem-break.h */
- struct breakpoint *
- set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
- {
- return set_breakpoint_type_at (other_breakpoint, where, handler);
- }
- static int
- delete_raw_breakpoint (struct process_info *proc, struct raw_breakpoint *todel)
- {
- struct raw_breakpoint *bp, **bp_link;
- int ret;
- bp = proc->raw_breakpoints;
- bp_link = &proc->raw_breakpoints;
- while (bp)
- {
- if (bp == todel)
- {
- if (bp->inserted > 0)
- {
- struct raw_breakpoint *prev_bp_link = *bp_link;
- *bp_link = bp->next;
- ret = the_target->remove_point (bp->raw_type, bp->pc,
- bp->kind, bp);
- if (ret != 0)
- {
- /* Something went wrong, relink the breakpoint. */
- *bp_link = prev_bp_link;
- threads_debug_printf ("Failed to uninsert raw breakpoint "
- "at 0x%s while deleting it.",
- paddress (bp->pc));
- return ret;
- }
- }
- else
- *bp_link = bp->next;
- free (bp);
- return 0;
- }
- else
- {
- bp_link = &bp->next;
- bp = *bp_link;
- }
- }
- warning ("Could not find raw breakpoint in list.");
- return ENOENT;
- }
- static int
- release_breakpoint (struct process_info *proc, struct breakpoint *bp)
- {
- int newrefcount;
- int ret;
- newrefcount = bp->raw->refcount - 1;
- if (newrefcount == 0)
- {
- ret = delete_raw_breakpoint (proc, bp->raw);
- if (ret != 0)
- return ret;
- }
- else
- bp->raw->refcount = newrefcount;
- free (bp);
- return 0;
- }
- static int
- delete_breakpoint_1 (struct process_info *proc, struct breakpoint *todel)
- {
- struct breakpoint *bp, **bp_link;
- int err;
- bp = proc->breakpoints;
- bp_link = &proc->breakpoints;
- while (bp)
- {
- if (bp == todel)
- {
- *bp_link = bp->next;
- err = release_breakpoint (proc, bp);
- if (err != 0)
- return err;
- bp = *bp_link;
- return 0;
- }
- else
- {
- bp_link = &bp->next;
- bp = *bp_link;
- }
- }
- warning ("Could not find breakpoint in list.");
- return ENOENT;
- }
- int
- delete_breakpoint (struct breakpoint *todel)
- {
- struct process_info *proc = current_process ();
- return delete_breakpoint_1 (proc, todel);
- }
- /* Locate a GDB breakpoint of type Z_TYPE and kind KIND placed at
- address ADDR and return a pointer to its structure. If KIND is -1,
- the breakpoint's kind is ignored. */
- static struct gdb_breakpoint *
- find_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind)
- {
- struct process_info *proc = current_process ();
- struct breakpoint *bp;
- enum bkpt_type type = Z_packet_to_bkpt_type (z_type);
- for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
- if (bp->type == type && bp->raw->pc == addr
- && (kind == -1 || bp->raw->kind == kind))
- return (struct gdb_breakpoint *) bp;
- return NULL;
- }
- static int
- z_type_supported (char z_type)
- {
- return (z_type >= '0' && z_type <= '4'
- && the_target->supports_z_point_type (z_type));
- }
- /* Create a new GDB breakpoint of type Z_TYPE at ADDR with kind KIND.
- Returns a pointer to the newly created breakpoint on success. On
- failure returns NULL and sets *ERR to either -1 for error, or 1 if
- Z_TYPE breakpoints are not supported on this target. */
- static struct gdb_breakpoint *
- set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind, int *err)
- {
- struct gdb_breakpoint *bp;
- enum bkpt_type type;
- enum raw_bkpt_type raw_type;
- /* If we see GDB inserting a second code breakpoint at the same
- address, then either: GDB is updating the breakpoint's conditions
- or commands; or, the first breakpoint must have disappeared due
- to a shared library unload. On targets where the shared
- libraries are handled by userspace, like SVR4, for example,
- GDBserver can't tell if a library was loaded or unloaded. Since
- we refcount raw breakpoints, we must be careful to make sure GDB
- breakpoints never contribute more than one reference. if we
- didn't do this, in case the previous breakpoint is gone due to a
- shared library unload, we'd just increase the refcount of the
- previous breakpoint at this address, but the trap was not planted
- in the inferior anymore, thus the breakpoint would never be hit.
- Note this must be careful to not create a window where
- breakpoints are removed from the target, for non-stop, in case
- the target can poke at memory while the program is running. */
- if (z_type == Z_PACKET_SW_BP
- || z_type == Z_PACKET_HW_BP)
- {
- bp = find_gdb_breakpoint (z_type, addr, -1);
- if (bp != NULL)
- {
- if (bp->base.raw->kind != kind)
- {
- /* A different kind than previously seen. The previous
- breakpoint must be gone then. */
- bp->base.raw->inserted = -1;
- delete_breakpoint ((struct breakpoint *) bp);
- bp = NULL;
- }
- else if (z_type == Z_PACKET_SW_BP)
- {
- /* Check if the breakpoint is actually gone from the
- target, due to an solib unload, for example. Might
- as well validate _all_ breakpoints. */
- validate_breakpoints ();
- /* Breakpoints that don't pass validation are
- deleted. */
- bp = find_gdb_breakpoint (z_type, addr, -1);
- }
- }
- }
- else
- {
- /* Data breakpoints for the same address but different kind are
- expected. GDB doesn't merge these. The backend gets to do
- that if it wants/can. */
- bp = find_gdb_breakpoint (z_type, addr, kind);
- }
- if (bp != NULL)
- {
- /* We already know about this breakpoint, there's nothing else
- to do - GDB's reference is already accounted for. Note that
- whether the breakpoint inserted is left as is - we may be
- stepping over it, for example, in which case we don't want to
- force-reinsert it. */
- return bp;
- }
- raw_type = Z_packet_to_raw_bkpt_type (z_type);
- type = Z_packet_to_bkpt_type (z_type);
- return (struct gdb_breakpoint *) set_breakpoint (type, raw_type, addr,
- kind, NULL, err);
- }
- static int
- check_gdb_bp_preconditions (char z_type, int *err)
- {
- /* As software/memory breakpoints work by poking at memory, we need
- to prepare to access memory. If that operation fails, we need to
- return error. Seeing an error, if this is the first breakpoint
- of that type that GDB tries to insert, GDB would then assume the
- breakpoint type is supported, but it may actually not be. So we
- need to check whether the type is supported at all before
- preparing to access memory. */
- if (!z_type_supported (z_type))
- {
- *err = 1;
- return 0;
- }
- return 1;
- }
- /* See mem-break.h. This is a wrapper for set_gdb_breakpoint_1 that
- knows to prepare to access memory for Z0 breakpoints. */
- struct gdb_breakpoint *
- set_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind, int *err)
- {
- struct gdb_breakpoint *bp;
- if (!check_gdb_bp_preconditions (z_type, err))
- return NULL;
- /* If inserting a software/memory breakpoint, need to prepare to
- access memory. */
- if (z_type == Z_PACKET_SW_BP)
- {
- if (prepare_to_access_memory () != 0)
- {
- *err = -1;
- return NULL;
- }
- }
- bp = set_gdb_breakpoint_1 (z_type, addr, kind, err);
- if (z_type == Z_PACKET_SW_BP)
- done_accessing_memory ();
- return bp;
- }
- /* Delete a GDB breakpoint of type Z_TYPE and kind KIND previously
- inserted at ADDR with set_gdb_breakpoint_at. Returns 0 on success,
- -1 on error, and 1 if Z_TYPE breakpoints are not supported on this
- target. */
- static int
- delete_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind)
- {
- struct gdb_breakpoint *bp;
- int err;
- bp = find_gdb_breakpoint (z_type, addr, kind);
- if (bp == NULL)
- return -1;
- /* Before deleting the breakpoint, make sure to free its condition
- and command lists. */
- clear_breakpoint_conditions_and_commands (bp);
- err = delete_breakpoint ((struct breakpoint *) bp);
- if (err != 0)
- return -1;
- return 0;
- }
- /* See mem-break.h. This is a wrapper for delete_gdb_breakpoint that
- knows to prepare to access memory for Z0 breakpoints. */
- int
- delete_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind)
- {
- int ret;
- if (!check_gdb_bp_preconditions (z_type, &ret))
- return ret;
- /* If inserting a software/memory breakpoint, need to prepare to
- access memory. */
- if (z_type == Z_PACKET_SW_BP)
- {
- int err;
- err = prepare_to_access_memory ();
- if (err != 0)
- return -1;
- }
- ret = delete_gdb_breakpoint_1 (z_type, addr, kind);
- if (z_type == Z_PACKET_SW_BP)
- done_accessing_memory ();
- return ret;
- }
- /* Clear all conditions associated with a breakpoint. */
- static void
- clear_breakpoint_conditions (struct gdb_breakpoint *bp)
- {
- struct point_cond_list *cond;
- if (bp->cond_list == NULL)
- return;
- cond = bp->cond_list;
- while (cond != NULL)
- {
- struct point_cond_list *cond_next;
- cond_next = cond->next;
- gdb_free_agent_expr (cond->cond);
- free (cond);
- cond = cond_next;
- }
- bp->cond_list = NULL;
- }
- /* Clear all commands associated with a breakpoint. */
- static void
- clear_breakpoint_commands (struct gdb_breakpoint *bp)
- {
- struct point_command_list *cmd;
- if (bp->command_list == NULL)
- return;
- cmd = bp->command_list;
- while (cmd != NULL)
- {
- struct point_command_list *cmd_next;
- cmd_next = cmd->next;
- gdb_free_agent_expr (cmd->cmd);
- free (cmd);
- cmd = cmd_next;
- }
- bp->command_list = NULL;
- }
- void
- clear_breakpoint_conditions_and_commands (struct gdb_breakpoint *bp)
- {
- clear_breakpoint_conditions (bp);
- clear_breakpoint_commands (bp);
- }
- /* Add condition CONDITION to GDBserver's breakpoint BP. */
- static void
- add_condition_to_breakpoint (struct gdb_breakpoint *bp,
- struct agent_expr *condition)
- {
- struct point_cond_list *new_cond;
- /* Create new condition. */
- new_cond = XCNEW (struct point_cond_list);
- new_cond->cond = condition;
- /* Add condition to the list. */
- new_cond->next = bp->cond_list;
- bp->cond_list = new_cond;
- }
- /* Add a target-side condition CONDITION to a breakpoint. */
- int
- add_breakpoint_condition (struct gdb_breakpoint *bp, const char **condition)
- {
- const char *actparm = *condition;
- struct agent_expr *cond;
- if (condition == NULL)
- return 1;
- if (bp == NULL)
- return 0;
- cond = gdb_parse_agent_expr (&actparm);
- if (cond == NULL)
- {
- warning ("Condition evaluation failed. Assuming unconditional.");
- return 0;
- }
- add_condition_to_breakpoint (bp, cond);
- *condition = actparm;
- return 1;
- }
- /* Evaluate condition (if any) at breakpoint BP. Return 1 if
- true and 0 otherwise. */
- static int
- gdb_condition_true_at_breakpoint_z_type (char z_type, CORE_ADDR addr)
- {
- /* Fetch registers for the current inferior. */
- struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
- ULONGEST value = 0;
- struct point_cond_list *cl;
- int err = 0;
- struct eval_agent_expr_context ctx;
- if (bp == NULL)
- return 0;
- /* Check if the breakpoint is unconditional. If it is,
- the condition always evaluates to TRUE. */
- if (bp->cond_list == NULL)
- return 1;
- ctx.regcache = get_thread_regcache (current_thread, 1);
- ctx.tframe = NULL;
- ctx.tpoint = NULL;
- /* Evaluate each condition in the breakpoint's list of conditions.
- Return true if any of the conditions evaluates to TRUE.
- If we failed to evaluate the expression, TRUE is returned. This
- forces GDB to reevaluate the conditions. */
- for (cl = bp->cond_list;
- cl && !value && !err; cl = cl->next)
- {
- /* Evaluate the condition. */
- err = gdb_eval_agent_expr (&ctx, cl->cond, &value);
- }
- if (err)
- return 1;
- return (value != 0);
- }
- int
- gdb_condition_true_at_breakpoint (CORE_ADDR where)
- {
- /* Only check code (software or hardware) breakpoints. */
- return (gdb_condition_true_at_breakpoint_z_type (Z_PACKET_SW_BP, where)
- || gdb_condition_true_at_breakpoint_z_type (Z_PACKET_HW_BP, where));
- }
- /* Add commands COMMANDS to GDBserver's breakpoint BP. */
- static void
- add_commands_to_breakpoint (struct gdb_breakpoint *bp,
- struct agent_expr *commands, int persist)
- {
- struct point_command_list *new_cmd;
- /* Create new command. */
- new_cmd = XCNEW (struct point_command_list);
- new_cmd->cmd = commands;
- new_cmd->persistence = persist;
- /* Add commands to the list. */
- new_cmd->next = bp->command_list;
- bp->command_list = new_cmd;
- }
- /* Add a target-side command COMMAND to the breakpoint at ADDR. */
- int
- add_breakpoint_commands (struct gdb_breakpoint *bp, const char **command,
- int persist)
- {
- const char *actparm = *command;
- struct agent_expr *cmd;
- if (command == NULL)
- return 1;
- if (bp == NULL)
- return 0;
- cmd = gdb_parse_agent_expr (&actparm);
- if (cmd == NULL)
- {
- warning ("Command evaluation failed. Disabling.");
- return 0;
- }
- add_commands_to_breakpoint (bp, cmd, persist);
- *command = actparm;
- return 1;
- }
- /* Return true if there are no commands to run at this location,
- which likely means we want to report back to GDB. */
- static int
- gdb_no_commands_at_breakpoint_z_type (char z_type, CORE_ADDR addr)
- {
- struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
- if (bp == NULL)
- return 1;
- threads_debug_printf ("at 0x%s, type Z%c, bp command_list is 0x%s",
- paddress (addr), z_type,
- phex_nz ((uintptr_t) bp->command_list, 0));
- return (bp->command_list == NULL);
- }
- /* Return true if there are no commands to run at this location,
- which likely means we want to report back to GDB. */
- int
- gdb_no_commands_at_breakpoint (CORE_ADDR where)
- {
- /* Only check code (software or hardware) breakpoints. */
- return (gdb_no_commands_at_breakpoint_z_type (Z_PACKET_SW_BP, where)
- && gdb_no_commands_at_breakpoint_z_type (Z_PACKET_HW_BP, where));
- }
- /* Run a breakpoint's commands. Returns 0 if there was a problem
- running any command, 1 otherwise. */
- static int
- run_breakpoint_commands_z_type (char z_type, CORE_ADDR addr)
- {
- /* Fetch registers for the current inferior. */
- struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
- ULONGEST value = 0;
- struct point_command_list *cl;
- int err = 0;
- struct eval_agent_expr_context ctx;
- if (bp == NULL)
- return 1;
- ctx.regcache = get_thread_regcache (current_thread, 1);
- ctx.tframe = NULL;
- ctx.tpoint = NULL;
- for (cl = bp->command_list;
- cl && !value && !err; cl = cl->next)
- {
- /* Run the command. */
- err = gdb_eval_agent_expr (&ctx, cl->cmd, &value);
- /* If one command has a problem, stop digging the hole deeper. */
- if (err)
- return 0;
- }
- return 1;
- }
- void
- run_breakpoint_commands (CORE_ADDR where)
- {
- /* Only check code (software or hardware) breakpoints. If one
- command has a problem, stop digging the hole deeper. */
- if (run_breakpoint_commands_z_type (Z_PACKET_SW_BP, where))
- run_breakpoint_commands_z_type (Z_PACKET_HW_BP, where);
- }
- /* See mem-break.h. */
- int
- gdb_breakpoint_here (CORE_ADDR where)
- {
- /* Only check code (software or hardware) breakpoints. */
- return (find_gdb_breakpoint (Z_PACKET_SW_BP, where, -1) != NULL
- || find_gdb_breakpoint (Z_PACKET_HW_BP, where, -1) != NULL);
- }
- void
- set_single_step_breakpoint (CORE_ADDR stop_at, ptid_t ptid)
- {
- struct single_step_breakpoint *bp;
- gdb_assert (current_ptid.pid () == ptid.pid ());
- bp = (struct single_step_breakpoint *) set_breakpoint_type_at (single_step_breakpoint,
- stop_at, NULL);
- bp->ptid = ptid;
- }
- void
- delete_single_step_breakpoints (struct thread_info *thread)
- {
- struct process_info *proc = get_thread_process (thread);
- struct breakpoint *bp, **bp_link;
- bp = proc->breakpoints;
- bp_link = &proc->breakpoints;
- while (bp)
- {
- if (bp->type == single_step_breakpoint
- && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread))
- {
- scoped_restore_current_thread restore_thread;
- switch_to_thread (thread);
- *bp_link = bp->next;
- release_breakpoint (proc, bp);
- bp = *bp_link;
- }
- else
- {
- bp_link = &bp->next;
- bp = *bp_link;
- }
- }
- }
- static void
- uninsert_raw_breakpoint (struct raw_breakpoint *bp)
- {
- if (bp->inserted < 0)
- {
- threads_debug_printf ("Breakpoint at %s is marked insert-disabled.",
- paddress (bp->pc));
- }
- else if (bp->inserted > 0)
- {
- int err;
- bp->inserted = 0;
- err = the_target->remove_point (bp->raw_type, bp->pc, bp->kind, bp);
- if (err != 0)
- {
- bp->inserted = 1;
- threads_debug_printf ("Failed to uninsert raw breakpoint at 0x%s.",
- paddress (bp->pc));
- }
- }
- }
- void
- uninsert_breakpoints_at (CORE_ADDR pc)
- {
- struct process_info *proc = current_process ();
- struct raw_breakpoint *bp;
- int found = 0;
- for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
- if ((bp->raw_type == raw_bkpt_type_sw
- || bp->raw_type == raw_bkpt_type_hw)
- && bp->pc == pc)
- {
- found = 1;
- if (bp->inserted)
- uninsert_raw_breakpoint (bp);
- }
- if (!found)
- {
- /* This can happen when we remove all breakpoints while handling
- a step-over. */
- threads_debug_printf ("Could not find breakpoint at 0x%s "
- "in list (uninserting).",
- paddress (pc));
- }
- }
- void
- uninsert_all_breakpoints (void)
- {
- struct process_info *proc = current_process ();
- struct raw_breakpoint *bp;
- for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
- if ((bp->raw_type == raw_bkpt_type_sw
- || bp->raw_type == raw_bkpt_type_hw)
- && bp->inserted)
- uninsert_raw_breakpoint (bp);
- }
- void
- uninsert_single_step_breakpoints (struct thread_info *thread)
- {
- struct process_info *proc = get_thread_process (thread);
- struct breakpoint *bp;
- for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
- {
- if (bp->type == single_step_breakpoint
- && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread))
- {
- gdb_assert (bp->raw->inserted > 0);
- /* Only uninsert the raw breakpoint if it only belongs to a
- reinsert breakpoint. */
- if (bp->raw->refcount == 1)
- {
- scoped_restore_current_thread restore_thread;
- switch_to_thread (thread);
- uninsert_raw_breakpoint (bp->raw);
- }
- }
- }
- }
- static void
- reinsert_raw_breakpoint (struct raw_breakpoint *bp)
- {
- int err;
- if (bp->inserted)
- return;
- err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp);
- if (err == 0)
- bp->inserted = 1;
- else
- threads_debug_printf ("Failed to reinsert breakpoint at 0x%s (%d).",
- paddress (bp->pc), err);
- }
- void
- reinsert_breakpoints_at (CORE_ADDR pc)
- {
- struct process_info *proc = current_process ();
- struct raw_breakpoint *bp;
- int found = 0;
- for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
- if ((bp->raw_type == raw_bkpt_type_sw
- || bp->raw_type == raw_bkpt_type_hw)
- && bp->pc == pc)
- {
- found = 1;
- reinsert_raw_breakpoint (bp);
- }
- if (!found)
- {
- /* This can happen when we remove all breakpoints while handling
- a step-over. */
- threads_debug_printf ("Could not find raw breakpoint at 0x%s "
- "in list (reinserting).",
- paddress (pc));
- }
- }
- int
- has_single_step_breakpoints (struct thread_info *thread)
- {
- struct process_info *proc = get_thread_process (thread);
- struct breakpoint *bp, **bp_link;
- bp = proc->breakpoints;
- bp_link = &proc->breakpoints;
- while (bp)
- {
- if (bp->type == single_step_breakpoint
- && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread))
- return 1;
- else
- {
- bp_link = &bp->next;
- bp = *bp_link;
- }
- }
- return 0;
- }
- void
- reinsert_all_breakpoints (void)
- {
- struct process_info *proc = current_process ();
- struct raw_breakpoint *bp;
- for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
- if ((bp->raw_type == raw_bkpt_type_sw
- || bp->raw_type == raw_bkpt_type_hw)
- && !bp->inserted)
- reinsert_raw_breakpoint (bp);
- }
- void
- reinsert_single_step_breakpoints (struct thread_info *thread)
- {
- struct process_info *proc = get_thread_process (thread);
- struct breakpoint *bp;
- for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
- {
- if (bp->type == single_step_breakpoint
- && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread))
- {
- gdb_assert (bp->raw->inserted > 0);
- if (bp->raw->refcount == 1)
- {
- scoped_restore_current_thread restore_thread;
- switch_to_thread (thread);
- reinsert_raw_breakpoint (bp->raw);
- }
- }
- }
- }
- void
- check_breakpoints (CORE_ADDR stop_pc)
- {
- struct process_info *proc = current_process ();
- struct breakpoint *bp, **bp_link;
- bp = proc->breakpoints;
- bp_link = &proc->breakpoints;
- while (bp)
- {
- struct raw_breakpoint *raw = bp->raw;
- if ((raw->raw_type == raw_bkpt_type_sw
- || raw->raw_type == raw_bkpt_type_hw)
- && raw->pc == stop_pc)
- {
- if (!raw->inserted)
- {
- warning ("Hit a removed breakpoint?");
- return;
- }
- if (bp->type == other_breakpoint)
- {
- struct other_breakpoint *other_bp
- = (struct other_breakpoint *) bp;
- if (other_bp->handler != NULL && (*other_bp->handler) (stop_pc))
- {
- *bp_link = bp->next;
- release_breakpoint (proc, bp);
- bp = *bp_link;
- continue;
- }
- }
- }
- bp_link = &bp->next;
- bp = *bp_link;
- }
- }
- int
- breakpoint_here (CORE_ADDR addr)
- {
- struct process_info *proc = current_process ();
- struct raw_breakpoint *bp;
- for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
- if ((bp->raw_type == raw_bkpt_type_sw
- || bp->raw_type == raw_bkpt_type_hw)
- && bp->pc == addr)
- return 1;
- return 0;
- }
- int
- breakpoint_inserted_here (CORE_ADDR addr)
- {
- struct process_info *proc = current_process ();
- struct raw_breakpoint *bp;
- for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
- if ((bp->raw_type == raw_bkpt_type_sw
- || bp->raw_type == raw_bkpt_type_hw)
- && bp->pc == addr
- && bp->inserted)
- return 1;
- return 0;
- }
- /* See mem-break.h. */
- int
- software_breakpoint_inserted_here (CORE_ADDR addr)
- {
- struct process_info *proc = current_process ();
- struct raw_breakpoint *bp;
- for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
- if (bp->raw_type == raw_bkpt_type_sw
- && bp->pc == addr
- && bp->inserted)
- return 1;
- return 0;
- }
- /* See mem-break.h. */
- int
- hardware_breakpoint_inserted_here (CORE_ADDR addr)
- {
- struct process_info *proc = current_process ();
- struct raw_breakpoint *bp;
- for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
- if (bp->raw_type == raw_bkpt_type_hw
- && bp->pc == addr
- && bp->inserted)
- return 1;
- return 0;
- }
- /* See mem-break.h. */
- int
- single_step_breakpoint_inserted_here (CORE_ADDR addr)
- {
- struct process_info *proc = current_process ();
- struct breakpoint *bp;
- for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
- if (bp->type == single_step_breakpoint
- && bp->raw->pc == addr
- && bp->raw->inserted)
- return 1;
- return 0;
- }
- static int
- validate_inserted_breakpoint (struct raw_breakpoint *bp)
- {
- unsigned char *buf;
- int err;
- gdb_assert (bp->inserted);
- gdb_assert (bp->raw_type == raw_bkpt_type_sw);
- buf = (unsigned char *) alloca (bp_size (bp));
- err = the_target->read_memory (bp->pc, buf, bp_size (bp));
- if (err || memcmp (buf, bp_opcode (bp), bp_size (bp)) != 0)
- {
- /* Tag it as gone. */
- bp->inserted = -1;
- return 0;
- }
- return 1;
- }
- static void
- delete_disabled_breakpoints (void)
- {
- struct process_info *proc = current_process ();
- struct breakpoint *bp, *next;
- for (bp = proc->breakpoints; bp != NULL; bp = next)
- {
- next = bp->next;
- if (bp->raw->inserted < 0)
- {
- /* If single_step_breakpoints become disabled, that means the
- manipulations (insertion and removal) of them are wrong. */
- gdb_assert (bp->type != single_step_breakpoint);
- delete_breakpoint_1 (proc, bp);
- }
- }
- }
- /* Check if breakpoints we inserted still appear to be inserted. They
- may disappear due to a shared library unload, and worse, a new
- shared library may be reloaded at the same address as the
- previously unloaded one. If that happens, we should make sure that
- the shadow memory of the old breakpoints isn't used when reading or
- writing memory. */
- void
- validate_breakpoints (void)
- {
- struct process_info *proc = current_process ();
- struct breakpoint *bp;
- for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
- {
- struct raw_breakpoint *raw = bp->raw;
- if (raw->raw_type == raw_bkpt_type_sw && raw->inserted > 0)
- validate_inserted_breakpoint (raw);
- }
- delete_disabled_breakpoints ();
- }
- void
- check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
- {
- struct process_info *proc = current_process ();
- struct raw_breakpoint *bp = proc->raw_breakpoints;
- struct fast_tracepoint_jump *jp = proc->fast_tracepoint_jumps;
- CORE_ADDR mem_end = mem_addr + mem_len;
- int disabled_one = 0;
- for (; jp != NULL; jp = jp->next)
- {
- CORE_ADDR bp_end = jp->pc + jp->length;
- CORE_ADDR start, end;
- int copy_offset, copy_len, buf_offset;
- gdb_assert (fast_tracepoint_jump_shadow (jp) >= buf + mem_len
- || buf >= fast_tracepoint_jump_shadow (jp) + (jp)->length);
- if (mem_addr >= bp_end)
- continue;
- if (jp->pc >= mem_end)
- continue;
- start = jp->pc;
- if (mem_addr > start)
- start = mem_addr;
- end = bp_end;
- if (end > mem_end)
- end = mem_end;
- copy_len = end - start;
- copy_offset = start - jp->pc;
- buf_offset = start - mem_addr;
- if (jp->inserted)
- memcpy (buf + buf_offset,
- fast_tracepoint_jump_shadow (jp) + copy_offset,
- copy_len);
- }
- for (; bp != NULL; bp = bp->next)
- {
- CORE_ADDR bp_end = bp->pc + bp_size (bp);
- CORE_ADDR start, end;
- int copy_offset, copy_len, buf_offset;
- if (bp->raw_type != raw_bkpt_type_sw)
- continue;
- gdb_assert (bp->old_data >= buf + mem_len
- || buf >= &bp->old_data[sizeof (bp->old_data)]);
- if (mem_addr >= bp_end)
- continue;
- if (bp->pc >= mem_end)
- continue;
- start = bp->pc;
- if (mem_addr > start)
- start = mem_addr;
- end = bp_end;
- if (end > mem_end)
- end = mem_end;
- copy_len = end - start;
- copy_offset = start - bp->pc;
- buf_offset = start - mem_addr;
- if (bp->inserted > 0)
- {
- if (validate_inserted_breakpoint (bp))
- memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
- else
- disabled_one = 1;
- }
- }
- if (disabled_one)
- delete_disabled_breakpoints ();
- }
- void
- check_mem_write (CORE_ADDR mem_addr, unsigned char *buf,
- const unsigned char *myaddr, int mem_len)
- {
- struct process_info *proc = current_process ();
- struct raw_breakpoint *bp = proc->raw_breakpoints;
- struct fast_tracepoint_jump *jp = proc->fast_tracepoint_jumps;
- CORE_ADDR mem_end = mem_addr + mem_len;
- int disabled_one = 0;
- /* First fast tracepoint jumps, then breakpoint traps on top. */
- for (; jp != NULL; jp = jp->next)
- {
- CORE_ADDR jp_end = jp->pc + jp->length;
- CORE_ADDR start, end;
- int copy_offset, copy_len, buf_offset;
- gdb_assert (fast_tracepoint_jump_shadow (jp) >= myaddr + mem_len
- || myaddr >= fast_tracepoint_jump_shadow (jp) + (jp)->length);
- gdb_assert (fast_tracepoint_jump_insn (jp) >= buf + mem_len
- || buf >= fast_tracepoint_jump_insn (jp) + (jp)->length);
- if (mem_addr >= jp_end)
- continue;
- if (jp->pc >= mem_end)
- continue;
- start = jp->pc;
- if (mem_addr > start)
- start = mem_addr;
- end = jp_end;
- if (end > mem_end)
- end = mem_end;
- copy_len = end - start;
- copy_offset = start - jp->pc;
- buf_offset = start - mem_addr;
- memcpy (fast_tracepoint_jump_shadow (jp) + copy_offset,
- myaddr + buf_offset, copy_len);
- if (jp->inserted)
- memcpy (buf + buf_offset,
- fast_tracepoint_jump_insn (jp) + copy_offset, copy_len);
- }
- for (; bp != NULL; bp = bp->next)
- {
- CORE_ADDR bp_end = bp->pc + bp_size (bp);
- CORE_ADDR start, end;
- int copy_offset, copy_len, buf_offset;
- if (bp->raw_type != raw_bkpt_type_sw)
- continue;
- gdb_assert (bp->old_data >= myaddr + mem_len
- || myaddr >= &bp->old_data[sizeof (bp->old_data)]);
- if (mem_addr >= bp_end)
- continue;
- if (bp->pc >= mem_end)
- continue;
- start = bp->pc;
- if (mem_addr > start)
- start = mem_addr;
- end = bp_end;
- if (end > mem_end)
- end = mem_end;
- copy_len = end - start;
- copy_offset = start - bp->pc;
- buf_offset = start - mem_addr;
- memcpy (bp->old_data + copy_offset, myaddr + buf_offset, copy_len);
- if (bp->inserted > 0)
- {
- if (validate_inserted_breakpoint (bp))
- memcpy (buf + buf_offset, bp_opcode (bp) + copy_offset, copy_len);
- else
- disabled_one = 1;
- }
- }
- if (disabled_one)
- delete_disabled_breakpoints ();
- }
- /* Delete all breakpoints, and un-insert them from the inferior. */
- void
- delete_all_breakpoints (void)
- {
- struct process_info *proc = current_process ();
- while (proc->breakpoints)
- delete_breakpoint_1 (proc, proc->breakpoints);
- }
- /* Clear the "inserted" flag in all breakpoints. */
- void
- mark_breakpoints_out (struct process_info *proc)
- {
- struct raw_breakpoint *raw_bp;
- for (raw_bp = proc->raw_breakpoints; raw_bp != NULL; raw_bp = raw_bp->next)
- raw_bp->inserted = 0;
- }
- /* Release all breakpoints, but do not try to un-insert them from the
- inferior. */
- void
- free_all_breakpoints (struct process_info *proc)
- {
- mark_breakpoints_out (proc);
- /* Note: use PROC explicitly instead of deferring to
- delete_all_breakpoints --- CURRENT_INFERIOR may already have been
- released when we get here. There should be no call to
- current_process from here on. */
- while (proc->breakpoints)
- delete_breakpoint_1 (proc, proc->breakpoints);
- }
- /* Clone an agent expression. */
- static struct agent_expr *
- clone_agent_expr (const struct agent_expr *src_ax)
- {
- struct agent_expr *ax;
- ax = XCNEW (struct agent_expr);
- ax->length = src_ax->length;
- ax->bytes = (unsigned char *) xcalloc (ax->length, 1);
- memcpy (ax->bytes, src_ax->bytes, ax->length);
- return ax;
- }
- /* Deep-copy the contents of one breakpoint to another. */
- static struct breakpoint *
- clone_one_breakpoint (const struct breakpoint *src, ptid_t ptid)
- {
- struct breakpoint *dest;
- struct raw_breakpoint *dest_raw;
- /* Clone the raw breakpoint. */
- dest_raw = XCNEW (struct raw_breakpoint);
- dest_raw->raw_type = src->raw->raw_type;
- dest_raw->refcount = src->raw->refcount;
- dest_raw->pc = src->raw->pc;
- dest_raw->kind = src->raw->kind;
- memcpy (dest_raw->old_data, src->raw->old_data, MAX_BREAKPOINT_LEN);
- dest_raw->inserted = src->raw->inserted;
- /* Clone the high-level breakpoint. */
- if (is_gdb_breakpoint (src->type))
- {
- struct gdb_breakpoint *gdb_dest = XCNEW (struct gdb_breakpoint);
- struct point_cond_list *current_cond;
- struct point_cond_list *new_cond;
- struct point_cond_list *cond_tail = NULL;
- struct point_command_list *current_cmd;
- struct point_command_list *new_cmd;
- struct point_command_list *cmd_tail = NULL;
- /* Clone the condition list. */
- for (current_cond = ((struct gdb_breakpoint *) src)->cond_list;
- current_cond != NULL;
- current_cond = current_cond->next)
- {
- new_cond = XCNEW (struct point_cond_list);
- new_cond->cond = clone_agent_expr (current_cond->cond);
- APPEND_TO_LIST (&gdb_dest->cond_list, new_cond, cond_tail);
- }
- /* Clone the command list. */
- for (current_cmd = ((struct gdb_breakpoint *) src)->command_list;
- current_cmd != NULL;
- current_cmd = current_cmd->next)
- {
- new_cmd = XCNEW (struct point_command_list);
- new_cmd->cmd = clone_agent_expr (current_cmd->cmd);
- new_cmd->persistence = current_cmd->persistence;
- APPEND_TO_LIST (&gdb_dest->command_list, new_cmd, cmd_tail);
- }
- dest = (struct breakpoint *) gdb_dest;
- }
- else if (src->type == other_breakpoint)
- {
- struct other_breakpoint *other_dest = XCNEW (struct other_breakpoint);
- other_dest->handler = ((struct other_breakpoint *) src)->handler;
- dest = (struct breakpoint *) other_dest;
- }
- else if (src->type == single_step_breakpoint)
- {
- struct single_step_breakpoint *ss_dest
- = XCNEW (struct single_step_breakpoint);
- dest = (struct breakpoint *) ss_dest;
- /* Since single-step breakpoint is thread specific, don't copy
- thread id from SRC, use ID instead. */
- ss_dest->ptid = ptid;
- }
- else
- gdb_assert_not_reached ("unhandled breakpoint type");
- dest->type = src->type;
- dest->raw = dest_raw;
- return dest;
- }
- /* See mem-break.h. */
- void
- clone_all_breakpoints (struct thread_info *child_thread,
- const struct thread_info *parent_thread)
- {
- const struct breakpoint *bp;
- struct breakpoint *new_bkpt;
- struct breakpoint *bkpt_tail = NULL;
- struct raw_breakpoint *raw_bkpt_tail = NULL;
- struct process_info *child_proc = get_thread_process (child_thread);
- struct process_info *parent_proc = get_thread_process (parent_thread);
- struct breakpoint **new_list = &child_proc->breakpoints;
- struct raw_breakpoint **new_raw_list = &child_proc->raw_breakpoints;
- for (bp = parent_proc->breakpoints; bp != NULL; bp = bp->next)
- {
- new_bkpt = clone_one_breakpoint (bp, ptid_of (child_thread));
- APPEND_TO_LIST (new_list, new_bkpt, bkpt_tail);
- APPEND_TO_LIST (new_raw_list, new_bkpt->raw, raw_bkpt_tail);
- }
- }
|