diff --git a/testing/debug/CMakeLists.txt b/testing/debug/CMakeLists.txt new file mode 100644 index 00000000000..bf8a2ab4804 --- /dev/null +++ b/testing/debug/CMakeLists.txt @@ -0,0 +1,31 @@ +# ############################################################################## +# apps/testing/debug/CMakeLists.txt +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# ############################################################################## + +if(CONFIG_TESTING_DEBUG) + nuttx_add_application( + NAME + ${CONFIG_TESTING_DEBUG_PROGNAME} + SRCS + debug.c + STACKSIZE + ${CONFIG_TESTING_DEBUG_STACKSIZE} + PRIORITY + ${CONFIG_TESTING_DEBUG_PRIORITY}) +endif() diff --git a/testing/debug/Kconfig b/testing/debug/Kconfig new file mode 100644 index 00000000000..5fb7b3417a5 --- /dev/null +++ b/testing/debug/Kconfig @@ -0,0 +1,32 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config TESTING_DEBUG + tristate "Debug test" + default n + depends on ARCH_HAVE_DEBUG + depends on LIB_GDBSTUB + ---help--- + Enable the DEBUG test program. It is a simple + test case of the NuttX debugging facilities. + +if TESTING_DEBUG + +config TESTING_DEBUG_PROGNAME + string "Program name" + default "debug" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config TESTING_DEBUG_PRIORITY + int "Task priority" + default 100 + +config TESTING_DEBUG_STACKSIZE + int "Stack size" + default DEFAULT_TASK_STACKSIZE + +endif diff --git a/testing/debug/Make.defs b/testing/debug/Make.defs new file mode 100644 index 00000000000..bbac6f8b25d --- /dev/null +++ b/testing/debug/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/testing/debug/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_TESTING_DEBUG),) +CONFIGURED_APPS += $(APPDIR)/testing/debug +endif diff --git a/testing/debug/Makefile b/testing/debug/Makefile new file mode 100644 index 00000000000..4befa9d0f8d --- /dev/null +++ b/testing/debug/Makefile @@ -0,0 +1,34 @@ +############################################################################ +# apps/testing/debug/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +# debug built-in application info + +PROGNAME = $(CONFIG_TESTING_DEBUG_PROGNAME) +PRIORITY = $(CONFIG_TESTING_DEBUG_PRIORITY) +STACKSIZE = $(CONFIG_TESTING_DEBUG_STACKSIZE) +MODULE = $(CONFIG_TESTING_DEBUG) + +# debug Example + +MAINSRC = debug.c + +include $(APPDIR)/Application.mk diff --git a/testing/debug/debug.c b/testing/debug/debug.c new file mode 100644 index 00000000000..f43a5715f53 --- /dev/null +++ b/testing/debug/debug.c @@ -0,0 +1,270 @@ +/**************************************************************************** + * apps/testing/debug/debug.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static uint8_t g_test_data[8]; +static const char g_test_rodata[] = "This is a read-only string"; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: trigger_func1 + ****************************************************************************/ + +static void test_trigger(void) +{ + printf("Calling test_trigger\n"); +} + +/**************************************************************************** + * Name: debug_callback + ****************************************************************************/ + +static void debug_callback(int type, FAR void *addr, size_t size, + FAR void *arg) +{ + *(bool *)arg = true; + gdb_debugpoint_remove(type, addr, size); +} + +/**************************************************************************** + * Name: test_function + ****************************************************************************/ + +static void test_function(void (*func)(void)) +{ + int ret = 0; + bool triggered; + printf("==== Calling test_function ====\n"); + + printf("Add breakpoint at %p\n", func); + ret = gdb_debugpoint_add(GDB_STOPREASON_BREAKPOINT, func, 0, + debug_callback, &triggered); + + if (ret != OK) + { + printf("ERROR: Registering breakpoint at %p failed with %d\n", + func, ret); + } + + /* Trigger the breakpoint */ + + triggered = false; + func(); + + if (triggered) + { + printf("Pass: Breakpoint at %p triggered\n", func); + } + else + { + gdb_debugpoint_remove(GDB_STOPREASON_BREAKPOINT, func, 0); + printf("ERROR: Breakpoint %p not triggered\n", func); + } +} + +/**************************************************************************** + * Name: test_dataread + ****************************************************************************/ + +static void test_data(uint8_t *addr, size_t size, bool r, bool w) +{ + int ret = 0; + int tmp; + int test_type; + bool triggered; + + printf("==== Calling test_data ====\n"); + + if (r && w) + { + test_type = GDB_STOPREASON_WATCHPOINT_RW; + printf("Add read/write watchpoint at %p\n", addr); + } + else if (r) + { + test_type = GDB_STOPREASON_WATCHPOINT_RO; + printf("Add read watchpoint at %p\n", addr); + } + else if (w) + { + test_type = GDB_STOPREASON_WATCHPOINT_WO; + printf("Add write watchpoint at %p\n", addr); + } + else + { + printf("ERROR: Invalid test type\n"); + return; + } + + ret = gdb_debugpoint_add(test_type, addr, size, + debug_callback, &triggered); + + if (ret != OK) + { + printf("ERROR: Registering read watchpoint at %p failed with %d\n", + addr, ret); + } + + if (r & w) + { + /* Trigger the watchpoint by reading the address */ + + triggered = false; + if (addr[0] == 0x55) + { + /* Do something to avoid compiler removing the read */ + + tmp = 0xaa; + } + else + { + tmp = 0x55; + } + + if (triggered) + { + printf("Pass: Read watchpoint at %p triggered\n", addr); + } + else + { + gdb_debugpoint_remove(test_type, addr, size); + printf("ERROR: Read watchpoint at %p not triggered\n", addr); + } + + /* Register the watchpoint again to test write watchpoints */ + + ret = gdb_debugpoint_add(test_type, addr, size, + debug_callback, &triggered); + + if (ret != OK) + { + printf("ERROR: Registering read/write watchpoint at %p" + " failed with %d\n", addr, ret); + } + + /* Trigger the watchpoint by writing to the address */ + + triggered = false; + addr[0] = tmp; + + if (triggered) + { + printf("Pass: Write watchpoint at %p triggered\n", addr); + } + else + { + gdb_debugpoint_remove(test_type, addr, size); + printf("ERROR: Write watchpoint at %p not triggered\n", addr); + } + } + else if (r) + { + /* Trigger the watchpoint by reading the address */ + + triggered = false; + if (addr[0] == 0x55) + { + /* Do something to avoid compiler removing the read */ + + printf("Reading %p\n", addr); + } + + if (triggered) + { + printf("Pass: Read watchpoint at %p triggered\n", addr); + } + else + { + gdb_debugpoint_remove(test_type, addr, size); + printf("ERROR: Read watchpoint at %p not triggered\n", addr); + } + } + else if (w) + { + /** Trigger the watchpoint by writing to the address */ + + triggered = false; + addr[0] = 0x55; + + if (triggered) + { + printf("Pass: Write watchpoint at %p triggered\n", addr); + } + else + { + gdb_debugpoint_remove(test_type, addr, size); + printf("ERROR: Write watchpoint at %p not triggered\n", addr); + } + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: main + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + printf("Testing breakpoints\n"); + + /* Test breakpoint at a function */ + + test_function(test_trigger); + + /* Test read watchpoint for rodata */ + + test_data((uint8_t *)&g_test_rodata, sizeof(g_test_rodata), true, false); + + /* Test read watchpoint for data */ + + test_data((uint8_t *)&g_test_data, sizeof(g_test_data), true, false); + + /* Test write watchpoint for data */ + + test_data((uint8_t *)&g_test_data, sizeof(g_test_data), false, true); + + /* Test read/write watchpoint for data */ + + test_data((uint8_t *)&g_test_data, sizeof(g_test_data), true, true); + + return 0; +}