From 2dfbc312e6ccb88f838170d8e777d48aacde2ff5 Mon Sep 17 00:00:00 2001
From: johannst A symbolic watchpoint defined on a member variable for debugging is only valid
+as long as the expression is in scope. Once out of scope the watchpoint gets
+deleted. When debugging some memory corruption we want to keep the watchpoint even the
+expression goes out of scope to find the location that overrides the variable
+and introduces the corruption. When using A small test function registry bringing together a few different template
+features. Prior to c++20's concepts, Watchpoint on struct / class member
+(gdb) l
+1 struct S { int v; };
+2
+3 void set(struct S* s, int v) {
+4 s->v = v;
+5 }
+6
+7 int main() {
+8 struct S s;
+9 set(&s, 1);
+10 set(&s, 2);
+11 set(&s, 3);
+...
+
+(gdb) s
+set (s=0x7fffffffe594, v=1) at test.c:4
+4 s->v = v;
+
+# Define a new watchpoint on the member of the struct. The expression however
+# is only valid in the current functions scope.
+
+(gdb) watch s->v
+Hardware watchpoint 2: s->v
+
+(gdb) c
+Hardware watchpoint 2: s->v
+Old value = 0
+New value = 1
+set (s=0x7fffffffe594, v=1) at test.c:5
+5 }
+
+# The watchpoint gets deleted as soon as we leave the function scope.
+
+(gdb) c
+Watchpoint 2 deleted because the program has left the block in
+which its expression is valid.
+main () at test.c:10
+10 set(&s, 2);
+
+(gdb) p &s->v
+$1 = (int *) 0x7fffffffe594
+
+# Define a watchpoint o the address of the member variable of the s instance.
+# This of course only makes sense as long as the s instance is not moved in memory.
+
+(gdb) watch *0x7fffffffe594
+Hardware watchpoint 3: *0x7fffffffe594
+
+(gdb) c
+Hardware watchpoint 3: *0x7fffffffe594
+Old value = 1
+New value = 2
+set (s=0x7fffffffe594, v=2) at test.c:5
+5 }
+
+(gdb) c
+Hardware watchpoint 3: *0x7fffffffe594
+Old value = 2
+New value = 3
+set (s=0x7fffffffe594, v=3) at test.c:5
+5 }
+
Know Bugs
Workaround
command + finish
bugfinish
inside a command
block, commands after finish
are not
@@ -2626,6 +2695,112 @@ int main() {
return 0;
}
+Example: Minimal templatized test registry
+#include <cstdio>
+#include <functional>
+#include <map>
+#include <string>
+#include <type_traits>
+
+template<typename R, typename... P>
+struct registry {
+ using FUNC = R (*)(P...);
+ using SELF = registry<R, P...>;
+ using RET = R;
+
+ static SELF& get() {
+ static SELF r;
+ return r;
+ }
+
+ bool add(std::string nm, FUNC fn) {
+ const auto r = m_fns.insert({std::move(nm), std::move(fn)});
+ return r.second;
+ }
+
+ R invoke(const std::string& nm, P... p) const { return invoke_impl<R>(nm, p...); }
+
+ void dump() const {
+ for (const auto& it : m_fns) {
+ std::puts(it.first.c_str());
+ }
+ }
+
+ private:
+ std::map<std::string, FUNC> m_fns;
+
+ template<typename RET>
+ std::enable_if_t<std::is_same_v<RET, void>> invoke_impl(const std::string& nm, P... p) const {
+ const auto it = m_fns.find(nm);
+ if (it == m_fns.end()) {
+ return;
+ }
+ std::invoke(it->second, p...);
+ }
+
+ template<typename RET>
+ std::enable_if_t<!std::is_same_v<RET, void>, RET> invoke_impl(const std::string& nm,
+ P... p) const {
+ const auto it = m_fns.find(nm);
+ if (it == m_fns.end()) {
+ static_assert(std::is_default_constructible_v<RET>,
+ "RET must be default constructible");
+ return {};
+ }
+ return std::invoke(it->second, p...);
+ }
+};
+
+#define TEST_REGISTER(REGISTRY, NAME) \
+ static bool regfn_##REGISTRY##NAME() { \
+ const bool r = REGISTRY::get().add(#NAME, NAME); \
+ if (!r) { \
+ std::puts("Failed to register test " #NAME ", same name already registered!"); \
+ std::abort(); \
+ } \
+ return r; \
+ } \
+ static const bool reg_##REGISTRY##NAME = regfn_##REGISTRY##NAME();
+
+#define TEST(REGISTRY, NAME, ...) \
+ REGISTRY::RET NAME(__VA_ARGS__); \
+ TEST_REGISTER(REGISTRY, NAME); \
+ REGISTRY::RET NAME(__VA_ARGS__)
+
+// -- Usage 1 simple usage.
+
+using REG1 = registry<void>;
+TEST(REG1, test1) {
+ std::puts("REG1::test1");
+}
+TEST(REG1, test2) {
+ std::puts("REG1::test2");
+}
+
+// -- Usage 2 with convenience macro wrapper.
+
+using REG2 = registry<void, bool>;
+#define TEST2(NAME, ...) TEST(REG2, NAME, ##__VA_ARGS__)
+
+TEST2(test1, bool val) {
+ printf("REG2::test1 val %d\n", val);
+}
+
+int main() {
+ const auto& R1 = REG1::get();
+ R1.dump();
+ R1.invoke("test1");
+ R1.invoke("test2");
+
+ const auto& R2 = REG2::get();
+ R2.dump();
+ R2.invoke("test1", true);
+
+ return 0;
+}
+
Example: Concepts pre c++20
SFINAE
and std::void_t
can be leveraged to build
something similar allowing to define an interface (aka trait) for a template
@@ -3304,6 +3479,7 @@ def sum(a: int, b: int) -> int:
systemd
systemctl
@@ -3566,9 +3742,129 @@ For example as systemd
service:
systemctl status dphys-swapfile
+Some notes on using /dev/input/*
device driver files.
These device files are created by the [mousedev] driver.
+/dev/input/mouseX
represents the input stream for a SINGLE mouse device./dev/input/mice
represents the merged input stream for ALL mouse devices.The data stream consists of 3 bytes
per event
. An event is encoded as (BTN, X, Y)
.
BTN
button pressedX
movement in x-direction -1 -> left
and 1 -> right
Y
movement in y-direction -1 -> down
and 1 -> up
The raw data stream can be inspected as follows.
+sudo cat /dev/input/mice | od -tx1 -w3 -v
+
+These device files are created by the [evdev] driver.
+/dev/input/eventX
represents the generic input event interface a SINGLE input deivece.Input events are encoded as given by the input_event
struct below. Reading
+from the eventX
device file will always yield whole number of input events.
struct input_event {
+ struct timeval time;
+ unsigned short type;
+ unsigned short code;
+ unsigned int value;
+};
+
+On most 64bit machines the raw data stream can be inspected as follows.
+sudo cat /dev/input/event4 | od -tx1 -w24 -v
+
+To find out which device file is assigned to which input device the following
+file /proc/bus/input/devices
in the proc filesystem can be consulted.
This yields entries as follows and shows which Handlers
are assigned to which
+Name
.
I: Bus=0018 Vendor=04f3 Product=0033 Version=0000
+N: Name="Elan Touchpad"
+...
+H: Handlers=event15 mouse0
+...
+
+/dev/input/eventX
Once compiled, the example should be run as sudo ./event /dev/input/eventX
.
#include <stdio.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <sys/time.h>
+#include <linux/input-event-codes.h>
+
+struct input_event {
+ struct timeval time;
+ unsigned short type;
+ unsigned short code;
+ unsigned int value;
+};
+
+const char* type(unsigned short t) {
+ static char buf[32];
+ const char* fmt = "0x%x";
+ switch (t) {
+#define FMT(TYPE) case TYPE: fmt = #TYPE"(0x%x)"; break
+ FMT(EV_SYN);
+ FMT(EV_KEY);
+ FMT(EV_REL);
+ FMT(EV_ABS);
+#undef FMT
+ }
+ snprintf(buf, sizeof(buf), fmt, t);
+ return buf;
+}
+
+const char* code(unsigned short c) {
+ static char buf[32];
+ const char* fmt = "0x%x";
+ switch (c) {
+#define FMT(CODE) case CODE: fmt = #CODE"(0x%x)"; break
+ FMT(BTN_LEFT);
+ FMT(BTN_RIGHT);
+ FMT(BTN_MIDDLE);
+ FMT(REL_X);
+ FMT(REL_Y);
+#undef FMT
+ }
+ snprintf(buf, sizeof(buf), fmt, c);
+ return buf;
+}
+
+const char* timefmt(const struct timeval* t) {
+ assert(t);
+ struct tm* lt = localtime(&t->tv_sec); // Returns pointer to static tm object.
+ static char buf[64];
+ strftime(buf, sizeof(buf), "%H:%M:%S", lt);
+ return buf;
+}
+
+int main(int argc, char* argv[]) {
+ assert(argc == 2);
+
+ int fd = open(argv[1], O_RDONLY);
+ assert(fd != -1);
+
+ struct input_event inp;
+ while (1) {
+ int ret = read(fd, &inp, sizeof(inp));
+ assert(ret == sizeof(inp));
+ printf("time: %s type: %s code: %s value: 0x%x\n",
+ timefmt(&inp.time), type(inp.type), code(inp.code), inp.value);
+ }
+}
+
+[mousedev]: TODO /home/johannst/dev/linux/drivers/input/mousedev.c +[evdev]: TODO /home/johannst/dev/linux/drivers/input/evdev.c
# -k: Start capturing immediately.
ssh <host> tcpdump -i <IF> -w - | sudo wireshark -k -i -
+Command line interface to the firewalld(1) daemon.
+# List all services and ports for all zones.
+firewall-cmd --list-all
+# List all services.
+firewall-cmd --list-services
+# List all ports.
+firewall-cmd --list-ports
+
+++Add
+--zone <ZONE>
to limit output to a givenZONE
. Use--get-zones
to +see all available zones.
# Add a service to the firewall, use `--get-services` to list all available
+# service names.
+firewall-cmd --add-service <SERVICE>
+# Add a specific port.
+firewall-cmd --add-port 8000/tcp
+
+# Remove service.
+firewall-cmd --remove-service <SERVICE>
+# Remove port.
+firewall-cmd --remove-port 8000/tcp
+
+<script>
+const showTab = (E, T) => {
+ const TABS = Array.from(document.getElementsByClassName("content"));
+ TABS.forEach(T => {
+ T.style.display = "none";
+ });
+
+ document.getElementById(T).style.display = "block";
+};
+
+window.onload = () => {
+ document.getElementById("bTab1").onclick = (E) => {
+ showTab(E, "tTab1");
+ };
+ document.getElementById("bTab2").onclick = (E) => {
+ showTab(E, "tTab2");
+ };
+}
+</script>
+
+<button type="button" id="bTab1">Tab1</button>
+<button type="button" id="bTab2">Tab2</button>
+
+<div id="tTab1" class="content" style="display: block;">
+ <p>Some content goes here ...</p>
+</div>
+
+<div id="tTab2" class="content" style="display: none;">
+ <p>... and there.</p>
+</div>
+
+<canvas id="myChart" style="margin:5em;"></canvas>
+
+<script>
+const get_or_create_tooltip = (id) => {
+ if (tooltip = document.getElementById(id)) {
+ return tooltip;
+ } else {
+ // -- Create a new Tooltip element.
+ const tooltip = document.createElement('div');
+ tooltip.id = id;
+ document.body.appendChild(tooltip);
+
+ // -- Some minimal styling.
+ tooltip.style.background = 'rgba(0, 0, 0, 0.1)';
+ tooltip.style.position = 'absolute';
+ tooltip.style.transition = 'all .2s ease';
+
+ // -- Add a table element for the tooltip content.
+ const table = document.createElement('table');
+ tooltip.appendChild(table);
+
+ return tooltip
+ }
+}
+
+const render_tooltip = (context) => {
+ const {chart, tooltip} = context;
+
+ // -- Get Tooltip element.
+ const tooltip_elem = get_or_create_tooltip('myTooltip');
+
+ // -- Get data point values (only one data point).
+ const {label: x, formattedValue: y} = tooltip.dataPoints[0];
+
+ // -- Format new tooltip.
+ const link = document.createElement('a');
+ link.href = "https://github.com/johannst";
+ link.innerHTML = "X:" + x + " Y:" + y;
+
+ // -- Remove previous child element and add new one.
+ const table = tooltip_elem.querySelector('table');
+ table.innerHTML = "";
+ table.appendChild(link);
+
+ // -- Get absolute X/Y position of the top left corner of the canvas.
+ const {offsetLeft: canvas_x, offsetTop: canvas_y} = chart.canvas;
+
+ // -- Set position and minimal style for the tooltip.
+ tooltip_elem.style.left = canvas_x + tooltip.caretX + 'px';
+ tooltip_elem.style.top = canvas_y + tooltip.caretY + 'px';
+ tooltip_elem.style.font = tooltip.options.bodyFont.string;
+
+ // -- Place the tooltip (I) left or (II) right of the data point.
+ if (tooltip.xAlign === "right") {
+ tooltip_elem.style.transform = 'translate(-100%, 0)'; // (I)
+ } else if (tooltip.xAlign === "left") {
+ tooltip_elem.style.transform = 'translate(0%, 0)'; // (II)
+ }
+}
+
+// -- Render a chart with some dummy data on the canvas.
+const chart = new Chart(
+ document.getElementById('myChart'),
+ {
+ data: {
+ datasets: [{
+ // -- A single dataset.
+ label: 'Just some values',
+ type: 'scatter',
+ data: [
+ {x: 4, y: 4},
+ {x: 5, y: 1},
+ {x: 7, y: 6},
+ {x: 10, y: 8},
+ {x: 10, y: 7},
+ {x: 10, y: 3},
+ ],
+ backgroundColor: 'rgba(255, 99, 132, 0.5)',
+ borderColor: 'rgb(255, 99, 132)',
+ }],
+ },
+ options: {
+ scales: {
+ y: {
+ beginAtZero: true, // -- Start the Y-Axis at zero instead min(y) of dataset.
+ }
+ },
+ plugins: {
+ tooltip: {
+ enabled: false, // -- Disable builtin tooltips.
+ mode: 'nearest', // -- Get the item that is nearest to the mouse.
+ intersect: false, // -- 'mode' is active also when the mouse doesnt intersect with an item on the chart.
+ external: render_tooltip, // -- External tooltip handler, allows to create own HTML.
+ }
+ }
+ }
+ }
+);
+</script>
> gcc -o greet greet.s -nostartfiles -nostdlib && ./greet
Hi ASM-World!
-Select dynamic linker according to abi used during compile & link.
-