SELFOUR-836: Hardware debug API functions should take tcb_t and not arch_tcb_t

Touches files all throughout x86 (32 and 64) and ARM.
This commit is contained in:
Kofi Doku Atuah 2017-03-22 16:11:49 +11:00 committed by Adrian Danis
parent 4e5cc369ff
commit 3f90fad605
13 changed files with 195 additions and 202 deletions

View file

@ -186,18 +186,18 @@ seL4_Fault_t handleUserLevelDebugException(word_t fault_vaddr);
* bitfield.
*/
static inline void
setBreakpointUsedFlag(arch_tcb_t *uds, uint16_t bp_num)
setBreakpointUsedFlag(tcb_t *t, uint16_t bp_num)
{
if (uds != NULL) {
uds->tcbContext.breakpointState.used_breakpoints_bf |= BIT(bp_num);
if (t != NULL) {
t->tcbArch.tcbContext.breakpointState.used_breakpoints_bf |= BIT(bp_num);
}
}
static inline void
unsetBreakpointUsedFlag(arch_tcb_t *uds, uint16_t bp_num)
unsetBreakpointUsedFlag(tcb_t *t, uint16_t bp_num)
{
if (uds != NULL) {
uds->tcbContext.breakpointState.used_breakpoints_bf &= ~BIT(bp_num);
if (t != NULL) {
t->tcbArch.tcbContext.breakpointState.used_breakpoints_bf &= ~BIT(bp_num);
}
}

View file

@ -193,7 +193,7 @@ static inline void Arch_initContext(user_context_t* context)
{
context->registers[CPSR] = CPSR_USER;
#if !defined(CONFIG_VERIFICATION_BUILD) && (defined(CONFIG_HARDWARE_DEBUG_API) || defined(CONFIG_ARM_HYPERVISOR_SUPPORT))
Arch_initBreakpointContext(&context->breakpointState);
Arch_initBreakpointContext(context);
#endif
}

View file

@ -20,7 +20,7 @@
void restore_user_debug_context(tcb_t *target_thread);
void Arch_debugAssociateVCPUTCB(tcb_t *t);
void Arch_debugDissociateVCPUTCB(tcb_t *t);
void saveAllBreakpointState(arch_tcb_t *at);
void saveAllBreakpointState(tcb_t *t);
void loadAllDisabledBreakpointState(void);
#endif
@ -117,7 +117,7 @@ getTypeFromBpNum(uint16_t bp_num)
}
static inline syscall_error_t
Arch_decodeConfigureSingleStepping(arch_tcb_t *at,
Arch_decodeConfigureSingleStepping(tcb_t *t,
uint16_t bp_num,
word_t n_instr,
bool_t is_reply)
@ -132,7 +132,7 @@ Arch_decodeConfigureSingleStepping(arch_tcb_t *at,
* configured bp_num. Of course, this assumes that a register had
* already previously been configured for single-stepping.
*/
if (!at->tcbContext.breakpointState.single_step_enabled) {
if (!t->tcbArch.tcbContext.breakpointState.single_step_enabled) {
userError("Debug: Single-step reply when single-stepping not "
"enabled.");
ret.type = seL4_IllegalOperation;
@ -140,7 +140,7 @@ Arch_decodeConfigureSingleStepping(arch_tcb_t *at,
}
type = seL4_InstructionBreakpoint;
bp_num = at->tcbContext.breakpointState.single_step_hw_bp_num;
bp_num = t->tcbArch.tcbContext.breakpointState.single_step_hw_bp_num;
} else {
type = getTypeFromBpNum(bp_num);
bp_num = convertBpNumToArch(bp_num);
@ -154,8 +154,8 @@ Arch_decodeConfigureSingleStepping(arch_tcb_t *at,
ret.invalidArgumentNumber = 0;
return ret;
}
if (at->tcbContext.breakpointState.single_step_enabled == true) {
if (bp_num != at->tcbContext.breakpointState.single_step_hw_bp_num) {
if (t->tcbArch.tcbContext.breakpointState.single_step_enabled == true) {
if (bp_num != t->tcbArch.tcbContext.breakpointState.single_step_hw_bp_num) {
/* Can't configure more than one register for stepping. */
userError("Debug: Only one register can be configured for "
"single-stepping at a time.");
@ -171,7 +171,7 @@ Arch_decodeConfigureSingleStepping(arch_tcb_t *at,
bool_t byte8WatchpointsSupported(void);
static inline syscall_error_t
Arch_decodeSetBreakpoint(arch_tcb_t *uds,
Arch_decodeSetBreakpoint(tcb_t *t,
uint16_t bp_num, word_t vaddr, word_t type,
word_t size, word_t rw)
{
@ -216,7 +216,7 @@ Arch_decodeSetBreakpoint(arch_tcb_t *uds,
}
static inline syscall_error_t
Arch_decodeGetBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
Arch_decodeGetBreakpoint(tcb_t *t, uint16_t bp_num)
{
syscall_error_t ret = {
.type = seL4_NoError
@ -231,7 +231,7 @@ Arch_decodeGetBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
}
static inline syscall_error_t
Arch_decodeUnsetBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
Arch_decodeUnsetBreakpoint(tcb_t *t, uint16_t bp_num)
{
syscall_error_t ret = {
.type = seL4_NoError
@ -249,7 +249,7 @@ Arch_decodeUnsetBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
type = getTypeFromBpNum(bp_num);
bp_num = convertBpNumToArch(bp_num);
bcr.words[0] = uds->tcbContext.breakpointState.breakpoint[bp_num].cr;
bcr.words[0] = t->tcbArch.tcbContext.breakpointState.breakpoint[bp_num].cr;
if (type == seL4_InstructionBreakpoint) {
if (Arch_breakpointIsMismatch(bcr) == true && dbg_bcr_get_enabled(bcr)) {
userError("Rejecting call to unsetBreakpoint on breakpoint configured "

View file

@ -106,7 +106,7 @@ writeDrReg(uint8_t reg, word_t val)
*@param source The memory block from which to load the register values.
*/
static inline void
loadBreakpointState(arch_tcb_t *source)
loadBreakpointState(tcb_t *source)
{
/* Order does matter when restoring the registers: we want to restore the
* breakpoint control register (DR7) last since it is what "activates" the
@ -132,7 +132,7 @@ loadBreakpointState(arch_tcb_t *source)
"movl (%%edx), %%ecx \n\t"
"movl %%ecx, %%dr7 \n\t"
:
: "r" (source->tcbContext.breakpointState.dr)
: "r" (source->tcbArch.tcbContext.breakpointState.dr)
: "edx", "ecx");
}

View file

@ -106,7 +106,7 @@ writeDrReg(uint8_t reg, word_t val)
*@param source The memory block from which to load the register values.
*/
static inline void
loadBreakpointState(arch_tcb_t *source)
loadBreakpointState(tcb_t *source)
{
/* Order does matter when restoring the registers: we want to restore the
* breakpoint control register (DR7) last since it is what "activates" the
@ -132,7 +132,7 @@ loadBreakpointState(arch_tcb_t *source)
"movq (%%rdx), %%rcx \n\t"
"movq %%rcx, %%dr7 \n\t"
:
: "r" (source->tcbContext.breakpointState.dr)
: "r" (source->tcbArch.tcbContext.breakpointState.dr)
: "rdx", "rcx");
}

View file

@ -58,18 +58,18 @@ exception_t handleUserLevelDebugException(int int_vector);
* bitfield.
*/
static inline void
setBreakpointUsedFlag(arch_tcb_t *uds, uint16_t bp_num)
setBreakpointUsedFlag(tcb_t *t, uint16_t bp_num)
{
if (uds != NULL) {
uds->tcbContext.breakpointState.used_breakpoints_bf |= BIT(bp_num);
if (t != NULL) {
t->tcbArch.tcbContext.breakpointState.used_breakpoints_bf |= BIT(bp_num);
}
}
static inline void
unsetBreakpointUsedFlag(arch_tcb_t *uds, uint16_t bp_num)
unsetBreakpointUsedFlag(tcb_t *t, uint16_t bp_num)
{
if (uds != NULL) {
uds->tcbContext.breakpointState.used_breakpoints_bf &= ~BIT(bp_num);
if (t != NULL) {
t->tcbArch.tcbContext.breakpointState.used_breakpoints_bf &= ~BIT(bp_num);
}
}
@ -82,11 +82,11 @@ unsetBreakpointUsedFlag(arch_tcb_t *uds, uint16_t bp_num)
* setting the disable bits.
*/
static void
loadAllDisabledBreakpointState(arch_tcb_t *at)
loadAllDisabledBreakpointState(tcb_t *t)
{
word_t disable_value;
disable_value = at->tcbContext.breakpointState.dr[5];
disable_value = t->tcbArch.tcbContext.breakpointState.dr[5];
disable_value &= ~(X86_DEBUG_BP0_ENABLE_BIT | X86_DEBUG_BP1_ENABLE_BIT
| X86_DEBUG_BP2_ENABLE_BIT | X86_DEBUG_BP3_ENABLE_BIT);
@ -98,9 +98,9 @@ restore_user_debug_context(tcb_t *target_thread)
{
arch_tcb_t *uds = &target_thread->tcbArch;
if (uds->tcbContext.breakpointState.used_breakpoints_bf != 0) {
loadBreakpointState(uds);
loadBreakpointState(target_thread);
} else {
loadAllDisabledBreakpointState(uds);
loadAllDisabledBreakpointState(target_thread);
}
/* If single-stepping was enabled, we need to re-set the TF flag as well. */
@ -126,7 +126,7 @@ restore_user_debug_context(tcb_t *target_thread)
}
static inline syscall_error_t
Arch_decodeConfigureSingleStepping(arch_tcb_t *uc,
Arch_decodeConfigureSingleStepping(tcb_t *t,
uint16_t bp_num,
word_t n_instr,
bool_t is_reply)
@ -140,7 +140,7 @@ Arch_decodeConfigureSingleStepping(arch_tcb_t *uc,
bool_t byte8BreakpointsSupported(void);
static inline syscall_error_t
Arch_decodeSetBreakpoint(arch_tcb_t *uds,
Arch_decodeSetBreakpoint(tcb_t *t,
uint16_t bp_num, word_t vaddr, word_t types,
word_t size, word_t rw)
{
@ -165,7 +165,7 @@ Arch_decodeSetBreakpoint(arch_tcb_t *uds,
}
static inline syscall_error_t
Arch_decodeGetBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
Arch_decodeGetBreakpoint(tcb_t *t, uint16_t bp_num)
{
syscall_error_t ret = {
.type = seL4_NoError
@ -181,7 +181,7 @@ Arch_decodeGetBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
}
static inline syscall_error_t
Arch_decodeUnsetBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
Arch_decodeUnsetBreakpoint(tcb_t *t, uint16_t bp_num)
{
syscall_error_t ret = {
.type = seL4_NoError

View file

@ -37,7 +37,7 @@ void Arch_breakpointThreadDelete(tcb_t *thread);
* context-saving memory block, and this function will write to that
* context-saving memory block instead.
*/
void setBreakpoint(arch_tcb_t *uds,
void setBreakpoint(tcb_t *t,
uint16_t bp_num,
word_t vaddr, word_t type, word_t size, word_t rw);
@ -61,7 +61,7 @@ typedef struct getBreakpointRet {
bool_t is_enabled;
} getBreakpoint_t;
getBreakpoint_t getBreakpoint(arch_tcb_t *uds, uint16_t bp_num);
getBreakpoint_t getBreakpoint(tcb_t *t, uint16_t bp_num);
/** Clears a breakpoint's configuration and disables it.
* @param bp_num Hardware breakpoint ID. Usually an integer from 0..N.
@ -71,15 +71,15 @@ getBreakpoint_t getBreakpoint(arch_tcb_t *uds, uint16_t bp_num);
* context-saving memory block, and this function will write to that
* context-saving memory block instead.
*/
void unsetBreakpoint(arch_tcb_t *uds, uint16_t bp_num);
void unsetBreakpoint(tcb_t *t, uint16_t bp_num);
bool_t configureSingleStepping(arch_tcb_t *uc,
bool_t configureSingleStepping(tcb_t *t,
uint16_t bp_num,
word_t n_instr,
bool_t is_reply);
static inline bool_t
singleStepFaultCounterReady(arch_tcb_t *uc)
singleStepFaultCounterReady(tcb_t *t)
{
/* For a single-step exception, the user may have specified a certain
* number of instructions to skip over before the next stop-point, so
@ -88,10 +88,10 @@ singleStepFaultCounterReady(arch_tcb_t *uc)
* We will check the counter's value when deciding whether or not to
* actually send a fault message to userspace.
*/
if (uc->tcbContext.breakpointState.n_instructions > 0) {
uc->tcbContext.breakpointState.n_instructions--;
if (t->tcbArch.tcbContext.breakpointState.n_instructions > 0) {
t->tcbArch.tcbContext.breakpointState.n_instructions--;
}
return uc->tcbContext.breakpointState.n_instructions == 0;
return t->tcbArch.tcbContext.breakpointState.n_instructions == 0;
}
#endif /* CONFIG_HARDWARE_DEBUG_API */

View file

@ -164,12 +164,12 @@ handleFaultReply(tcb_t *receiver, tcb_t *sender)
syscall_error_t res;
res = Arch_decodeConfigureSingleStepping(&receiver->tcbArch, 0, n_instrs, true);
res = Arch_decodeConfigureSingleStepping(receiver, 0, n_instrs, true);
if (res.type != seL4_NoError) {
return false;
};
configureSingleStepping(&receiver->tcbArch, 0, n_instrs, true);
configureSingleStepping(receiver, 0, n_instrs, true);
/* Replying will always resume the thread: the only variant behaviour
* is whether or not the thread will be resumed with stepping still

View file

@ -1364,7 +1364,7 @@ handleVMFault(tcb_t *thread, vm_fault_type_t vm_faultType)
current_fault = handleUserLevelDebugException(pc);
if (seL4_Fault_DebugException_get_exceptionReason(current_fault) == seL4_SingleStep
&& !singleStepFaultCounterReady(&thread->tcbArch)) {
&& !singleStepFaultCounterReady(thread)) {
/* Don't send a fault message to the thread yet if we were asked
* to step through N instructions and the counter isn't depleted
* yet.

View file

@ -306,59 +306,59 @@ DEBUG_GENERATE_WRITE_FN(writeWvrCp, DBGWVR)
* context and not from the hardware registers.
*/
static word_t
readBcrContext(arch_tcb_t *at, uint16_t index)
readBcrContext(tcb_t *t, uint16_t index)
{
assert(index < seL4_NumExclusiveBreakpoints);
return at->tcbContext.breakpointState.breakpoint[index].cr;
return t->tcbArch.tcbContext.breakpointState.breakpoint[index].cr;
}
static word_t
readBvrContext(arch_tcb_t *at, uint16_t index)
readBvrContext(tcb_t *t, uint16_t index)
{
assert(index < seL4_NumExclusiveBreakpoints);
return at->tcbContext.breakpointState.breakpoint[index].vr;
return t->tcbArch.tcbContext.breakpointState.breakpoint[index].vr;
}
static word_t
readWcrContext(arch_tcb_t *at, uint16_t index)
readWcrContext(tcb_t *t, uint16_t index)
{
assert(index < seL4_NumExclusiveWatchpoints);
return at->tcbContext.breakpointState.watchpoint[index].cr;
return t->tcbArch.tcbContext.breakpointState.watchpoint[index].cr;
}
static word_t
readWvrContext(arch_tcb_t *at, uint16_t index)
readWvrContext(tcb_t *t, uint16_t index)
{
assert(index < seL4_NumExclusiveWatchpoints);
return at->tcbContext.breakpointState.watchpoint[index].vr;
return t->tcbArch.tcbContext.breakpointState.watchpoint[index].vr;
}
static void
writeBcrContext(arch_tcb_t *at, uint16_t index, word_t val)
writeBcrContext(tcb_t *t, uint16_t index, word_t val)
{
assert(index < seL4_NumExclusiveBreakpoints);
at->tcbContext.breakpointState.breakpoint[index].cr = val;
t->tcbArch.tcbContext.breakpointState.breakpoint[index].cr = val;
}
static void
writeBvrContext(arch_tcb_t *at, uint16_t index, word_t val)
writeBvrContext(tcb_t *t, uint16_t index, word_t val)
{
assert(index < seL4_NumExclusiveBreakpoints);
at->tcbContext.breakpointState.breakpoint[index].vr = val;
t->tcbArch.tcbContext.breakpointState.breakpoint[index].vr = val;
}
static void
writeWcrContext(arch_tcb_t *at, uint16_t index, word_t val)
writeWcrContext(tcb_t *t, uint16_t index, word_t val)
{
assert(index < seL4_NumExclusiveWatchpoints);
at->tcbContext.breakpointState.watchpoint[index].cr = val;
t->tcbArch.tcbContext.breakpointState.watchpoint[index].cr = val;
}
static void
writeWvrContext(arch_tcb_t *at, uint16_t index, word_t val)
writeWvrContext(tcb_t *t, uint16_t index, word_t val)
{
assert(index < seL4_NumExclusiveWatchpoints);
at->tcbContext.breakpointState.watchpoint[index].vr = val;
t->tcbArch.tcbContext.breakpointState.watchpoint[index].vr = val;
}
#endif /* !defined(CONFIG_VERIFICATION_BUILD) && (CONFIG_HARDWARE_DEBUG_API || CONFIG_ARM_HYPERVISOR_SUPPORT) */
@ -394,16 +394,16 @@ dumpBpsAndWpsCp(int nBp, int nWp)
* @param mWp Number of WP regs to print, beginning at WP #0.
*/
UNUSED static void
dumpBpsAndWpsContext(arch_tcb_t *at, int nBp, int nWp)
dumpBpsAndWpsContext(tcb_t *t, int nBp, int nWp)
{
int i;
for (i = 0; i < nBp; i++) {
userError("Ctxt BP %d: Bcr %lx, Bvr %lx", i, readBcrContext(at, i), readBvrContext(at, i));
userError("Ctxt BP %d: Bcr %lx, Bvr %lx", i, readBcrContext(t, i), readBvrContext(t, i));
}
for (i = 0; i < nWp; i++) {
userError("Ctxt WP %d: Wcr %lx, Wvr %lx", i, readWcrContext(at, i), readWvrContext(at, i));
userError("Ctxt WP %d: Wcr %lx, Wvr %lx", i, readWcrContext(t, i), readWvrContext(t, i));
}
}
@ -547,7 +547,7 @@ getMethodOfEntry(void)
* All documented in the seL4 API Manuals.
*/
void
setBreakpoint(arch_tcb_t *at,
setBreakpoint(tcb_t *t,
uint16_t bp_num,
word_t vaddr, word_t type, word_t size, word_t rw)
{
@ -576,23 +576,23 @@ setBreakpoint(arch_tcb_t *at,
if (type == seL4_InstructionBreakpoint) {
dbg_bcr_t bcr;
writeBvrContext(at, bp_num, vaddr);
writeBvrContext(t, bp_num, vaddr);
/* Preserve reserved bits. */
bcr.words[0] = readBcrContext(at, bp_num);
bcr.words[0] = readBcrContext(t, bp_num);
bcr = dbg_bcr_set_enabled(bcr, 1);
bcr = dbg_bcr_set_linkedBrp(bcr, 0);
bcr = dbg_bcr_set_supervisorAccess(bcr, DBGBCR_PRIV_USER);
bcr = dbg_bcr_set_byteAddressSelect(bcr, convertSizeToArch(4));
bcr = Arch_setupBcr(bcr, true);
writeBcrContext(at, bp_num, bcr.words[0]);
writeBcrContext(t, bp_num, bcr.words[0]);
} else {
dbg_wcr_t wcr;
writeWvrContext(at, bp_num, vaddr);
writeWvrContext(t, bp_num, vaddr);
/* Preserve reserved bits */
wcr.words[0] = readWcrContext(at, bp_num);
wcr.words[0] = readWcrContext(t, bp_num);
wcr = dbg_wcr_set_enabled(wcr, 1);
wcr = dbg_wcr_set_supervisorAccess(wcr, DBGWCR_PRIV_USER);
wcr = dbg_wcr_set_byteAddressSelect(wcr, convertSizeToArch(size));
@ -600,7 +600,7 @@ setBreakpoint(arch_tcb_t *at,
wcr = dbg_wcr_set_enableLinking(wcr, 0);
wcr = dbg_wcr_set_linkedBrp(wcr, 0);
wcr = Arch_setupWcr(wcr);
writeWcrContext(at, bp_num, wcr.words[0]);
writeWcrContext(t, bp_num, wcr.words[0]);
}
}
@ -616,7 +616,7 @@ setBreakpoint(arch_tcb_t *at,
* breakpoint.
*/
getBreakpoint_t
getBreakpoint(arch_tcb_t *at, uint16_t bp_num)
getBreakpoint(tcb_t *t, uint16_t bp_num)
{
getBreakpoint_t ret;
@ -626,21 +626,21 @@ getBreakpoint(arch_tcb_t *at, uint16_t bp_num)
if (ret.type == seL4_InstructionBreakpoint) {
dbg_bcr_t bcr;
bcr.words[0] = readBcrContext(at, bp_num);
bcr.words[0] = readBcrContext(t, bp_num);
if (Arch_breakpointIsMismatch(bcr) == true) {
ret.type = seL4_SingleStep;
};
ret.size = 0;
ret.rw = seL4_BreakOnRead;
ret.vaddr = readBvrContext(at, bp_num);
ret.vaddr = readBvrContext(t, bp_num);
ret.is_enabled = dbg_bcr_get_enabled(bcr);
} else {
dbg_wcr_t wcr;
wcr.words[0] = readWcrContext(at, bp_num);
wcr.words[0] = readWcrContext(t, bp_num);
ret.size = convertArchToSize(dbg_wcr_get_byteAddressSelect(wcr));
ret.rw = convertArchToAccess(dbg_wcr_get_loadStore(wcr));
ret.vaddr = readWvrContext(at, bp_num);
ret.vaddr = readWvrContext(t, bp_num);
ret.is_enabled = dbg_wcr_get_enabled(wcr);
}
return ret;
@ -652,7 +652,7 @@ getBreakpoint(arch_tcb_t *at, uint16_t bp_num)
* @param bp_num The hardware breakpoint you want to disable+clear.
*/
void
unsetBreakpoint(arch_tcb_t *at, uint16_t bp_num)
unsetBreakpoint(tcb_t *t, uint16_t bp_num)
{
word_t type;
@ -662,17 +662,17 @@ unsetBreakpoint(arch_tcb_t *at, uint16_t bp_num)
if (type == seL4_InstructionBreakpoint) {
dbg_bcr_t bcr;
bcr.words[0] = readBcrContext(at, bp_num);
bcr.words[0] = readBcrContext(t, bp_num);
bcr = dbg_bcr_set_enabled(bcr, 0);
writeBcrContext(at, bp_num, bcr.words[0]);
writeBvrContext(at, bp_num, 0);
writeBcrContext(t, bp_num, bcr.words[0]);
writeBvrContext(t, bp_num, 0);
} else {
dbg_wcr_t wcr;
wcr.words[0] = readWcrContext(at, bp_num);
wcr.words[0] = readWcrContext(t, bp_num);
wcr = dbg_wcr_set_enabled(wcr, 0);
writeWcrContext(at, bp_num, wcr.words[0]);
writeWvrContext(at, bp_num, 0);
writeWcrContext(t, bp_num, wcr.words[0]);
writeWvrContext(t, bp_num, 0);
}
}
@ -683,7 +683,7 @@ unsetBreakpoint(arch_tcb_t *at, uint16_t bp_num)
* @param n_instr The number of instructions to step over.
*/
bool_t
configureSingleStepping(arch_tcb_t *at,
configureSingleStepping(tcb_t *t,
uint16_t bp_num,
word_t n_instr,
bool_t is_reply)
@ -697,7 +697,7 @@ configureSingleStepping(arch_tcb_t *at,
*/
if (is_reply) {
bp_num = at->tcbContext.breakpointState.single_step_hw_bp_num;
bp_num = t->tcbArch.tcbContext.breakpointState.single_step_hw_bp_num;
} else {
bp_num = convertBpNumToArch(bp_num);
}
@ -714,17 +714,17 @@ configureSingleStepping(arch_tcb_t *at,
*/
dbg_bcr_t bcr;
bcr.words[0] = readBcrContext(at, bp_num);
bcr.words[0] = readBcrContext(t, bp_num);
/* If the user calls us with n_instr == 0, allow them to configure, but
* leave it disabled.
*/
if (n_instr > 0) {
bcr = dbg_bcr_set_enabled(bcr, 1);
at->tcbContext.breakpointState.single_step_enabled = true;
t->tcbArch.tcbContext.breakpointState.single_step_enabled = true;
} else {
bcr = dbg_bcr_set_enabled(bcr, 0);
at->tcbContext.breakpointState.single_step_enabled = false;
t->tcbArch.tcbContext.breakpointState.single_step_enabled = false;
}
bcr = dbg_bcr_set_linkedBrp(bcr, 0);
@ -732,11 +732,11 @@ configureSingleStepping(arch_tcb_t *at,
bcr = dbg_bcr_set_byteAddressSelect(bcr, convertSizeToArch(1));
bcr = Arch_setupBcr(bcr, false);
writeBvrContext(at, bp_num, 0);
writeBcrContext(at, bp_num, bcr.words[0]);
writeBvrContext(t, bp_num, 0);
writeBcrContext(t, bp_num, bcr.words[0]);
at->tcbContext.breakpointState.n_instructions = n_instr;
at->tcbContext.breakpointState.single_step_hw_bp_num = bp_num;
t->tcbArch.tcbContext.breakpointState.n_instructions = n_instr;
t->tcbArch.tcbContext.breakpointState.single_step_hw_bp_num = bp_num;
return true;
}
@ -1195,9 +1195,9 @@ handleUserLevelDebugException(word_t fault_vaddr)
* coprocessor.
*/
void
Arch_initBreakpointContext(user_breakpoint_state_t *uds)
Arch_initBreakpointContext(user_context_t *uc)
{
*uds = armKSNullBreakpointState;
uc->breakpointState = armKSNullBreakpointState;
}
void
@ -1242,20 +1242,20 @@ loadAllDisabledBreakpointState(void)
* associateVcpu.
*/
void
saveAllBreakpointState(arch_tcb_t *at)
saveAllBreakpointState(tcb_t *t)
{
int i;
assert(at != NULL);
assert(t != NULL);
for (i = 0; i < seL4_NumExclusiveBreakpoints; i++) {
writeBvrContext(at, i, readBvrCp(i));
writeBcrContext(at, i, readBcrCp(i));
writeBvrContext(t, i, readBvrCp(i));
writeBcrContext(t, i, readBcrCp(i));
}
for (i = 0; i < seL4_NumExclusiveWatchpoints; i++) {
writeWvrContext(at, i, readWvrCp(i));
writeWcrContext(at, i, readWcrCp(i));
writeWvrContext(t, i, readWvrCp(i));
writeWcrContext(t, i, readWcrCp(i));
}
}
@ -1278,16 +1278,16 @@ Arch_debugDissociateVCPUTCB(tcb_t *t)
}
static void
loadBreakpointState(arch_tcb_t *at)
loadBreakpointState(tcb_t *t)
{
int i;
assert(at != NULL);
assert(t != NULL);
for (i = 0; i < seL4_NumExclusiveBreakpoints; i++) {
if (at->tcbContext.breakpointState.used_breakpoints_bf & BIT(i)) {
writeBvrCp(i, readBvrContext(at, i));
writeBcrCp(i, readBcrContext(at, i));
if (t->tcbArch.tcbContext.breakpointState.used_breakpoints_bf & BIT(i)) {
writeBvrCp(i, readBvrContext(t, i));
writeBcrCp(i, readBcrContext(t, i));
} else {
/* If the thread isn't using the BP, then just load
* a default "disabled" state.
@ -1297,10 +1297,10 @@ loadBreakpointState(arch_tcb_t *at)
}
for (i = 0; i < seL4_NumExclusiveWatchpoints; i++) {
if (at->tcbContext.breakpointState.used_breakpoints_bf &
if (t->tcbArch.tcbContext.breakpointState.used_breakpoints_bf &
BIT(i + seL4_NumExclusiveBreakpoints)) {
writeWvrCp(i, readWvrContext(at, i));
writeWcrCp(i, readWcrContext(at, i));
writeWvrCp(i, readWvrContext(t, i));
writeWcrCp(i, readWcrContext(t, i));
} else {
writeWcrCp(i, readWcrCp(i) & ~DBGWCR_ENABLE);
}
@ -1319,7 +1319,7 @@ restore_user_debug_context(tcb_t *target_thread)
if (target_thread->tcbArch.tcbContext.breakpointState.used_breakpoints_bf == 0) {
loadAllDisabledBreakpointState();
} else {
loadBreakpointState(&target_thread->tcbArch);
loadBreakpointState(target_thread);
}
/* ARMv6 manual, sec D3.3.7:

View file

@ -532,7 +532,7 @@ vcpu_save(vcpu_t *vcpu, bool_t active)
* not exporting the debug API, because in that case, native
* threads can't modify the debug registers (i.e, without the API).
*/
saveAllBreakpointState(&vcpu->vcpuTCB->tcbArch);
saveAllBreakpointState(vcpu->vcpuTCB);
#endif
isb();
}
@ -851,7 +851,7 @@ vcpu_switch(vcpu_t *new)
} else if (unlikely(armHSVCPUActive)) {
/* leave the current VCPU state loaded, but disable vgic and mmu */
#ifndef CONFIG_VERIFICATION_BUILD
saveAllBreakpointState(&armHSCurVCPU->vcpuTCB->tcbArch);
saveAllBreakpointState(armHSCurVCPU->vcpuTCB);
#endif
vcpu_disable(armHSCurVCPU);
armHSVCPUActive = false;

View file

@ -72,25 +72,25 @@ bitwiseAndDr6Reg(word_t mask)
}
static inline word_t
readDr7Context(arch_tcb_t *uds)
readDr7Context(tcb_t *t)
{
return uds->tcbContext.breakpointState.dr[5];
return t->tcbArch.tcbContext.breakpointState.dr[5];
}
static inline void
bitwiseOrDr7Context(arch_tcb_t *uds, word_t val)
bitwiseOrDr7Context(tcb_t *t, word_t val)
{
uds->tcbContext.breakpointState.dr[5] |= val;
t->tcbArch.tcbContext.breakpointState.dr[5] |= val;
}
static inline void
bitwiseAndDr7Context(arch_tcb_t *uds, word_t mask)
bitwiseAndDr7Context(tcb_t *t, word_t mask)
{
uds->tcbContext.breakpointState.dr[5] &= mask;
t->tcbArch.tcbContext.breakpointState.dr[5] &= mask;
}
static void
unsetDr7BitsFor(arch_tcb_t *uds, uint16_t bp_num)
unsetDr7BitsFor(tcb_t *t, uint16_t bp_num)
{
word_t mask;
@ -111,7 +111,7 @@ unsetDr7BitsFor(arch_tcb_t *uds, uint16_t bp_num)
}
mask = ~mask;
bitwiseAndDr7Context(uds, mask);
bitwiseAndDr7Context(t, mask);
}
/** Converts an seL4_BreakpointType value into the underlying hardware
@ -306,11 +306,11 @@ convertArchToSize(word_t dr7, uint16_t bp_num)
* @param bp_num Hardware breakpoint ID. Usually an integer from 0..N.
*/
static void
enableBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
enableBreakpoint(tcb_t *t, uint16_t bp_num)
{
word_t enable_bit;
assert(uds != NULL);
assert(t != NULL);
assert(bp_num < X86_DEBUG_BP_N_REGS);
switch (bp_num) {
@ -328,18 +328,18 @@ enableBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
break;
}
bitwiseOrDr7Context(uds, enable_bit);
bitwiseOrDr7Context(t, enable_bit);
}
/** Disables a breakpoint without clearing its configuration.
* @param bp_num Hardware breakpoint ID. Usually an integer from 0..N.
*/
static void
disableBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
disableBreakpoint(tcb_t *t, uint16_t bp_num)
{
word_t disable_mask;
assert(uds != NULL);
assert(t != NULL);
assert(bp_num < X86_DEBUG_BP_N_REGS);
switch (bp_num) {
@ -357,21 +357,21 @@ disableBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
break;
}
bitwiseAndDr7Context(uds, disable_mask);
bitwiseAndDr7Context(t, disable_mask);
}
/** Returns a boolean for whether or not a breakpoint is enabled.
* @param bp_num Hardware breakpoint ID. Usually an integer from 0..N.
*/
static bool_t
breakpointIsEnabled(arch_tcb_t *uds, uint16_t bp_num)
breakpointIsEnabled(tcb_t *t, uint16_t bp_num)
{
word_t dr7;
assert(uds != NULL);
assert(t != NULL);
assert(bp_num < X86_DEBUG_BP_N_REGS);
dr7 = readDr7Context(uds);
dr7 = readDr7Context(t);
switch (bp_num) {
case 0:
return !!(dr7 & X86_DEBUG_BP0_ENABLE_BIT);
@ -385,22 +385,24 @@ breakpointIsEnabled(arch_tcb_t *uds, uint16_t bp_num)
}
static void
setBpVaddrContext(user_breakpoint_state_t *uds, uint16_t bp_num, word_t vaddr)
setBpVaddrContext(tcb_t *t, uint16_t bp_num, word_t vaddr)
{
assert(uds != NULL);
assert(t != NULL);
user_breakpoint_state_t *ubs = &t->tcbArch.tcbContext.breakpointState;
switch (bp_num) {
case 0:
uds->dr[0] = vaddr;
ubs->dr[0] = vaddr;
break;
case 1:
uds->dr[1] = vaddr;
ubs->dr[1] = vaddr;
break;
case 2:
uds->dr[2] = vaddr;
ubs->dr[2] = vaddr;
break;
default:
assert(bp_num == 3);
uds->dr[3] = vaddr;
ubs->dr[3] = vaddr;
break;
}
return;
@ -418,36 +420,38 @@ setBpVaddrContext(user_breakpoint_state_t *uds, uint16_t bp_num, word_t vaddr)
* @param rw Access type that should trigger the BP (read/write).
*/
void
setBreakpoint(arch_tcb_t *uds,
setBreakpoint(tcb_t *t,
uint16_t bp_num, word_t vaddr, word_t types, word_t size, word_t rw)
{
word_t dr7val;
assert(uds != NULL);
assert(t != NULL);
dr7val = convertTypeAndAccessToArch(bp_num, types, rw);
dr7val |= convertSizeToArch(bp_num, types, size);
setBpVaddrContext(&uds->tcbContext.breakpointState, bp_num, vaddr);
unsetDr7BitsFor(uds, bp_num);
bitwiseOrDr7Context(uds, dr7val);
enableBreakpoint(uds, bp_num);
setBpVaddrContext(t, bp_num, vaddr);
unsetDr7BitsFor(t, bp_num);
bitwiseOrDr7Context(t, dr7val);
enableBreakpoint(t, bp_num);
}
static word_t
getBpVaddrContext(user_breakpoint_state_t *uds, uint16_t bp_num)
getBpVaddrContext(tcb_t *t, uint16_t bp_num)
{
assert(uds != NULL);
assert(t != NULL);
user_breakpoint_state_t *ubs = &t->tcbArch.tcbContext.breakpointState;
switch (bp_num) {
case 0:
return uds->dr[0];
return ubs->dr[0];
case 1:
return uds->dr[1];
return ubs->dr[1];
case 2:
return uds->dr[2];
return ubs->dr[2];
default:
assert(bp_num == 3);
return uds->dr[3];
return ubs->dr[3];
}
}
@ -461,19 +465,19 @@ getBpVaddrContext(user_breakpoint_state_t *uds, uint16_t bp_num)
* @return Structure containing information about the status of the breakpoint.
*/
getBreakpoint_t
getBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
getBreakpoint(tcb_t *t, uint16_t bp_num)
{
word_t dr7val;
getBreakpoint_t ret;
convertedTypeAndAccess_t res;
dr7val = readDr7Context(uds);
ret.vaddr = getBpVaddrContext(&uds->tcbContext.breakpointState, bp_num);
dr7val = readDr7Context(t);
ret.vaddr = getBpVaddrContext(t, bp_num);
ret.size = convertArchToSize(dr7val, bp_num);
res = convertArchToTypeAndAccess(dr7val, bp_num);
ret.type = res.type;
ret.rw = res.rw;
ret.is_enabled = breakpointIsEnabled(uds, bp_num);
ret.is_enabled = breakpointIsEnabled(t, bp_num);
return ret;
}
@ -484,11 +488,11 @@ getBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
* @param bp_num The hardware breakpoint ID you'd like to clear.
*/
void
unsetBreakpoint(arch_tcb_t *uds, uint16_t bp_num)
unsetBreakpoint(tcb_t *t, uint16_t bp_num)
{
disableBreakpoint(uds, bp_num);
unsetDr7BitsFor(uds, bp_num);
setBpVaddrContext(&uds->tcbContext.breakpointState, bp_num, 0);
disableBreakpoint(t, bp_num);
unsetDr7BitsFor(t, bp_num);
setBpVaddrContext(t, bp_num, 0);
}
/** Used in the exception path to determine if an exception was caused by
@ -504,7 +508,7 @@ typedef struct {
} testAndResetSingleStepException_t;
static testAndResetSingleStepException_t
testAndResetSingleStepException(arch_tcb_t *uc)
testAndResetSingleStepException(tcb_t *t)
{
testAndResetSingleStepException_t ret;
word_t dr6;
@ -516,7 +520,7 @@ testAndResetSingleStepException(arch_tcb_t *uc)
}
ret.ret = true;
ret.instr_vaddr = uc->tcbContext.registers[FaultIP];
ret.instr_vaddr = t->tcbArch.tcbContext.registers[FaultIP];
bitwiseAndDr6Reg(~X86_DEBUG_DR6_SINGLE_STEP_FLAG);
/* And that's not all: if the breakpoint is an instruction breakpoint, we
@ -531,12 +535,12 @@ testAndResetSingleStepException(arch_tcb_t *uc)
* Intel manuals, vol3, section 17.3.1.1.
*/
/* This will automatically be popped by restore_user_context() */
uc->tcbContext.registers[FLAGS] |= X86_DEBUG_EFLAGS_RESUME_FLAG;
t->tcbArch.tcbContext.registers[FLAGS] |= X86_DEBUG_EFLAGS_RESUME_FLAG;
return ret;
}
bool_t
configureSingleStepping(arch_tcb_t *uc, uint16_t bp_num, word_t n_instr,
configureSingleStepping(tcb_t *t, uint16_t bp_num, word_t n_instr,
UNUSED bool_t is_reply)
{
/* On x86 no hardware breakpoints are needed for single stepping. */
@ -544,13 +548,13 @@ configureSingleStepping(arch_tcb_t *uc, uint16_t bp_num, word_t n_instr,
/* If n_instr (number of instructions to single-step) is 0, that is the
* same as requesting that single-stepping be disabled.
*/
uc->tcbContext.breakpointState.single_step_enabled = false;
uc->tcbContext.registers[FLAGS] &= ~X86_DEBUG_EFLAGS_TRAP_FLAG;
t->tcbArch.tcbContext.breakpointState.single_step_enabled = false;
t->tcbArch.tcbContext.registers[FLAGS] &= ~X86_DEBUG_EFLAGS_TRAP_FLAG;
} else {
uc->tcbContext.breakpointState.single_step_enabled = true;
t->tcbArch.tcbContext.breakpointState.single_step_enabled = true;
}
uc->tcbContext.breakpointState.n_instructions = n_instr;
t->tcbArch.tcbContext.breakpointState.n_instructions = n_instr;
return false;
}
@ -576,7 +580,7 @@ typedef struct {
} getAndResetActiveBreakpoint_t;
static getAndResetActiveBreakpoint_t
getAndResetActiveBreakpoint(arch_tcb_t *at)
getAndResetActiveBreakpoint(tcb_t *t)
{
convertedTypeAndAccess_t tmp;
getAndResetActiveBreakpoint_t ret;
@ -596,8 +600,8 @@ getAndResetActiveBreakpoint(arch_tcb_t *at)
return ret;
}
tmp = convertArchToTypeAndAccess(readDr7Context(at), ret.bp_num);
ret.vaddr = getBpVaddrContext(&at->tcbContext.breakpointState, ret.bp_num);
tmp = convertArchToTypeAndAccess(readDr7Context(t), ret.bp_num);
ret.vaddr = getBpVaddrContext(t, ret.bp_num);
ret.reason = tmp.type;
bitwiseAndDr6Reg(~BIT(ret.bp_num));
@ -607,7 +611,7 @@ getAndResetActiveBreakpoint(arch_tcb_t *at)
exception_t
handleUserLevelDebugException(int int_vector)
{
arch_tcb_t *context;
tcb_t *ct;
getAndResetActiveBreakpoint_t active_bp;
testAndResetSingleStepException_t single_step_info;
@ -622,7 +626,7 @@ handleUserLevelDebugException(int int_vector)
benchmark_track_start();
#endif
context = &NODE_STATE(ksCurThread)->tcbArch;
ct = NODE_STATE(ksCurThread);
/* Software break request (INT3) is detected by the vector number */
if (int_vector == int_software_break_request) {
@ -630,20 +634,20 @@ handleUserLevelDebugException(int int_vector)
0, seL4_SoftwareBreakRequest);
} else {
/* Hardware breakpoint trigger is detected using DR6 */
active_bp = getAndResetActiveBreakpoint(context);
active_bp = getAndResetActiveBreakpoint(ct);
if (active_bp.bp_num >= 0) {
current_fault = seL4_Fault_DebugException_new(active_bp.vaddr,
active_bp.bp_num,
active_bp.reason);
} else {
single_step_info = testAndResetSingleStepException(context);
single_step_info = testAndResetSingleStepException(ct);
if (single_step_info.ret == true) {
/* If the caller asked us to skip over N instructions before
* generating the next single-step breakpoint, we shouldn't
* bother to construct a fault message until we've skipped N
* instructions.
*/
if (singleStepFaultCounterReady(context) == false) {
if (singleStepFaultCounterReady(ct) == false) {
return EXCEPTION_NONE;
}
current_fault = seL4_Fault_DebugException_new(single_step_info.instr_vaddr,

View file

@ -389,17 +389,17 @@ decodeSetAffinity(cap_t cap, word_t length, word_t *buffer)
#ifdef CONFIG_HARDWARE_DEBUG_API
static exception_t
invokeConfigureSingleStepping(word_t *buffer, arch_tcb_t *context,
invokeConfigureSingleStepping(word_t *buffer, tcb_t *t,
uint16_t bp_num, word_t n_instrs)
{
bool_t bp_was_consumed;
bp_was_consumed = configureSingleStepping(context, bp_num, n_instrs, false);
bp_was_consumed = configureSingleStepping(t, bp_num, n_instrs, false);
if (n_instrs == 0) {
unsetBreakpointUsedFlag(context, bp_num);
unsetBreakpointUsedFlag(t, bp_num);
setMR(NODE_STATE(ksCurThread), buffer, 0, false);
} else {
setBreakpointUsedFlag(context, bp_num);
setBreakpointUsedFlag(t, bp_num);
setMR(NODE_STATE(ksCurThread), buffer, 0, bp_was_consumed);
}
return EXCEPTION_NONE;
@ -411,32 +411,30 @@ decodeConfigureSingleStepping(cap_t cap, word_t *buffer)
uint16_t bp_num;
word_t n_instrs;
tcb_t *tcb;
arch_tcb_t *context;
syscall_error_t syserr;
tcb = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap));
context = &tcb->tcbArch;
bp_num = getSyscallArg(0, buffer);
n_instrs = getSyscallArg(1, buffer);
syserr = Arch_decodeConfigureSingleStepping(context, bp_num, n_instrs, false);
syserr = Arch_decodeConfigureSingleStepping(tcb, bp_num, n_instrs, false);
if (syserr.type != seL4_NoError) {
current_syscall_error = syserr;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeConfigureSingleStepping(buffer, context, bp_num, n_instrs);
return invokeConfigureSingleStepping(buffer, tcb, bp_num, n_instrs);
}
static exception_t
invokeSetBreakpoint(arch_tcb_t *context, uint16_t bp_num,
invokeSetBreakpoint(tcb_t *tcb, uint16_t bp_num,
word_t vaddr, word_t type, word_t size, word_t rw)
{
setBreakpoint(context, bp_num, vaddr, type, size, rw);
setBreakpoint(tcb, bp_num, vaddr, type, size, rw);
/* Signal restore_user_context() to pop the breakpoint context on return. */
setBreakpointUsedFlag(context, bp_num);
setBreakpointUsedFlag(tcb, bp_num);
return EXCEPTION_NONE;
}
@ -446,7 +444,6 @@ decodeSetBreakpoint(cap_t cap, word_t *buffer)
uint16_t bp_num;
word_t vaddr, type, size, rw;
tcb_t *tcb;
arch_tcb_t *context;
syscall_error_t error;
tcb = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap));
@ -548,25 +545,23 @@ decodeSetBreakpoint(cap_t cap, word_t *buffer)
return EXCEPTION_SYSCALL_ERROR;
}
context = &tcb->tcbArch;
error = Arch_decodeSetBreakpoint(context, bp_num, vaddr, type, size, rw);
error = Arch_decodeSetBreakpoint(tcb, bp_num, vaddr, type, size, rw);
if (error.type != seL4_NoError) {
current_syscall_error = error;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeSetBreakpoint(context, bp_num,
return invokeSetBreakpoint(tcb, bp_num,
vaddr, type, size, rw);
}
static exception_t
invokeGetBreakpoint(word_t *buffer, arch_tcb_t *context, uint16_t bp_num)
invokeGetBreakpoint(word_t *buffer, tcb_t *tcb, uint16_t bp_num)
{
getBreakpoint_t res;
res = getBreakpoint(context, bp_num);
res = getBreakpoint(tcb, bp_num);
setMR(NODE_STATE(ksCurThread), buffer, 0, res.vaddr);
setMR(NODE_STATE(ksCurThread), buffer, 1, res.type);
setMR(NODE_STATE(ksCurThread), buffer, 2, res.size);
@ -580,30 +575,27 @@ decodeGetBreakpoint(cap_t cap, word_t *buffer)
{
tcb_t *tcb;
uint16_t bp_num;
arch_tcb_t *context;
syscall_error_t error;
tcb = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap));
bp_num = getSyscallArg(0, buffer);
context = &tcb->tcbArch;
error = Arch_decodeGetBreakpoint(context, bp_num);
error = Arch_decodeGetBreakpoint(tcb, bp_num);
if (error.type != seL4_NoError) {
current_syscall_error = error;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeGetBreakpoint(buffer, context, bp_num);
return invokeGetBreakpoint(buffer, tcb, bp_num);
}
static exception_t
invokeUnsetBreakpoint(arch_tcb_t *context, uint16_t bp_num)
invokeUnsetBreakpoint(tcb_t *tcb, uint16_t bp_num)
{
/* Maintain the bitfield of in-use breakpoints. */
unsetBreakpoint(context, bp_num);
unsetBreakpointUsedFlag(context, bp_num);
unsetBreakpoint(tcb, bp_num);
unsetBreakpointUsedFlag(tcb, bp_num);
return EXCEPTION_NONE;
}
@ -612,22 +604,19 @@ decodeUnsetBreakpoint(cap_t cap, word_t *buffer)
{
tcb_t *tcb;
uint16_t bp_num;
arch_tcb_t *context;
syscall_error_t error;
tcb = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap));
bp_num = getSyscallArg(0, buffer);
context = &tcb->tcbArch;
error = Arch_decodeUnsetBreakpoint(context, bp_num);
error = Arch_decodeUnsetBreakpoint(tcb, bp_num);
if (error.type != seL4_NoError) {
current_syscall_error = error;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeUnsetBreakpoint(context, bp_num);
return invokeUnsetBreakpoint(tcb, bp_num);
}
#endif /* CONFIG_HARDWARE_DEBUG_API */