* ========== Copyright Header Begin ==========================================
* OpenSPARC T2 Processor File: breakpoint.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
* The above named 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 work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
* ========== Copyright Header End ============================================
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
#pragma ident "@(#)breakpoint.c 1.11 07/05/30 SMI"
#include "xicache.h" /* for xicache_instn_flush */
* Breakpoint info is a global structure.
* We set a pointer in the cpu structure to it
* to indicate that breakpoints are possible for that
* cpu. The only thread that can modify this structure
* and it's elements is the main run thread ...
* .... so we don't need to worry about locking it ....
* .... just have to be careful about adding and removing
* entries so as to not strand cpus in hyperspace....
bip
= Xcalloc(1, bp_info_t
);
for (i
= 0; i
< BREAK_HASH_SIZE
; i
++) {
bip
->active_listp
= NULL
;
bip
->disabled_listp
= NULL
;
* Insert at top of hash ... recently
* added breakpoints should be found first ...
bp_hash_insert(bp_info_t
*bip
, breakpoint_t
*bp
)
assert(bp
->hash_nextp
== (void*)0);
assert(bp
->free_nextp
== (void*)0);
assert(bp
->disabled_nextp
== (void*)0);
i
= (bp
->pc
>> 2) & BREAK_HASH_MASK
;
bp
->hash_nextp
= bip
->hash
[i
];
* only gets called for existing breakpoints
* which are being deleted or disabled
bp_hash_unhook(bp_info_t
*bip
, breakpoint_t
*bp
)
assert(bp
->free_nextp
== (void*)0);
assert(bp
->disabled_nextp
== (void*)0);
i
= (bp
->pc
>> 2) & BREAK_HASH_MASK
;
for (pbp
= &(bip
->hash
[i
]); (bb
= *pbp
) != (void*)0;
pbp
= &(bb
->hash_nextp
)) {
bb
->hash_nextp
= NULL
; /* sanity */
* just enabled a breakpoint, so clobber the
* cpus' xi-caches ... and other stuff ...
* this is pretty poor, and we must come up with a
* better way to get the cpus to exit their
* inner loops.... this may not always work FIXME
* ... talk about brute force - FIXME
breaks_changed(bp_info_t
*bip
)
for (i
= 0; i
< simcpu_list
.count
; i
++) {
sp
= LIST_ENTRY(simcpu_list
, i
);
/* blow away decoded versions ... */
sp
->xicache_instn_flush_pending
= true;
* Insert a new breakpoint ...
breakpoint_insert(bp_info_t
*bip
, tvaddr_t pc
, int context
)
DBG( printf("breakpoint_insert: @ 0x%llx, ctxt=0x%x\n", pc
, (int)context
); );
if (bip
->free_listp
!= NULL
) {
bip
->free_listp
= bp
->free_nextp
;
/* use calloc to clear all pointer fields */
bp
= (breakpoint_t
*)calloc(1, sizeof (*bp
));
if (bp
== NULL
) fatal("out of memory in breakpoint_insert");
bp
->active_nextp
= bip
->active_listp
;
/* must not be disabled */
assert(bp
->disabled_nextp
== NULL
);
breakpoint_insert_next(bp_info_t
*bip
)
breakpoint_clear_next(bp_info_t
*bip
)
breakpoint_find_by_addr(bp_info_t
*bip
, uint64_t addr
, int context
)
i
= (addr
>> 2) & BREAK_HASH_MASK
;
for (bp
= bip
->hash
[i
]; bp
!= NULL
; bp
= bp
->hash_nextp
) {
if (bp
->pc
== addr
&& bp
->context
== context
)
return ((breakpoint_t
*)0);
breakpoint_delete_by_id(bp_info_t
*bip
, int id
)
/* search first active list */
for (pbp
= &(bip
->active_listp
); (bp
= *pbp
) != NULL
;
pbp
= &(bp
->active_nextp
)) {
assert(bp
->enabled
); /* sanity */
/* unhook from list and unhook from hash */
/* then search disabled list */
for (pbp
= &(bip
->disabled_listp
); (bp
= *pbp
) != NULL
;
pbp
= &(bp
->disabled_nextp
)) {
assert(!bp
->enabled
); /* sanity */
/* hit on disabled list */
*pbp
= bp
->disabled_nextp
;
return (-1); /* no such id */
/* just stuff back on free list */
bp
->disabled_nextp
= NULL
;
assert(bp
->free_nextp
== NULL
);
assert(bp
->hash_nextp
== NULL
);
bp
->free_nextp
= bip
->free_listp
;
* Hardly efficient, but effective - FIXME
* Since don't often add or remove breakpoints
* hopefully this isn't too painful.
breakpoint_delete_by_addr(bp_info_t
*bip
, uint64_t addr
, int context
)
bool_t flag_deleted
= false;
while ((bp
= breakpoint_find_by_addr(bip
, addr
, context
)) \
breakpoint_delete_by_id(bip
, bp
->id
);
* Either the bp is enabled, disabled or doesn't exist !
breakpoint_disable_by_id(bp_info_t
*bip
, int id
)
/* search first active list */
for (pbp
= &(bip
->active_listp
); (bp
= *pbp
) != NULL
;
pbp
= &(bp
->active_nextp
)) {
assert(bp
->enabled
); /* sanity */
/* unhook from active list and unhook from hash */
/* then search disabled list */
for (bp
= bip
->disabled_listp
; bp
!= NULL
; bp
= bp
->disabled_nextp
) {
assert(!bp
->enabled
); /* sanity */
/* hit on disabled list */
printf("Breakpoint %d is already disabled\n", bp
->id
);
return (0); /* job done */
printf("No breakpoint with id %d\n", bp
->id
);
return (-1); /* no such id */
assert(bp
->disabled_nextp
== NULL
);
assert(bp
->free_nextp
== NULL
);
assert(bp
->hash_nextp
== NULL
);
bp
->disabled_nextp
= bip
->disabled_listp
;
bip
->disabled_listp
= bp
;
breakpoint_enable_by_id(bp_info_t
*bip
, int id
)
/* make sure not already enabled */
for (bp
= bip
->active_listp
; bp
!= NULL
; bp
= bp
->active_nextp
) {
assert(bp
->enabled
); /* sanity */
printf("Breakpoint %d is already enabled\n", bp
->id
);
return (0); /* job done */
/* then search disabled list */
for (pbp
= &(bip
->disabled_listp
); (bp
= *pbp
) != NULL
;
pbp
= &(bp
->disabled_nextp
)) {
assert(!bp
->enabled
); /* sanity */
*pbp
= bp
->disabled_nextp
;
bp
->disabled_nextp
= NULL
;
printf("No breakpoint with id %d\n", bp
->id
);
return (-1); /* no such id */
assert(bp
->active_nextp
== NULL
);
assert(bp
->disabled_nextp
== NULL
);
assert(bp
->free_nextp
== NULL
);
assert(bp
->hash_nextp
== NULL
);
bp
->active_nextp
= bip
->active_listp
;
/* no need to flush xcache here, but do set ptrs */
* This is what gets called if we're checking for a possible
* We return one of three options:
* a) NOTHING - didn't hit anything
* b) ON_BREAKPOINT - we landed on a breakpoint
breakpoint_check(bp_info_t
*bip
, uint64_t pc
, int context
, breakpoint_t
**bpp
)
i
= (pc
>> 2) & BREAK_HASH_MASK
;
for (bp
= bip
->hash
[i
]; bp
!= NULL
; bp
= bp
->hash_nextp
) {
continue; /* in process of being deleted */
DBG( printf("Matched pc @ 0x%llx : current ctxt = 0x%x, match ctxt = 0x%x\n", pc
, context
, bp
->context
); );
if (bp
->context
== context
) {
breakpoint_any_reached(void)
for (i
= 0; i
< simcpu_list
.count
; i
++) {
sp
= LIST_ENTRY(simcpu_list
, i
);
if (sp
->bp_infop
!= NULL
&&
breakpoint_check(sp
->bp_infop
, sp
->pc
, DEFAULT_BP_CONTEXT
,
/* FIXME */ &bp
) == ON_BREAKPOINT
) {
* Print all the breakpoints (in order)
breakpoint_print(bp_info_t
*bip
)
printf("List of active simulation breakpoints:\n");
for (pbp
= &(bip
->active_listp
); (bp
= *pbp
) != NULL
;
pbp
= &(bp
->active_nextp
)) {
assert(bp
->enabled
); /* sanity */
printf("breakpoint id=%d: pc=0x%llx, context=0x%x, "
"enabled=%s\n", bp
->id
, bp
->pc
, bp
->context
,
bp
->enabled
? "true" : "false");
printf("No simulation Breakpoints set\n");
* Dump all the breakpoints (in order)
breakpoint_dump(bp_info_t
*bip
, FILE *fp
)
for (pbp
= &(bip
->active_listp
); (bp
= *pbp
) != NULL
;
pbp
= &(bp
->active_nextp
)) {
printf("breakpoint_dump: saving: 0x%016llx\n", bp
->pc
);
fprintf(fp
, "0x%016llx\n", bp
->pc
);
printf("%d simulation Breakpoints saved\n", count
);
printf("No simulation Breakpoints set, none to save\n");
breakpoint_restore(bp_info_t
*bip
, FILE *fp
)
while (fgets(line
, sizeof (line
), fp
) != NULL
) {
rv
= sscanf(line
, "%llx", &bp
);
printf("breakpoint_restore: "
printf("breakpoint_restore: restoring: "
breakpoint_insert(bip
, bp
, DEFAULT_BP_CONTEXT
);
printf("%d simulation Breakpoints restored\n", count
);
printf("No simulation Breakpoints restored\n");