diff options
Diffstat (limited to '_notes')
-rw-r--r-- | _notes/bash.html | 184 | ||||
-rw-r--r-- | _notes/gdb.md | 135 | ||||
-rw-r--r-- | _notes/latex.md | 38 | ||||
-rw-r--r-- | _notes/makefile.md | 129 | ||||
-rw-r--r-- | _notes/markdown.md | 44 |
5 files changed, 530 insertions, 0 deletions
diff --git a/_notes/bash.html b/_notes/bash.html new file mode 100644 index 0000000..c401522 --- /dev/null +++ b/_notes/bash.html @@ -0,0 +1,184 @@ +--- +title: bash +subtitle: best practices +layout: nosidebar +links: + - {rel: stylesheet, href: 'assets/css/guides.css'} +features: + - title: Script header + topics: + - do: + - | + #!/usr/bin/env bash + + set -o errexit -o nounset -o pipefail + shopt -s inherit_errexit lastpipe + dont: + - | + #!/bin/sh -e + - title: Arrays + topics: + - title: Declaration + do: + - | + local -a xs=() + declare -a xs=() + local -A xs=() + declare -A xs=() + dont: + - | + local -a xs + declare -a xs + local -A xs + declare -A xs + + # Doesn't work with nounset: + echo "${#xs[@]}" + - title: Expansion + do: + - | + func ${arr[@]+"${arr[@]}"} + dont: + - | + # Doesn't work with nounset: + func "${arr[@]}" + - | + # Expands to 0 arguments instead of 1: + declare -a arr=('') + func "${arr[@]+"${arr[@]}"}" + - title: unset + do: + - | + unset -v 'arr[x]' + unset -v 'arr[$i]' + dont: + - | + # May break due to globbing: + unset -v arr[x] + # In addition, possible quoting problem: + unset -v arr[$i] + # Doesn't work for some reason: + unset -v 'arr["x"]' + unset -v 'arr["]"]' + # Also rejected: + unset -v 'arr["$i"]' + + # An insightful discussion on the topic: + # https://lists.gnu.org/archive/html/help-bash/2016-09/msg00020.html + - title: errexit + topics: + - title: Command substitution + do: + - | + shopt -s inherit_errexit + + foo() { echo foo ; } + bar() { false ; echo bar >&2 ; } + + output="$( bar )" + foo "$output" + + # If inherit_errexit is unavailable, you can do + #output="$( set -e; bar )" + dont: + - | + foo() { echo foo ; } + bar() { false ; echo bar >&2 ; } + + # This will print both "foo" and "bar": + foo "$( bar )" + # This will also print "foo": + foo "$( false )" + - | + foo() { echo foo ; } + bar() { false ; echo bar >&2 ; } + + # This will still print both "foo" and "bar". + output="$( bar )" + foo "$output" + + # This won't print anything. + output="$( false )" + foo "$output" + - title: Process substitution + do: + - | + shopt -s lastpipe + + result=() + cmd | while IFS= read -r line; do + result+=("$( process_line "$line" )") + done + dont: + - | + # Without lastpipe, the loop is executed is a subshell, + # and the array will be empty: + result=() + cmd | while IFS= read -r line; do + result+=("$( process_line "$line" )") + done + - | + # errexit doesn't work for <( cmd ) no matter what: + while IFS= read -r line; do + process_line "$line" + done < <( cmd ) + # This will be printed even if cmd fails: + echo 'should never see this' + - | + # This breaks if $output contains the \0 byte: + output="$( cmd )" + + while IFS= read -r line; do + process_line "$line" + done <<< "$output" + - title: Functions + do: + - | + foo() { false ; echo foo >&2 ; } + + foo + echo ok + dont: + - | + foo() { false ; echo foo >&2 ; } + + # This will print "foo" no matter what. + if foo; then + echo ok + fi + + # Same below. + foo && echo ok + foo || echo fail + + # It currently appears to be completely impossible to + # execute a function inside a conditional with errexit + # enabled. Therefore, you should try to avoid this + # whenever possible. +--- +{% for feature in page.features %} + <h2>{{ feature.title }}</h2> + {% for topic in feature.topics %} + {% if topic.title %} + <h3>{{ topic.title }}</h3> + {% endif %} + <div class="row"> + <div class="col-md-6"> + {% for guide in topic.do %} + <div class="pre_container pre_do"> + {% highlight bash %}{{ guide }}{% endhighlight %} + <div class="pre_mark"><span class="glyphicon glyphicon-ok"></span></div> + </div> + {% endfor %} + </div> + <div class="col-md-6"> + {% for guide in topic.dont %} + <div class="pre_container pre_dont"> + {% highlight bash %}{{ guide }}{% endhighlight %} + <div class="pre_mark"><span class="glyphicon glyphicon-remove"></span></div> + </div> + {% endfor %} + </div> + </div> + {% endfor %} +{% endfor %} diff --git a/_notes/gdb.md b/_notes/gdb.md new file mode 100644 index 0000000..47db5c9 --- /dev/null +++ b/_notes/gdb.md @@ -0,0 +1,135 @@ +--- +title: gdb +subtitle: cheat sheet +links: + - {rel: stylesheet, href: 'assets/css/gdb.css'} +--- +Core dumps +---------- + +* Where are my core dumps? + + cat /proc/sys/kernel/core_pattern + +* Put core dumps in a directory: + + mkdir /coredumps + chmod 0777 /coredumps + echo '/coredumps/core.%e.%p' | tee /proc/sys/kernel/core_pattern + +* Still no dumps :-( + + ulimit -c unlimited + +* If dumps are piped to systemd-coredump, you can examine them using +`coredumpctl`. + + <div markdown="1" class="table-responsive"> + | List dumps | `coredumpctl` + | Debug the last dump | `coredumpctl gdb` + | Extract the last dump | `coredumpctl dump -o core` + {: .table .table-bordered } + </div> + +.gdbinit +-------- + + # Without these, gdb is hardly usable: + set pagination off + set confirm off + set print pretty on + + # Save history: + set history save on + set history filename ~/.gdb-history + set history size 10000 + +Basics +------ + +<div markdown="1" class="table-responsive"> + +| Run | `r` +| Continue | `c` +| Breakpoint at function | `b FUNC` +| Breakpoint at address | `b *0xdeadbeef` +| List breakpoints | `i b` +| Disable breakpoint | `dis N` +| Enable breakpoint | `en N` +| Delete breakpoint | `d N` +| Call stack | `bt` +| Call stack: all threads | `thread apply all bt` +| Go to frame | `f N` +| Switch to thread | `t N` +| Disassemble | `disas FUNC` +| Step over line | `n` +| Step over instruction | `si` +| Step out of frame | `fin` +{: .table .table-bordered } + +</div> + +Hint: put this in your ~/.gdbinit and use `bta` as a shortcut: + + define bta + thread apply all backtrace + end + +Data inspection +--------------- + +<div markdown="1" class="table-responsive"> + +| Disassemble 5 instructions | `x/5i 0xdeadbeef` +| Print a 64-bit address | `x/1xg 0xdeadbeef` +| Print a 32-bit address | `x/1xw 0xdeadbeef` +| Print anything | `p sa->__sigaction_handler.sa_handler` +| Describe a type | `ptype struct sigaction` +| Describe a type with offsets | `ptype /o struct sigaction` +| Disassemble all code sections | `objdump -d /proc/self/exe` +| Disassemble a single section | `objdump -d -j .init /proc/self/exe` +| Display the section contents | `objdump -s -j .data /proc/self/exe` +{: .table .table-bordered } + +</div> + +Hint: put this in your ~/.gdbinit: + + define xxd + dump binary memory /tmp/dump.bin $arg0 ((char *)$arg0)+$arg1 + shell xxd -groupsize 1 /tmp/dump.bin + shell rm -f /tmp/dump.bin + end + +You can then use `xxd ADDR LEN` to display, in my opinion, the best formatting +for memory dumps: + + (gdb) xxd main 24 + 00000000: f3 0f 1e fa 41 57 41 89 ff bf 05 00 00 00 41 56 ....AWA.......AV + 00000010: 49 89 f6 41 55 41 54 55 I..AUATU + +Debuginfod +---------- + +If your distribution provides a Debuginfod server, use it! +For example, see [Arch], [Debian], [Fedora]. +In ~/.gdbinit, add + + set debuginfod enabled on + +[Arch]: https://wiki.archlinux.org/title/Debuginfod +[Debian]: https://wiki.debian.org/Debuginfod +[Fedora]: https://fedoraproject.org/wiki/Debuginfod + + +Intel syntax +------------ + +This is just me being a baby duck. +In ~/.gdbinit: + + set disassembly-flavor intel + +With `objdump`: + + objdump -Mintel -d /proc/self/exe diff --git a/_notes/latex.md b/_notes/latex.md new file mode 100644 index 0000000..35e4a7d --- /dev/null +++ b/_notes/latex.md @@ -0,0 +1,38 @@ +--- +title: LaTeX +subtitle: document template +--- +A more-or-less complete, but still very basic LaTeX document follows. + +```tex +\documentclass[11pt]{article} + +% Basic setup +\usepackage{cmap} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} % Use T2A for non-ASCII scripts +\usepackage[english]{babel} + +% Completely arbitrary settings follow: + +% Sans serif font by default +\renewcommand\familydefault{\sfdefault} + +% Document margins +\usepackage[margin=2.5cm]{geometry} + +% Paragraph indents +\usepackage{parskip} +\setlength\parindent{0cm} +\setlength\parskip{0cm} + +% URLs +\usepackage[colorlinks=true,urlcolor=blue]{hyperref} + +\begin{document} + +Hello, \LaTeX! +Repository link: \href{https://github.com/egor-tensin/blog}{https://github.com/egor-tensin/blog}. + +\end{document} +``` diff --git a/_notes/makefile.md b/_notes/makefile.md new file mode 100644 index 0000000..62e0570 --- /dev/null +++ b/_notes/makefile.md @@ -0,0 +1,129 @@ +--- +title: make +subtitle: best practices +layout: nosidebar +links: + - {rel: stylesheet, href: 'assets/css/guides.css'} +features: + - note: This should go on top of every Makefile. + sections: + - do: + - | + MAKEFLAGS += --no-builtin-rules --no-builtin-variables --warn-undefined-variables + unexport MAKEFLAGS + .DEFAULT_GOAL := all + .DELETE_ON_ERROR: + .SUFFIXES: + SHELL := bash + .SHELLFLAGS := -eu -o pipefail -c + + escape = $(subst ','\'',$(1)) + + define noexpand + ifeq ($$(origin $(1)),environment) + $(1) := $$(value $(1)) + endif + ifeq ($$(origin $(1)),environment override) + $(1) := $$(value $(1)) + endif + ifeq ($$(origin $(1)),command line) + override $(1) := $$(value $(1)) + endif + endef + - note: Quote command arguments and use the `escape` function on variables and shell output. + sections: + - do: + - | + var := Includes ' quote + test: + printf '%s\n' '$(call escape,$(var))' + dont: + - | + var := Includes space + test: + printf '%s\n' $(var) + - | + var := Includes ' quote + test: + printf '%s\n' '$(var)' + - do: + - | + cwd := $(shell pwd) + test: + printf 'In directory %s\n' '$(call escape,$(cwd))' + dont: + - | + cwd := $(shell pwd) + test: + printf 'In directory %s\n' $(cwd) + - | + cwd := $(shell pwd) + test: + printf 'In directory %s\n' '$(cwd)' + - note: Use the `noexpand` function on environment variables or variables that can be overridden on the command line. + sections: + - do: + - | + has_default ?= Default value + $(eval $(call noexpand,has_default)) + + test: + echo '$(call escape,$(has_default))' + dont: + - | + has_default ?= Default value + + test: + echo '$(call escape,$(has_default))' + - | + has_default ?= Default value + export has_default + + test: + echo "$$has_default" + - do: + - | + $(eval $(call noexpand,ENV_VAR)) + + test: + echo '$(call escape,$(ENV_VAR))' + dont: + - | + test: + echo '$(call escape,$(ENV_VAR))' +--- +I've made a [detailed blog post] about how all of this works. +{: .alert .alert-info } + +[detailed blog post]: {% post_url 2020-05-20-makefile-escaping %} + +{% for feature in page.features %} + {{ feature.note | markdownify }} + {% for section in feature.sections %} +<div class="row"> + {% if section.do %} + {% if section.dont %}{% assign width = "6" %}{% else %}{% assign width = "12" %}{% endif %} + <div class="col-md-{{ width }}"> + {% for guide in section.do %} + <div class="pre_container pre_do"> + <pre>{{ guide }}</pre> + <div class="pre_mark"><span class="glyphicon glyphicon-ok"></span></div> + </div> + {% endfor %} + </div> + {% endif %} + {% if section.dont %} + {% if section.do %}{% assign width = "6" %}{% else %}{% assign width = "12" %}{% endif %} + <div class="col-md-{{ width }}"> + {% for guide in section.dont %} + <div class="pre_container pre_dont"> + <pre>{{ guide }}</pre> + <div class="pre_mark"><span class="glyphicon glyphicon-remove"></span></div> + </div> + {% endfor %} + </div> + {% endif %} +</div> + {% endfor %} + <hr/> +{% endfor %} diff --git a/_notes/markdown.md b/_notes/markdown.md new file mode 100644 index 0000000..39cbbd9 --- /dev/null +++ b/_notes/markdown.md @@ -0,0 +1,44 @@ +--- +title: Markdown +subtitle: style guide +--- +* `diff`- and HTML-friendliness is valued over human-readability. +* Every sentence starts on a new line ("semantic newlines"). +* Lines are at most 79 characters long, not counting neither the carriage +return, nor the line feed characters. + * Not 80 characters, because when you display a 80-character line with a +line feed at the end in Windows' `cmd`, an extra empty line is added. +* No hanging indents in lists. + * Nested lists are indented with 4 spaces. + * No hanging indents in those also. + * Longer items wrap at 79 characters and continue from the leftmost +character column. +Additional sentences start there also. +* Prefer reference-style links over inline links. +Omit the second pair of brackets `[]` entirely where appropriate. +For example, [Google] is preferred over both [Google](https://ya.ru) and +[I'm feeling lucky][google] (see [this document's source]). +* First- and second-level headers are underlined with strings of `=` and `-`. +The number of `=`/`-` signs must be equal to the number of characters in the +header. +* File paths are enclosed in double quotes. +Environment variable names are enclosed in a pair of backticks (\`) unless it's +a part of a path. +Executable names are enclosed in a pair of backticks (\`) unless it's a part of +a path, a link or a header. +* Code blocks are indented with 4 spaces. + + Code blocks inside lists are indented according to the spec + (https://github.github.com/gfm/#list-items), i.e. the column of the first + non-whitespace character in the item + 4. + +* Don't mix fenced code blocks with indented code blocks in a single document. + +| In a table, | the first | row | is underlined. +| ----------- | --------- | ----- | -------------- +| Leftmost | vertical | lines | are required. +| Rightmost | vertical | lines | are omitted. +{: .table .table-bordered } + +[Google]: https://www.google.com/ +[this document's source]: https://raw.githubusercontent.com/{{ site.github.repository_nwo }}/gh-pages/{{ page.path }} |