cregit-Linux how code gets into the kernel

Release 4.14 arch/powerpc/xmon/xmon.c

/*
 * Routines providing a simple monitor for use on the PowerMac.
 *
 * Copyright (C) 1996-2005 Paul Mackerras.
 * Copyright (C) 2001 PPC64 Team, IBM Corp
 * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
 *
 *      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
 *      2 of the License, or (at your option) any later version.
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/sched/signal.h>
#include <linux/smp.h>
#include <linux/mm.h>
#include <linux/reboot.h>
#include <linux/delay.h>
#include <linux/kallsyms.h>
#include <linux/kmsg_dump.h>
#include <linux/cpumask.h>
#include <linux/export.h>
#include <linux/sysrq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/bug.h>
#include <linux/nmi.h>
#include <linux/ctype.h>

#include <asm/debugfs.h>
#include <asm/ptrace.h>
#include <asm/smp.h>
#include <asm/string.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/xmon.h>
#include <asm/processor.h>
#include <asm/pgtable.h>
#include <asm/mmu.h>
#include <asm/mmu_context.h>
#include <asm/cputable.h>
#include <asm/rtas.h>
#include <asm/sstep.h>
#include <asm/irq_regs.h>
#include <asm/spu.h>
#include <asm/spu_priv1.h>
#include <asm/setjmp.h>
#include <asm/reg.h>
#include <asm/debug.h>
#include <asm/hw_breakpoint.h>
#include <asm/xive.h>
#include <asm/opal.h>
#include <asm/firmware.h>
#include <asm/code-patching.h>

#ifdef CONFIG_PPC64
#include <asm/hvcall.h>
#include <asm/paca.h>
#endif

#if defined(CONFIG_PPC_SPLPAR)
#include <asm/plpar_wrappers.h>
#else

static inline long plapr_set_ciabr(unsigned long ciabr) {return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anshuman Khandual14100.00%1100.00%
Total14100.00%1100.00%

; #endif #include "nonstdio.h" #include "dis-asm.h" #ifdef CONFIG_SMP static cpumask_t cpus_in_xmon = CPU_MASK_NONE; static unsigned long xmon_taken = 1; static int xmon_owner; static int xmon_gate; #else #define xmon_owner 0 #endif /* CONFIG_SMP */ static unsigned long in_xmon __read_mostly = 0; static int xmon_on = IS_ENABLED(CONFIG_XMON_DEFAULT); static unsigned long adrs; static int size = 1; #define MAX_DUMP (128 * 1024) static unsigned long ndump = 64; static unsigned long nidump = 16; static unsigned long ncsum = 4096; static int termch; static char tmpstr[128]; static int tracing_enabled; static long bus_error_jmp[JMP_BUF_LEN]; static int catch_memory_errors; static int catch_spr_faults; static long *xmon_fault_jmp[NR_CPUS]; /* Breakpoint stuff */ struct bpt { unsigned long address; unsigned int instr[2]; atomic_t ref_count; int enabled; unsigned long pad; }; /* Bits in bpt.enabled */ #define BP_CIABR 1 #define BP_TRAP 2 #define BP_DABR 4 #define NBPTS 256 static struct bpt bpts[NBPTS]; static struct bpt dabr; static struct bpt *iabr; static unsigned bpinstr = 0x7fe00008; /* trap */ #define BP_NUM(bp) ((bp) - bpts + 1) /* Prototypes */ static int cmds(struct pt_regs *); static int mread(unsigned long, void *, int); static int mwrite(unsigned long, void *, int); static int handle_fault(struct pt_regs *); static void byterev(unsigned char *, int); static void memex(void); static int bsesc(void); static void dump(void); static void prdump(unsigned long, long); static int ppc_inst_dump(unsigned long, long, int); static void dump_log_buf(void); #ifdef CONFIG_PPC_POWERNV static void dump_opal_msglog(void); #else
static inline void dump_opal_msglog(void) { printf("Machine is not running OPAL firmware.\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Donnellan14100.00%1100.00%
Total14100.00%1100.00%

#endif static void backtrace(struct pt_regs *); static void excprint(struct pt_regs *); static void prregs(struct pt_regs *); static void memops(int); static void memlocate(void); static void memzcan(void); static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned); int skipbl(void); int scanhex(unsigned long *valp); static void scannl(void); static int hexdigit(int); void getstring(char *, int); static void flush_input(void); static int inchar(void); static void take_input(char *); static int read_spr(int, unsigned long *); static void write_spr(int, unsigned long); static void super_regs(void); static void remove_bpts(void); static void insert_bpts(void); static void remove_cpu_bpts(void); static void insert_cpu_bpts(void); static struct bpt *at_breakpoint(unsigned long pc); static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp); static int do_step(struct pt_regs *); static void bpt_cmds(void); static void cacheflush(void); static int cpu_cmd(void); static void csum(void); static void bootcmds(void); static void proccall(void); static void show_tasks(void); void dump_segments(void); static void symbol_lookup(void); static void xmon_show_stack(unsigned long sp, unsigned long lr, unsigned long pc); static void xmon_print_symbol(unsigned long address, const char *mid, const char *after); static const char *getvecname(unsigned long vec); static int do_spu_cmd(void); #ifdef CONFIG_44x static void dump_tlb_44x(void); #endif #ifdef CONFIG_PPC_BOOK3E static void dump_tlb_book3e(void); #endif #ifdef CONFIG_PPC64 #define REG "%.16lx" #else #define REG "%.8lx" #endif #ifdef __LITTLE_ENDIAN__ #define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0]) #else #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) #endif static char *help_string = "\ Commands:\n\ b show breakpoints\n\ bd set data breakpoint\n\ bi set instruction breakpoint\n\ bc clear breakpoint\n" #ifdef CONFIG_SMP "\ c print cpus stopped in xmon\n\ c# try to switch to cpu number h (in hex)\n" #endif "\ C checksum\n\ d dump bytes\n\ d1 dump 1 byte values\n\ d2 dump 2 byte values\n\ d4 dump 4 byte values\n\ d8 dump 8 byte values\n\ di dump instructions\n\ df dump float values\n\ dd dump double values\n\ dl dump the kernel log buffer\n" #ifdef CONFIG_PPC_POWERNV "\ do dump the OPAL message log\n" #endif #ifdef CONFIG_PPC64 "\ dp[#] dump paca for current cpu, or cpu #\n\ dpa dump paca for all possible cpus\n" #endif "\ dr dump stream of raw bytes\n\ dt dump the tracing buffers (uses printk)\n\ dtc dump the tracing buffers for current CPU (uses printk)\n\ " #ifdef CONFIG_PPC_POWERNV " dx# dump xive on CPU #\n\ dxi# dump xive irq state #\n\ dxa dump xive on all CPUs\n" #endif " e print exception information\n\ f flush cache\n\ la lookup symbol+offset of specified address\n\ ls lookup address of specified symbol\n\ m examine/change memory\n\ mm move a block of memory\n\ ms set a block of memory\n\ md compare two blocks of memory\n\ ml locate a block of memory\n\ mz zero a block of memory\n\ mi show information about memory allocation\n\ p call a procedure\n\ P list processes/tasks\n\ r print registers\n\ s single step\n" #ifdef CONFIG_SPU_BASE " ss stop execution on all spus\n\ sr restore execution on stopped spus\n\ sf # dump spu fields for spu # (in hex)\n\ sd # dump spu local store for spu # (in hex)\n\ sdi # disassemble spu local store for spu # (in hex)\n" #endif " S print special registers\n\ Sa print all SPRs\n\ Sr # read SPR #\n\ Sw #v write v to SPR #\n\ t print backtrace\n\ x exit monitor and recover\n\ X exit monitor and don't recover\n" #if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E) " u dump segment table or SLB\n" #elif defined(CONFIG_PPC_STD_MMU_32) " u dump segment registers\n" #elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E) " u dump TLB\n" #endif " ? help\n" " # n limit output to n lines per page (for dp, dpa, dl)\n" " zr reboot\n\ zh halt\n" ; static struct pt_regs *xmon_regs;
static inline void sync(void) { asm volatile("sync; isync"); }

Contributors

PersonTokensPropCommitsCommitProp
Anton Blanchard1191.67%150.00%
Paul Mackerras18.33%150.00%
Total12100.00%2100.00%


static inline void store_inst(void *p) { asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p)); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras14100.00%1100.00%
Total14100.00%1100.00%


static inline void cflush(void *p) { asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p)); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras14100.00%1100.00%
Total14100.00%1100.00%


