mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 09:08:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
553
kernel/debug/kdb/kdb_bp.c
Normal file
553
kernel/debug/kdb/kdb_bp.c
Normal file
|
@ -0,0 +1,553 @@
|
|||
/*
|
||||
* Kernel Debugger Architecture Independent Breakpoint Handler
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved.
|
||||
* Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kdb.h>
|
||||
#include <linux/kgdb.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include "kdb_private.h"
|
||||
|
||||
/*
|
||||
* Table of kdb_breakpoints
|
||||
*/
|
||||
kdb_bp_t kdb_breakpoints[KDB_MAXBPT];
|
||||
|
||||
static void kdb_setsinglestep(struct pt_regs *regs)
|
||||
{
|
||||
KDB_STATE_SET(DOING_SS);
|
||||
}
|
||||
|
||||
static char *kdb_rwtypes[] = {
|
||||
"Instruction(i)",
|
||||
"Instruction(Register)",
|
||||
"Data Write",
|
||||
"I/O",
|
||||
"Data Access"
|
||||
};
|
||||
|
||||
static char *kdb_bptype(kdb_bp_t *bp)
|
||||
{
|
||||
if (bp->bp_type < 0 || bp->bp_type > 4)
|
||||
return "";
|
||||
|
||||
return kdb_rwtypes[bp->bp_type];
|
||||
}
|
||||
|
||||
static int kdb_parsebp(int argc, const char **argv, int *nextargp, kdb_bp_t *bp)
|
||||
{
|
||||
int nextarg = *nextargp;
|
||||
int diag;
|
||||
|
||||
bp->bph_length = 1;
|
||||
if ((argc + 1) != nextarg) {
|
||||
if (strncasecmp(argv[nextarg], "datar", sizeof("datar")) == 0)
|
||||
bp->bp_type = BP_ACCESS_WATCHPOINT;
|
||||
else if (strncasecmp(argv[nextarg], "dataw", sizeof("dataw")) == 0)
|
||||
bp->bp_type = BP_WRITE_WATCHPOINT;
|
||||
else if (strncasecmp(argv[nextarg], "inst", sizeof("inst")) == 0)
|
||||
bp->bp_type = BP_HARDWARE_BREAKPOINT;
|
||||
else
|
||||
return KDB_ARGCOUNT;
|
||||
|
||||
bp->bph_length = 1;
|
||||
|
||||
nextarg++;
|
||||
|
||||
if ((argc + 1) != nextarg) {
|
||||
unsigned long len;
|
||||
|
||||
diag = kdbgetularg((char *)argv[nextarg],
|
||||
&len);
|
||||
if (diag)
|
||||
return diag;
|
||||
|
||||
|
||||
if (len > 8)
|
||||
return KDB_BADLENGTH;
|
||||
|
||||
bp->bph_length = len;
|
||||
nextarg++;
|
||||
}
|
||||
|
||||
if ((argc + 1) != nextarg)
|
||||
return KDB_ARGCOUNT;
|
||||
}
|
||||
|
||||
*nextargp = nextarg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _kdb_bp_remove(kdb_bp_t *bp)
|
||||
{
|
||||
int ret = 1;
|
||||
if (!bp->bp_installed)
|
||||
return ret;
|
||||
if (!bp->bp_type)
|
||||
ret = dbg_remove_sw_break(bp->bp_addr);
|
||||
else
|
||||
ret = arch_kgdb_ops.remove_hw_breakpoint(bp->bp_addr,
|
||||
bp->bph_length,
|
||||
bp->bp_type);
|
||||
if (ret == 0)
|
||||
bp->bp_installed = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void kdb_handle_bp(struct pt_regs *regs, kdb_bp_t *bp)
|
||||
{
|
||||
if (KDB_DEBUG(BP))
|
||||
kdb_printf("regs->ip = 0x%lx\n", instruction_pointer(regs));
|
||||
|
||||
/*
|
||||
* Setup single step
|
||||
*/
|
||||
kdb_setsinglestep(regs);
|
||||
|
||||
/*
|
||||
* Reset delay attribute
|
||||
*/
|
||||
bp->bp_delay = 0;
|
||||
bp->bp_delayed = 1;
|
||||
}
|
||||
|
||||
static int _kdb_bp_install(struct pt_regs *regs, kdb_bp_t *bp)
|
||||
{
|
||||
int ret;
|
||||
/*
|
||||
* Install the breakpoint, if it is not already installed.
|
||||
*/
|
||||
|
||||
if (KDB_DEBUG(BP))
|
||||
kdb_printf("%s: bp_installed %d\n",
|
||||
__func__, bp->bp_installed);
|
||||
if (!KDB_STATE(SSBPT))
|
||||
bp->bp_delay = 0;
|
||||
if (bp->bp_installed)
|
||||
return 1;
|
||||
if (bp->bp_delay || (bp->bp_delayed && KDB_STATE(DOING_SS))) {
|
||||
if (KDB_DEBUG(BP))
|
||||
kdb_printf("%s: delayed bp\n", __func__);
|
||||
kdb_handle_bp(regs, bp);
|
||||
return 0;
|
||||
}
|
||||
if (!bp->bp_type)
|
||||
ret = dbg_set_sw_break(bp->bp_addr);
|
||||
else
|
||||
ret = arch_kgdb_ops.set_hw_breakpoint(bp->bp_addr,
|
||||
bp->bph_length,
|
||||
bp->bp_type);
|
||||
if (ret == 0) {
|
||||
bp->bp_installed = 1;
|
||||
} else {
|
||||
kdb_printf("%s: failed to set breakpoint at 0x%lx\n",
|
||||
__func__, bp->bp_addr);
|
||||
#ifdef CONFIG_DEBUG_RODATA
|
||||
if (!bp->bp_type) {
|
||||
kdb_printf("Software breakpoints are unavailable.\n"
|
||||
" Change the kernel CONFIG_DEBUG_RODATA=n\n"
|
||||
" OR use hw breaks: help bph\n");
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* kdb_bp_install
|
||||
*
|
||||
* Install kdb_breakpoints prior to returning from the
|
||||
* kernel debugger. This allows the kdb_breakpoints to be set
|
||||
* upon functions that are used internally by kdb, such as
|
||||
* printk(). This function is only called once per kdb session.
|
||||
*/
|
||||
void kdb_bp_install(struct pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < KDB_MAXBPT; i++) {
|
||||
kdb_bp_t *bp = &kdb_breakpoints[i];
|
||||
|
||||
if (KDB_DEBUG(BP)) {
|
||||
kdb_printf("%s: bp %d bp_enabled %d\n",
|
||||
__func__, i, bp->bp_enabled);
|
||||
}
|
||||
if (bp->bp_enabled)
|
||||
_kdb_bp_install(regs, bp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* kdb_bp_remove
|
||||
*
|
||||
* Remove kdb_breakpoints upon entry to the kernel debugger.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
* Outputs:
|
||||
* None.
|
||||
* Returns:
|
||||
* None.
|
||||
* Locking:
|
||||
* None.
|
||||
* Remarks:
|
||||
*/
|
||||
void kdb_bp_remove(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = KDB_MAXBPT - 1; i >= 0; i--) {
|
||||
kdb_bp_t *bp = &kdb_breakpoints[i];
|
||||
|
||||
if (KDB_DEBUG(BP)) {
|
||||
kdb_printf("%s: bp %d bp_enabled %d\n",
|
||||
__func__, i, bp->bp_enabled);
|
||||
}
|
||||
if (bp->bp_enabled)
|
||||
_kdb_bp_remove(bp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* kdb_printbp
|
||||
*
|
||||
* Internal function to format and print a breakpoint entry.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
* Outputs:
|
||||
* None.
|
||||
* Returns:
|
||||
* None.
|
||||
* Locking:
|
||||
* None.
|
||||
* Remarks:
|
||||
*/
|
||||
|
||||
static void kdb_printbp(kdb_bp_t *bp, int i)
|
||||
{
|
||||
kdb_printf("%s ", kdb_bptype(bp));
|
||||
kdb_printf("BP #%d at ", i);
|
||||
kdb_symbol_print(bp->bp_addr, NULL, KDB_SP_DEFAULT);
|
||||
|
||||
if (bp->bp_enabled)
|
||||
kdb_printf("\n is enabled");
|
||||
else
|
||||
kdb_printf("\n is disabled");
|
||||
|
||||
kdb_printf("\taddr at %016lx, hardtype=%d installed=%d\n",
|
||||
bp->bp_addr, bp->bp_type, bp->bp_installed);
|
||||
|
||||
kdb_printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* kdb_bp
|
||||
*
|
||||
* Handle the bp commands.
|
||||
*
|
||||
* [bp|bph] <addr-expression> [DATAR|DATAW]
|
||||
*
|
||||
* Parameters:
|
||||
* argc Count of arguments in argv
|
||||
* argv Space delimited command line arguments
|
||||
* Outputs:
|
||||
* None.
|
||||
* Returns:
|
||||
* Zero for success, a kdb diagnostic if failure.
|
||||
* Locking:
|
||||
* None.
|
||||
* Remarks:
|
||||
*
|
||||
* bp Set breakpoint on all cpus. Only use hardware assist if need.
|
||||
* bph Set breakpoint on all cpus. Force hardware register
|
||||
*/
|
||||
|
||||
static int kdb_bp(int argc, const char **argv)
|
||||
{
|
||||
int i, bpno;
|
||||
kdb_bp_t *bp, *bp_check;
|
||||
int diag;
|
||||
char *symname = NULL;
|
||||
long offset = 0ul;
|
||||
int nextarg;
|
||||
kdb_bp_t template = {0};
|
||||
|
||||
if (argc == 0) {
|
||||
/*
|
||||
* Display breakpoint table
|
||||
*/
|
||||
for (bpno = 0, bp = kdb_breakpoints; bpno < KDB_MAXBPT;
|
||||
bpno++, bp++) {
|
||||
if (bp->bp_free)
|
||||
continue;
|
||||
kdb_printbp(bp, bpno);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
nextarg = 1;
|
||||
diag = kdbgetaddrarg(argc, argv, &nextarg, &template.bp_addr,
|
||||
&offset, &symname);
|
||||
if (diag)
|
||||
return diag;
|
||||
if (!template.bp_addr)
|
||||
return KDB_BADINT;
|
||||
|
||||
/*
|
||||
* Find an empty bp structure to allocate
|
||||
*/
|
||||
for (bpno = 0, bp = kdb_breakpoints; bpno < KDB_MAXBPT; bpno++, bp++) {
|
||||
if (bp->bp_free)
|
||||
break;
|
||||
}
|
||||
|
||||
if (bpno == KDB_MAXBPT)
|
||||
return KDB_TOOMANYBPT;
|
||||
|
||||
if (strcmp(argv[0], "bph") == 0) {
|
||||
template.bp_type = BP_HARDWARE_BREAKPOINT;
|
||||
diag = kdb_parsebp(argc, argv, &nextarg, &template);
|
||||
if (diag)
|
||||
return diag;
|
||||
} else {
|
||||
template.bp_type = BP_BREAKPOINT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for clashing breakpoints.
|
||||
*
|
||||
* Note, in this design we can't have hardware breakpoints
|
||||
* enabled for both read and write on the same address.
|
||||
*/
|
||||
for (i = 0, bp_check = kdb_breakpoints; i < KDB_MAXBPT;
|
||||
i++, bp_check++) {
|
||||
if (!bp_check->bp_free &&
|
||||
bp_check->bp_addr == template.bp_addr) {
|
||||
kdb_printf("You already have a breakpoint at "
|
||||
kdb_bfd_vma_fmt0 "\n", template.bp_addr);
|
||||
return KDB_DUPBPT;
|
||||
}
|
||||
}
|
||||
|
||||
template.bp_enabled = 1;
|
||||
|
||||
/*
|
||||
* Actually allocate the breakpoint found earlier
|
||||
*/
|
||||
*bp = template;
|
||||
bp->bp_free = 0;
|
||||
|
||||
kdb_printbp(bp, bpno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* kdb_bc
|
||||
*
|
||||
* Handles the 'bc', 'be', and 'bd' commands
|
||||
*
|
||||
* [bd|bc|be] <breakpoint-number>
|
||||
* [bd|bc|be] *
|
||||
*
|
||||
* Parameters:
|
||||
* argc Count of arguments in argv
|
||||
* argv Space delimited command line arguments
|
||||
* Outputs:
|
||||
* None.
|
||||
* Returns:
|
||||
* Zero for success, a kdb diagnostic for failure
|
||||
* Locking:
|
||||
* None.
|
||||
* Remarks:
|
||||
*/
|
||||
static int kdb_bc(int argc, const char **argv)
|
||||
{
|
||||
unsigned long addr;
|
||||
kdb_bp_t *bp = NULL;
|
||||
int lowbp = KDB_MAXBPT;
|
||||
int highbp = 0;
|
||||
int done = 0;
|
||||
int i;
|
||||
int diag = 0;
|
||||
|
||||
int cmd; /* KDBCMD_B? */
|
||||
#define KDBCMD_BC 0
|
||||
#define KDBCMD_BE 1
|
||||
#define KDBCMD_BD 2
|
||||
|
||||
if (strcmp(argv[0], "be") == 0)
|
||||
cmd = KDBCMD_BE;
|
||||
else if (strcmp(argv[0], "bd") == 0)
|
||||
cmd = KDBCMD_BD;
|
||||
else
|
||||
cmd = KDBCMD_BC;
|
||||
|
||||
if (argc != 1)
|
||||
return KDB_ARGCOUNT;
|
||||
|
||||
if (strcmp(argv[1], "*") == 0) {
|
||||
lowbp = 0;
|
||||
highbp = KDB_MAXBPT;
|
||||
} else {
|
||||
diag = kdbgetularg(argv[1], &addr);
|
||||
if (diag)
|
||||
return diag;
|
||||
|
||||
/*
|
||||
* For addresses less than the maximum breakpoint number,
|
||||
* assume that the breakpoint number is desired.
|
||||
*/
|
||||
if (addr < KDB_MAXBPT) {
|
||||
bp = &kdb_breakpoints[addr];
|
||||
lowbp = highbp = addr;
|
||||
highbp++;
|
||||
} else {
|
||||
for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT;
|
||||
i++, bp++) {
|
||||
if (bp->bp_addr == addr) {
|
||||
lowbp = highbp = i;
|
||||
highbp++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now operate on the set of breakpoints matching the input
|
||||
* criteria (either '*' for all, or an individual breakpoint).
|
||||
*/
|
||||
for (bp = &kdb_breakpoints[lowbp], i = lowbp;
|
||||
i < highbp;
|
||||
i++, bp++) {
|
||||
if (bp->bp_free)
|
||||
continue;
|
||||
|
||||
done++;
|
||||
|
||||
switch (cmd) {
|
||||
case KDBCMD_BC:
|
||||
bp->bp_enabled = 0;
|
||||
|
||||
kdb_printf("Breakpoint %d at "
|
||||
kdb_bfd_vma_fmt " cleared\n",
|
||||
i, bp->bp_addr);
|
||||
|
||||
bp->bp_addr = 0;
|
||||
bp->bp_free = 1;
|
||||
|
||||
break;
|
||||
case KDBCMD_BE:
|
||||
bp->bp_enabled = 1;
|
||||
|
||||
kdb_printf("Breakpoint %d at "
|
||||
kdb_bfd_vma_fmt " enabled",
|
||||
i, bp->bp_addr);
|
||||
|
||||
kdb_printf("\n");
|
||||
break;
|
||||
case KDBCMD_BD:
|
||||
if (!bp->bp_enabled)
|
||||
break;
|
||||
|
||||
bp->bp_enabled = 0;
|
||||
|
||||
kdb_printf("Breakpoint %d at "
|
||||
kdb_bfd_vma_fmt " disabled\n",
|
||||
i, bp->bp_addr);
|
||||
|
||||
break;
|
||||
}
|
||||
if (bp->bp_delay && (cmd == KDBCMD_BC || cmd == KDBCMD_BD)) {
|
||||
bp->bp_delay = 0;
|
||||
KDB_STATE_CLEAR(SSBPT);
|
||||
}
|
||||
}
|
||||
|
||||
return (!done) ? KDB_BPTNOTFOUND : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* kdb_ss
|
||||
*
|
||||
* Process the 'ss' (Single Step) command.
|
||||
*
|
||||
* ss
|
||||
*
|
||||
* Parameters:
|
||||
* argc Argument count
|
||||
* argv Argument vector
|
||||
* Outputs:
|
||||
* None.
|
||||
* Returns:
|
||||
* KDB_CMD_SS for success, a kdb error if failure.
|
||||
* Locking:
|
||||
* None.
|
||||
* Remarks:
|
||||
*
|
||||
* Set the arch specific option to trigger a debug trap after the next
|
||||
* instruction.
|
||||
*/
|
||||
|
||||
static int kdb_ss(int argc, const char **argv)
|
||||
{
|
||||
if (argc != 0)
|
||||
return KDB_ARGCOUNT;
|
||||
/*
|
||||
* Set trace flag and go.
|
||||
*/
|
||||
KDB_STATE_SET(DOING_SS);
|
||||
return KDB_CMD_SS;
|
||||
}
|
||||
|
||||
/* Initialize the breakpoint table and register breakpoint commands. */
|
||||
|
||||
void __init kdb_initbptab(void)
|
||||
{
|
||||
int i;
|
||||
kdb_bp_t *bp;
|
||||
|
||||
/*
|
||||
* First time initialization.
|
||||
*/
|
||||
memset(&kdb_breakpoints, '\0', sizeof(kdb_breakpoints));
|
||||
|
||||
for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++)
|
||||
bp->bp_free = 1;
|
||||
|
||||
kdb_register_repeat("bp", kdb_bp, "[<vaddr>]",
|
||||
"Set/Display breakpoints", 0, KDB_REPEAT_NO_ARGS);
|
||||
kdb_register_repeat("bl", kdb_bp, "[<vaddr>]",
|
||||
"Display breakpoints", 0, KDB_REPEAT_NO_ARGS);
|
||||
if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT)
|
||||
kdb_register_repeat("bph", kdb_bp, "[<vaddr>]",
|
||||
"[datar [length]|dataw [length]] Set hw brk", 0, KDB_REPEAT_NO_ARGS);
|
||||
kdb_register_repeat("bc", kdb_bc, "<bpnum>",
|
||||
"Clear Breakpoint", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("be", kdb_bc, "<bpnum>",
|
||||
"Enable Breakpoint", 0, KDB_REPEAT_NONE);
|
||||
kdb_register_repeat("bd", kdb_bc, "<bpnum>",
|
||||
"Disable Breakpoint", 0, KDB_REPEAT_NONE);
|
||||
|
||||
kdb_register_repeat("ss", kdb_ss, "",
|
||||
"Single Step", 1, KDB_REPEAT_NO_ARGS);
|
||||
/*
|
||||
* Architecture dependent initialization.
|
||||
*/
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue