mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-29 16:24:55 +00:00
Merge pull request #14634 from LabNConsulting/chopps/gdb-use-emacs
tests: add --gdb-use-emacs option
This commit is contained in:
commit
614d7873d5
@ -583,6 +583,12 @@ Here's an example of launching ``zebra`` and ``bgpd`` inside ``gdb`` on router
|
|||||||
--gdb-breakpoints=nb_config_diff \
|
--gdb-breakpoints=nb_config_diff \
|
||||||
all-protocol-startup
|
all-protocol-startup
|
||||||
|
|
||||||
|
Finally, for Emacs users, you can specify ``--gdb-use-emacs``. When specified
|
||||||
|
the first router and daemon to be launched in gdb will be launched and run with
|
||||||
|
Emacs gdb functionality by using `emacsclient --eval` commands. This provides an
|
||||||
|
IDE debugging experience for Emacs users. This functionality works best when
|
||||||
|
using password-less sudo.
|
||||||
|
|
||||||
Reporting Memleaks with FRR Memory Statistics
|
Reporting Memleaks with FRR Memory Statistics
|
||||||
"""""""""""""""""""""""""""""""""""""""""""""
|
"""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
@ -102,6 +102,12 @@ def pytest_addoption(parser):
|
|||||||
help="Comma-separated list of routers to spawn gdb on, or 'all'",
|
help="Comma-separated list of routers to spawn gdb on, or 'all'",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
parser.addoption(
|
||||||
|
"--gdb-use-emacs",
|
||||||
|
action="store_true",
|
||||||
|
help="Use emacsclient to run gdb instead of a shell",
|
||||||
|
)
|
||||||
|
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--logd",
|
"--logd",
|
||||||
action="append",
|
action="append",
|
||||||
|
@ -31,7 +31,8 @@ from copy import deepcopy
|
|||||||
import lib.topolog as topolog
|
import lib.topolog as topolog
|
||||||
from lib.micronet_compat import Node
|
from lib.micronet_compat import Node
|
||||||
from lib.topolog import logger
|
from lib.topolog import logger
|
||||||
from munet.base import Timeout
|
from munet.base import commander, get_exec_path_host, Timeout
|
||||||
|
from munet.testing.util import retry
|
||||||
|
|
||||||
from lib import micronet
|
from lib import micronet
|
||||||
|
|
||||||
@ -1261,8 +1262,8 @@ def rlimit_atleast(rname, min_value, raises=False):
|
|||||||
|
|
||||||
def fix_netns_limits(ns):
|
def fix_netns_limits(ns):
|
||||||
# Maximum read and write socket buffer sizes
|
# Maximum read and write socket buffer sizes
|
||||||
sysctl_atleast(ns, "net.ipv4.tcp_rmem", [10 * 1024, 87380, 16 * 2 ** 20])
|
sysctl_atleast(ns, "net.ipv4.tcp_rmem", [10 * 1024, 87380, 16 * 2**20])
|
||||||
sysctl_atleast(ns, "net.ipv4.tcp_wmem", [10 * 1024, 87380, 16 * 2 ** 20])
|
sysctl_atleast(ns, "net.ipv4.tcp_wmem", [10 * 1024, 87380, 16 * 2**20])
|
||||||
|
|
||||||
sysctl_assure(ns, "net.ipv4.conf.all.rp_filter", 0)
|
sysctl_assure(ns, "net.ipv4.conf.all.rp_filter", 0)
|
||||||
sysctl_assure(ns, "net.ipv4.conf.default.rp_filter", 0)
|
sysctl_assure(ns, "net.ipv4.conf.default.rp_filter", 0)
|
||||||
@ -1321,8 +1322,8 @@ def fix_host_limits():
|
|||||||
sysctl_atleast(None, "net.core.netdev_max_backlog", 4 * 1024)
|
sysctl_atleast(None, "net.core.netdev_max_backlog", 4 * 1024)
|
||||||
|
|
||||||
# Maximum read and write socket buffer sizes
|
# Maximum read and write socket buffer sizes
|
||||||
sysctl_atleast(None, "net.core.rmem_max", 16 * 2 ** 20)
|
sysctl_atleast(None, "net.core.rmem_max", 16 * 2**20)
|
||||||
sysctl_atleast(None, "net.core.wmem_max", 16 * 2 ** 20)
|
sysctl_atleast(None, "net.core.wmem_max", 16 * 2**20)
|
||||||
|
|
||||||
# Garbage Collection Settings for ARP and Neighbors
|
# Garbage Collection Settings for ARP and Neighbors
|
||||||
sysctl_atleast(None, "net.ipv4.neigh.default.gc_thresh2", 4 * 1024)
|
sysctl_atleast(None, "net.ipv4.neigh.default.gc_thresh2", 4 * 1024)
|
||||||
@ -1363,6 +1364,8 @@ def setup_node_tmpdir(logdir, name):
|
|||||||
class Router(Node):
|
class Router(Node):
|
||||||
"A Node with IPv4/IPv6 forwarding enabled"
|
"A Node with IPv4/IPv6 forwarding enabled"
|
||||||
|
|
||||||
|
gdb_emacs_router = None
|
||||||
|
|
||||||
def __init__(self, name, *posargs, **params):
|
def __init__(self, name, *posargs, **params):
|
||||||
# Backward compatibility:
|
# Backward compatibility:
|
||||||
# Load configuration defaults like topogen.
|
# Load configuration defaults like topogen.
|
||||||
@ -1799,6 +1802,7 @@ class Router(Node):
|
|||||||
gdb_breakpoints = g_pytest_config.get_option_list("--gdb-breakpoints")
|
gdb_breakpoints = g_pytest_config.get_option_list("--gdb-breakpoints")
|
||||||
gdb_daemons = g_pytest_config.get_option_list("--gdb-daemons")
|
gdb_daemons = g_pytest_config.get_option_list("--gdb-daemons")
|
||||||
gdb_routers = g_pytest_config.get_option_list("--gdb-routers")
|
gdb_routers = g_pytest_config.get_option_list("--gdb-routers")
|
||||||
|
gdb_use_emacs = bool(g_pytest_config.option.gdb_use_emacs)
|
||||||
valgrind_extra = bool(g_pytest_config.option.valgrind_extra)
|
valgrind_extra = bool(g_pytest_config.option.valgrind_extra)
|
||||||
valgrind_memleaks = bool(g_pytest_config.option.valgrind_memleaks)
|
valgrind_memleaks = bool(g_pytest_config.option.valgrind_memleaks)
|
||||||
strace_daemons = g_pytest_config.get_option_list("--strace-daemons")
|
strace_daemons = g_pytest_config.get_option_list("--strace-daemons")
|
||||||
@ -1926,12 +1930,19 @@ class Router(Node):
|
|||||||
cmdopt += " " + extra_opts
|
cmdopt += " " + extra_opts
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(gdb_routers or gdb_daemons)
|
(not gdb_use_emacs or Router.gdb_emacs_router)
|
||||||
|
and (gdb_routers or gdb_daemons)
|
||||||
and (
|
and (
|
||||||
not gdb_routers or self.name in gdb_routers or "all" in gdb_routers
|
not gdb_routers or self.name in gdb_routers or "all" in gdb_routers
|
||||||
)
|
)
|
||||||
and (not gdb_daemons or daemon in gdb_daemons or "all" in gdb_daemons)
|
and (not gdb_daemons or daemon in gdb_daemons or "all" in gdb_daemons)
|
||||||
):
|
):
|
||||||
|
if Router.gdb_emacs_router is not None:
|
||||||
|
logger.warning(
|
||||||
|
"--gdb-use-emacs can only run a single router and daemon, using"
|
||||||
|
" new window"
|
||||||
|
)
|
||||||
|
|
||||||
if daemon == "snmpd":
|
if daemon == "snmpd":
|
||||||
cmdopt += " -f "
|
cmdopt += " -f "
|
||||||
|
|
||||||
@ -1942,9 +1953,84 @@ class Router(Node):
|
|||||||
for bp in gdb_breakpoints:
|
for bp in gdb_breakpoints:
|
||||||
gdbcmd += " -ex 'b {}'".format(bp)
|
gdbcmd += " -ex 'b {}'".format(bp)
|
||||||
gdbcmd += " -ex 'run {}'".format(cmdopt)
|
gdbcmd += " -ex 'run {}'".format(cmdopt)
|
||||||
|
|
||||||
self.run_in_window(gdbcmd, daemon)
|
self.run_in_window(gdbcmd, daemon)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
"%s: %s %s launched in gdb window", self, self.routertype, daemon
|
||||||
|
)
|
||||||
|
elif (
|
||||||
|
gdb_use_emacs
|
||||||
|
and (daemon in gdb_daemons)
|
||||||
|
and (not gdb_routers or self.name in gdb_routers)
|
||||||
|
):
|
||||||
|
assert Router.gdb_emacs_router is None
|
||||||
|
Router.gdb_emacs_router = self
|
||||||
|
|
||||||
|
if daemon == "snmpd":
|
||||||
|
cmdopt += " -f "
|
||||||
|
cmdopt += rediropt
|
||||||
|
|
||||||
|
sudo_path = get_exec_path_host("sudo")
|
||||||
|
ecbin = [
|
||||||
|
sudo_path,
|
||||||
|
"-Eu",
|
||||||
|
os.environ["SUDO_USER"],
|
||||||
|
get_exec_path_host("emacsclient"),
|
||||||
|
]
|
||||||
|
pre_cmd = self._get_pre_cmd(True, False, ns_only=True, root_level=True)
|
||||||
|
# why fail:? gdb -i=mi -iex='set debuginfod enabled off' {binary} "
|
||||||
|
gdbcmd = f"{sudo_path} {pre_cmd} gdb -i=mi {binary} "
|
||||||
|
|
||||||
|
commander.cmd_raises(
|
||||||
|
ecbin
|
||||||
|
+ [
|
||||||
|
"--eval",
|
||||||
|
f'(gdb "{gdbcmd}"))',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
elcheck = (
|
||||||
|
'(ignore-errors (with-current-buffer "*gud-nsenter*"'
|
||||||
|
" (and (string-match-p"
|
||||||
|
' "(gdb) "'
|
||||||
|
" (buffer-substring-no-properties "
|
||||||
|
' (- (point-max) 10) (point-max))) "ready")))'
|
||||||
|
)
|
||||||
|
|
||||||
|
@retry(10)
|
||||||
|
def emacs_gdb_ready():
|
||||||
|
check = commander.cmd_nostatus(ecbin + ["--eval", elcheck])
|
||||||
|
return None if "ready" in check else False
|
||||||
|
|
||||||
|
emacs_gdb_ready()
|
||||||
|
|
||||||
|
# target gdb commands
|
||||||
|
cmd = "set breakpoint pending on"
|
||||||
|
self.cmd_raises(
|
||||||
|
ecbin
|
||||||
|
+ [
|
||||||
|
"--eval",
|
||||||
|
f'(gud-gdb-run-command-fetch-lines "{cmd}" "*gud-gdb*")',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
# gdb breakpoints
|
||||||
|
for bp in gdb_breakpoints:
|
||||||
|
self.cmd_raises(
|
||||||
|
ecbin
|
||||||
|
+ [
|
||||||
|
"--eval",
|
||||||
|
f'(gud-gdb-run-command-fetch-lines "br {bp}" "*gud-gdb*")',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
# gdb run cmd
|
||||||
|
self.cmd_raises(
|
||||||
|
ecbin
|
||||||
|
+ [
|
||||||
|
"--eval",
|
||||||
|
f'(gud-gdb-run-command-fetch-lines "run {cmdopt}" "*gud-gdb*")',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
"%s: %s %s launched in gdb window", self, self.routertype, daemon
|
"%s: %s %s launched in gdb window", self, self.routertype, daemon
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user