static inline void cinval(void *p) { asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p)); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras14100.00%1100.00%
Total14100.00%1100.00%

/** * write_ciabr() - write the CIABR SPR * @ciabr: The value to write. * * This function writes a value to the CIARB register either directly * through mtspr instruction if the kernel is in HV privilege mode or * call a hypervisor function to achieve the same in case the kernel * is in supervisor privilege mode. */
static void write_ciabr(unsigned long ciabr) { if (!cpu_has_feature(CPU_FTR_ARCH_207S)) return; if (cpu_has_feature(CPU_FTR_HVMODE)) { mtspr(SPRN_CIABR, ciabr); return; } plapr_set_ciabr(ciabr); }

Contributors

PersonTokensPropCommitsCommitProp
Anshuman Khandual41100.00%1100.00%
Total41100.00%1100.00%

/** * set_ciabr() - set the CIABR * @addr: The value to set. * * This function sets the correct privilege value into the the HW * breakpoint address before writing it up in the CIABR register. */
static void set_ciabr(unsigned long addr) { addr &= ~CIABR_PRIV; if (cpu_has_feature(CPU_FTR_HVMODE)) addr |= CIABR_PRIV_HYPER; else addr |= CIABR_PRIV_SUPER; write_ciabr(addr); }

Contributors

