aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/_notes
diff options
context:
space:
mode:
Diffstat (limited to '_notes')
-rw-r--r--_notes/bash.html184
-rw-r--r--_notes/gdb.md135
-rw-r--r--_notes/latex.md38
-rw-r--r--_notes/makefile.md129
-rw-r--r--_notes/markdown.md44
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 }}