/**************************************************************************** * drivers/serial/serial_gdbstub.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 #include #include #include #include /**************************************************************************** * Private Data ****************************************************************************/ struct uart_gdbstub_s { FAR struct uart_dev_s *dev; FAR struct gdb_state_s *state; FAR const struct uart_ops_s *org_ops; struct uart_ops_s ops; struct notifier_block nb; }; static FAR struct uart_gdbstub_s *g_uart_gdbstub; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: uart_gdbstub_panic_callback * * Description: * This is panic callback for gdbstub, If a crash occurs, * you can debug it through gdb * ****************************************************************************/ static int uart_gdbstub_panic_callback(FAR struct notifier_block *nb, unsigned long action, FAR void *data) { FAR struct uart_gdbstub_s *uart_gdbstub = container_of(nb, struct uart_gdbstub_s, nb); if (action != PANIC_KERNEL_FINAL) { return 0; } _alert("Enter panic gdbstub mode, plase use gdb connect to debug\n"); _alert("Please use gdb of the corresponding architecture to " "connect to nuttx"); _alert("such as: arm-none-eabi-gdb nuttx -ex \"set " "target-charset ASCII\" -ex \"target remote /dev/ttyUSB0\"\n"); gdb_console_message(uart_gdbstub->state, "Enter panic gdbstub mode!\n"); gdb_process(uart_gdbstub->state, GDB_STOPREASON_CTRLC, NULL); return 0; } /**************************************************************************** * Name: uart_gdbstub_ctrlc * * Description: * This is uart receive callback in interruption. * The function is to accept the initial connection of Ctrl c and gdb. * ****************************************************************************/ static int uart_gdbstub_ctrlc(FAR struct uart_dev_s *dev, FAR unsigned int *status) { uart_disablerxint(dev); gdb_process(g_uart_gdbstub->state, GDB_STOPREASON_CTRLC, NULL); uart_enablerxint(dev); return 0; } /**************************************************************************** * Name: uart_gdbstub_receive * * Description: * This is gdbstub receive char function. * ****************************************************************************/ static ssize_t uart_gdbstub_receive(FAR void *priv, FAR void *buf, size_t len) { FAR struct uart_gdbstub_s *uart_gdbstub = priv; FAR uart_dev_t *dev = uart_gdbstub->dev; FAR char *ptr = buf; unsigned int state; size_t i = 0; while (i < len) { if (uart_gdbstub->org_ops->rxavailable(dev)) { ptr[i++] = g_uart_gdbstub->org_ops->receive(dev, &state); } } return len; } /**************************************************************************** * Name: uart_gdbstub_send * * Description: * This is gdbstub send char function. * ****************************************************************************/ static ssize_t uart_gdbstub_send(FAR void *priv, FAR void *buf, size_t len) { FAR struct uart_gdbstub_s *uart_gdbstub = priv; FAR uart_dev_t *dev = uart_gdbstub->dev; size_t i = 0; while (i < len) { if (uart_gdbstub->org_ops->txready(dev)) { uart_gdbstub->org_ops->send(dev, ((FAR char *)buf)[i++]); } } return len; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: uart_gdbstub_register * * Description: * Use the uart device to register gdbstub. * gdbstub run with serial interrupt. * ****************************************************************************/ int uart_gdbstub_register(FAR uart_dev_t *dev) { FAR struct uart_gdbstub_s *uart_gdbstub; uart_gdbstub = kmm_malloc(sizeof(struct uart_gdbstub_s)); if (uart_gdbstub == NULL) { return -ENOMEM; } uart_gdbstub->state = gdb_state_init(uart_gdbstub_send, uart_gdbstub_receive, NULL, uart_gdbstub); if (uart_gdbstub->state == NULL) { kmm_free(uart_gdbstub); return -ENOMEM; } g_uart_gdbstub = uart_gdbstub; memcpy(&uart_gdbstub->ops, dev->ops, sizeof(struct uart_ops_s)); uart_gdbstub->dev = dev; uart_gdbstub->org_ops = dev->ops; uart_gdbstub->ops.receive = uart_gdbstub_ctrlc; dev->ops = &uart_gdbstub->ops; uart_setup(dev); uart_attach(dev); uart_enablerxint(dev); uart_gdbstub->nb.notifier_call = uart_gdbstub_panic_callback; panic_notifier_chain_register(&uart_gdbstub->nb); return 0; }