PersonTokensPropCommitsCommitProp
Anshuman Khandual36100.00%1100.00%
Total36100.00%1100.00%

/* * Disable surveillance (the service processor watchdog function) * while we are in xmon. * XXX we should re-enable it when we leave. :) */ #define SURVEILLANCE_TOKEN 9000
static inline void disable_surveillance(void) { #ifdef CONFIG_PPC_PSERIES /* Since this can't be a module, args should end up below 4GB. */ static struct rtas_args args; int token; /* * At this point we have got all the cpus we can into * xmon, so there is hopefully no other cpu calling RTAS * at the moment, even though we don't take rtas.lock. * If we did try to take rtas.lock there would be a * real possibility of deadlock. */ token = rtas_token("set-indicator"); if (token == RTAS_UNKNOWN_SERVICE) return; rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0); #endif /* CONFIG_PPC_PSERIES */ }

Contributors

PersonTokensPropCommitsCommitProp
Anton Blanchard2237.29%228.57%
Andrew Morton1627.12%228.57%
Michael Ellerman1322.03%114.29%
Benjamin Herrenschmidt58.47%114.29%
Laurent Dufour35.08%114.29%
Total59100.00%7100.00%

#ifdef CONFIG_SMP static int xmon_speaker;
static void get_output_lock(void) { int me = smp_processor_id() + 0x100; int last_speaker = 0, prev; long timeout; if (xmon_speaker == me) return; for (;;) { last_speaker = cmpxchg(&xmon_speaker, 0, me); if (last_speaker == 0) return; /* * Wait a full second for the lock, we might be on a slow * console, but check every 100us. */ timeout = 10000; while (xmon_speaker == last_speaker) { if (--timeout > 0) { udelay(100); continue; } /* hostile takeover */ prev = cmpxchg(&xmon_speaker, last_speaker, me); if (prev == last_speaker) return; break; } } }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton8074.07%250.00%
Anton Blanchard1917.59%125.00%
Michael Ellerman98.33%125.00%
Total108100.00%4100.00%


static void release_output_lock(void) { xmon_speaker = 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton866.67%150.00%
Anton Blanchard433.33%150.00%
Total12100.00%2100.00%


int cpus_are_in_xmon(void) { return !cpumask_empty(&cpus_in_xmon); }

Contributors

PersonTokensPropCommitsCommitProp
Michael Ellerman1386.67%150.00%
Motohiro Kosaki213.33%150.00%
Total15100.00%2100.00%


static bool wait_for_other_cpus(int ncpus) { unsigned long timeout; /* We wait for 2s, which is a metric "little while" */ for (timeout = 20000; timeout != 0; --timeout) { if (cpumask_weight(&cpus_in_xmon) >= ncpus) return true; udelay(100); barrier(); } return false; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Piggin53100.00%1100.00%
Total53100.00%1100.00%

#endif /* CONFIG_SMP */
static inline int unrecoverable_excp(struct pt_regs *regs) { #if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E) /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */ return 0; #else return ((regs->msr & MSR_RI) == 0); #endif }

Contributors

PersonTokensPropCommitsCommitProp
Josh Boyer3375.00%133.33%
Jimi Xenidis1125.00%266.67%
Total44100.00%3100.00%


static int xmon_core(struct pt_regs *regs, int fromipi) { int cmd = 0; struct bpt *bp; long recurse_jmp[JMP_BUF_LEN]; unsigned long offset; unsigned long flags; #ifdef CONFIG_SMP int cpu; int secondary; #endif local_irq_save(flags); hard_irq_disable(); tracing_enabled = tracing_is_on(); tracing_off(); bp = in_breakpoint_table(regs->nip, &offset); if (bp != NULL) { regs->nip = bp->address + offset; atomic_dec(&bp->ref_count); } remove_cpu_bpts(); #ifdef CONFIG_SMP cpu = smp_processor_id(); if (cpumask_test_cpu(cpu, &cpus_in_xmon)) { /* * We catch SPR read/write faults here because the 0x700, 0xf60 * etc. handlers don't call debugger_fault_handler(). */ if (catch_spr_faults) longjmp(bus_error_jmp, 1); get_output_lock(); excprint(regs); printf("cpu 0x%x: Exception %lx %s in xmon, " "returning to main loop\n", cpu, regs->trap, getvecname(TRAP(regs))); release_output_lock(); longjmp(xmon_fault_jmp[cpu], 1); } if (setjmp(recurse_jmp) != 0) { if (!in_xmon || !xmon_gate) { get_output_lock(); printf("xmon: WARNING: bad recursive fault " "on cpu 0x%x\n", cpu); release_output_lock(); goto waiting; } secondary = !(xmon_taken && cpu == xmon_owner); goto cmdloop; } xmon_fault_jmp[cpu] = recurse_jmp; bp = NULL; if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) bp = at_breakpoint(regs->nip); if (bp || unrecoverable_excp(regs)) fromipi = 0; if (!fromipi) { get_output_lock(); excprint(regs); if (bp) { printf("cpu 0x%x stopped at breakpoint 0x%lx (", cpu, BP_NUM(bp)); xmon_print_symbol(regs->nip, " ", ")\n"); } if (unrecoverable_excp(regs)) printf("WARNING: exception is not recoverable, " "can't continue\n"); release_output_lock(); } cpumask_set_cpu(cpu, &cpus_in_xmon); waiting: secondary = 1; while (secondary && !xmon_gate) { if (in_xmon == 0) { if (fromipi) goto leave; secondary = test_and_set_bit(0, &in_xmon); } barrier(); } if (!secondary && !xmon_gate) { /* we are the first cpu to come in */ /* interrupt other cpu(s) */ int ncpus = num_online_cpus(); xmon_owner = cpu; mb(); if (ncpus > 1) { /* * A system reset (trap == 0x100) can be triggered on * all CPUs, so when we come in via 0x100 try waiting * for the other CPUs to come in before we send the * debugger break (IPI). This is similar to * crash_kexec_secondary(). */ if (TRAP(regs) != 0x100 || !wait_for_other_cpus(ncpus)) smp_send_debugger_break(); wait_for_other_cpus(ncpus); } remove_bpts(); disable_surveillance(); /* for breakpoint or single step, print the current instr. */ if (bp || TRAP(regs) == 0xd00) ppc_inst_dump(regs->nip, 1, 0); printf("enter ? for help\n"); mb(); xmon_gate = 1; barrier(); } cmdloop: while (in_xmon) { if (secondary) { if (cpu == xmon_owner) { if (!test_and_set_bit(0, &xmon_taken)) { secondary = 0; continue; } /* missed it */ while (cpu == xmon_owner) barrier(); } barrier(); } else { cmd = cmds(regs); if (cmd != 0) { /* exiting xmon */ insert_bpts(); xmon_gate = 0; wmb(); in_xmon = 0; break; } /* have switched to some other cpu */ secondary = 1; } } leave: cpumask_clear_cpu(cpu, &cpus_in_xmon); xmon_fault_jmp[cpu] = NULL; #else /* UP is simple... */ if (in_xmon) { printf("Exception %lx %s in xmon, returning to main loop\n", regs->trap, getvecname(TRAP(regs))); longjmp(xmon_fault_jmp[0], 1); } if (setjmp(recurse_jmp) == 0) { xmon_fault_jmp[0] = recurse_jmp; in_xmon = 1; excprint(regs); bp = at_breakpoint(regs->nip); if (bp) { printf("Stopped at breakpoint %lx (", BP_NUM(bp)); xmon_print_symbol(regs->nip, " ", ")\n"); } if (unrecoverable_excp(regs)) printf("WARNING: exception is not recoverable, " "can't continue\n"); remove_bpts(); disable_surveillance(); /* for breakpoint or single step, print the current instr. */ if (bp || TRAP(regs) == 0xd00) ppc_inst_dump(regs->nip, 1, 0); printf("enter ? for help\n"); } cmd = cmds(regs); insert_bpts(); in_xmon = 0; #endif #ifdef CONFIG_BOOKE if (regs->msr & MSR_DE) { bp = at_breakpoint(regs->nip); if (bp != NULL) { regs->nip = (unsigned long) &bp->instr[0]; atomic_inc(&bp->ref_count); } } #else if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) { bp = at_breakpoint(regs->nip); if (bp != NULL) { int stepped = emulate_step(regs, bp->instr[0]); if (stepped == 0) { regs->nip = (unsigned long) &bp->instr[0]; atomic_inc(&bp->ref_count); } else if (stepped < 0) { printf("Couldn't single-step %s instruction\n", (IS_RFID(bp->instr[0])? "rfid": "mtmsrd")); } } } #endif insert_cpu_bpts(); touch_nmi_watchdog(); local_irq_restore(flags); return cmd != 'X' && cmd != EOF; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton58360.41%520.83%
Anton Blanchard21522.28%520.83%
Josh Boyer676.94%28.33%
Paul Mackerras484.97%416.67%
Nicholas Piggin161.66%14.17%
Michael Ellerman141.45%312.50%
Haren Myneni90.93%14.17%
Breno Leitão80.83%14.17%
Motohiro Kosaki40.41%14.17%
Arnd Bergmann10.10%14.17%
Total965100.00%24100.00%


int xmon(struct pt_regs *excp) { struct pt_regs regs; if (excp == NULL) { ppc_save_regs(&regs); excp = &regs; } return xmon_core(excp, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton3380.49%125.00%
Anton Blanchard49.76%125.00%
Paul Mackerras37.32%125.00%
Anton Vorontsov12.44%125.00%
Total41100.00%4100.00%

EXPORT_SYMBOL(xmon);
irqreturn_t xmon_irq(int irq, void *d) { unsigned long flags; local_irq_save(flags); printf("Keyboard interrupt\n"); xmon(get_irq_regs()); local_irq_restore(flags); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras40100.00%2100.00%
Total40100.00%2100.00%


static int xmon_bpt(struct pt_regs *regs) { struct bpt *bp; unsigned long offset; if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT)) return 0; /* Are we at the trap at bp->instr[1] for some bp? */ bp = in_breakpoint_table(regs->nip, &offset); if (bp != NULL && offset == 4) { regs->nip = bp->address + 4; atomic_dec(&bp->ref_count); return 1; } /* Are we at a breakpoint? */ bp = at_breakpoint(regs->nip); if (!bp) return 0; xmon_core(regs, 0); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton8369.75%116.67%
Anton Blanchard3327.73%350.00%
Michael Ellerman21.68%116.67%
Arnd Bergmann10.84%116.67%
Total119100.00%6100.00%


static int xmon_sstep(struct pt_regs *regs) { if (user_mode(regs)) return 0; xmon_core(regs, 0); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton3096.77%150.00%
Arnd Bergmann13.23%150.00%
Total31100.00%2100.00%


static int xmon_break_match(struct pt_regs *regs) { if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT)) return 0; if (dabr.enabled == 0) return 0; xmon_core(regs, 0); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton4273.68%120.00%
Anton Blanchard1119.30%120.00%
Michael Ellerman23.51%120.00%
Arnd Bergmann11.75%120.00%
Michael Neuling11.75%120.00%
Total57100.00%5100.00%


static int xmon_iabr_match(struct pt_regs *regs) { if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT)) return 0; if (iabr == NULL) return 0; xmon_core(regs, 0); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton5192.73%125.00%
Michael Ellerman35.45%250.00%
Arnd Bergmann11.82%125.00%
Total55100.00%4100.00%


static int xmon_ipi(struct pt_regs *regs) { #ifdef CONFIG_SMP if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon)) xmon_core(regs, 1); #endif return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton3792.50%133.33%
Motohiro Kosaki25.00%133.33%
Arnd Bergmann12.50%133.33%
Total40100.00%3100.00%


static int xmon_fault_handler(struct pt_regs *regs) { struct bpt *bp; unsigned long offset; if (in_xmon && catch_memory_errors) handle_fault(regs); /* doesn't return */ if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) { bp = in_breakpoint_table(regs->nip, &offset); if (bp != NULL) { regs->nip = bp->address + offset; atomic_dec(&bp->ref_count); } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton9496.91%133.33%
Michael Ellerman22.06%133.33%
Arnd Bergmann11.03%133.33%
Total97100.00%3100.00%


static struct bpt *at_breakpoint(unsigned long pc) { int i; struct bpt *bp; bp = bpts; for (i = 0