My code works, I don’t know why.

國王的耳朵是驢耳朵

從gdb Dump Process 記憶體資料

| Comments

無聊在trace vdso 找到的技巧。整理如下

方法說明

  • gdb 你要的程式
  • gdb 設常用的 system callopen
  • 執行程式
  • 中斷後
    • info proc mappings
    • dump memory 檔名 開始位址 結束位址
    • 離開
  • 剩下看你拿要dump 的檔案做啥了

範例: dump process中的vdso記憶體區塊,觀察vdso symbol

  • gdb 你要的程式
1
2
3
4
5
$ gdb /bin/ls
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
...
Reading symbols from /bin/ls...(no debugging symbols found)...done.
(gdb) 
  • gdb 設常用的 system callopen
1
2
(gdb) b open
Breakpoint 1 at 0x3d30
  • 執行程式
1
2
3
4
5
6
(gdb) r
Starting program: /bin/ls 

Breakpoint 1, __libc_open64 (file=file@entry=0x7ffff7df6428 "/etc/ld.so.cache", oflag=oflag@entry=524288)
    at ../sysdeps/unix/sysv/linux/open64.c:39
39    ../sysdeps/unix/sysv/linux/open64.c: No such file or directory.
  • info proc mapings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(gdb) info proc mappings 
process 30094
Mapped address spaces:

          Start Addr           End Addr       Size     Offset objfile
      0x555555554000     0x555555573000    0x1f000        0x0 /bin/ls
      0x555555772000     0x555555775000     0x3000    0x1e000 /bin/ls
      0x555555775000     0x555555776000     0x1000        0x0 [heap]
      0x7ffff7dd5000     0x7ffff7dfc000    0x27000        0x0 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7ff7000     0x7ffff7ffa000     0x3000        0x0 [vvar]
      0x7ffff7ffa000     0x7ffff7ffc000     0x2000        0x0 [vdso]
      0x7ffff7ffc000     0x7ffff7ffe000     0x2000    0x27000 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7ffe000     0x7ffff7fff000     0x1000        0x0 
      0x7ffffffde000     0x7ffffffff000    0x21000        0x0 [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0 [vsyscall]
  • dump memory 檔名 開始位址 結束位址
1
2
3
4
5
6
7
(gdb) dump memory vdso 0x7ffff7ffa000  0x7ffff7ffc000
(gdb) quit
A debugging session is active.

  Inferior 1 [process 30094] will be killed.

Quit anyway? (y or n) y
  • 看dump 檔案 symbol
1
2
3
4
5
6
7
8
9
10
11
12
$ file vdso 
vdso: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=cef5ed3c3dc2b39082ae093560c168a8b427ebb6, stripped
$ nm -D vdso 
0000000000000a30 W clock_gettime
0000000000000f30 W getcpu
0000000000000d40 W gettimeofday
0000000000000000 A LINUX_2.6
0000000000000f10 W time
0000000000000a30 T __vdso_clock_gettime
0000000000000f30 T __vdso_getcpu
0000000000000d40 T __vdso_gettimeofday
0000000000000f10 T __vdso_time

加碼,觀察ASLR

懶的說明ASLR,請自行參考連結。 另外請自行比較下面兩個 cat 的記憶體區塊位址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ cat /proc/self/maps
5601e5311000-5601e5319000 r-xp 00000000 103:02 13631603                  /bin/cat
...
5601e6814000-5601e6835000 rw-p 00000000 00:00 0                          [heap]
...
7ffe6edcf000-7ffe6edf0000 rw-p 00000000 00:00 0                          [stack]
7ffe6edfb000-7ffe6edfe000 r--p 00000000 00:00 0                          [vvar]
7ffe6edfe000-7ffe6ee00000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]


$ cat /proc/self/maps
556ef8185000-556ef818d000 r-xp 00000000 103:02 13631603                  /bin/cat
...
556ef91df000-556ef9200000 rw-p 00000000 00:00 0                          [heap]
...
7ffc83c55000-7ffc83c76000 rw-p 00000000 00:00 0                          [stack]
7ffc83d4a000-7ffc83d4d000 r--p 00000000 00:00 0                          [vvar]
7ffc83d4d000-7ffc83d4f000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

Linux Binary 縮寫和連結

| Comments

整理目前看過的資料縮寫以及網路連結,可能會更新。

ELF header

  • hdr: header
  • Ehdr: ELF header
  • EI: ELF ident
  • ET: ELF type
  • EM: ELF machine

Program header

  • Phdr: Program header
  • PT: Program header type
  • PF: Prgram header flag

Section header

  • Shdr: Section header
  • SHN: Section header index
  • sh_: Section header
  • SHT: Section header type
  • SHF: Section header flag

Symbol table

  • st: Symbol table
  • STT: Symbol table type
  • STV: Symbol table visibility

Dynamic section

  • DT: Dynamic section type

Note section

  • NT: Note type

Auxiliary vector

  • AT: auxiliary vector type

資源

Ubuntu 16.04更新到Ubuntu 18.04後Octopress 環境變動

| Comments

本來想要寫一些東西,結果發現rake在Ubuntu 無法執行,只好先處理了。

主要的問題是更新後Ruby版本從16.04使用的2.3升級成2.5了。以下是我紀錄過的測試指令,必須承認這是網路上的東西剪貼,我不想知道後面的原理,後果自行負責。寫這篇文章另一個目的是確定上傳到網路上後可以正常發佈才證明真的解決問題了。

預安裝套件

1
sudo apt -y gcc libcurl4-openssl-dev libxml2-dev

Ruby 相關更新,完全不知道做啥

1
2
3
sudo gem install bundler
bundle install
sudo gem install rake

更新Octopress Gemfile

由於更新後rake版本也從10.5.0變成12.3.1,所以一跑rake就會出現版本不合的錯誤,因此我把Gemfile rake的版本檢查改成12,diff 檔案如下

1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/Gemfile b/Gemfile
index 153dd3d..9f5048b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,7 +1,7 @@
 source "https://rubygems.org"

 group :development do
-  gem 'rake', '~> 10.0'
+  gem 'rake', '~> 12.0'
   gem 'jekyll', '~> 2.0'
   gem 'octopress-hooks', '~> 2.2'
   gem 'octopress-date-format', '~> 2.0'

參考資料

Vim POSIX Group Regex 使用方式

| Comments

由於個人需求,需要在vim下面使用稍微複雜的字串搜尋取代。故整理這篇以後可以參考。

目錄

測試環境

1
2
3
4
5
6
7
8
9
$ lsb_release -a
No LSB modules are available.
Distributor ID:   Ubuntu
Description:  Ubuntu 18.04.1 LTS
Release:  18.04
Codename: bionic

$ vim --version
VIM - Vi IMproved 8.0 (2016 Sep 12, compiled Apr 10 2018 21:31:58)

問題描述以及POSIX regex grouping 簡介

Regular express 的特色是他可以match不同的pattern,所以用於搜尋和取代是非常的方便,然而當要把符合條件的字串前面或後面加上字串就會有一個問題,那就是符合的字串要怎麼表示?舉例來說,當我們想要在下面log[mem....] 之後放入test,要怎麼做到? 這時候我們就可以使用reguler expressiongroup 功能了

1
2
3
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x0000000000057fff] usable
[    0.000000] BIOS-e820: [mem 0x0000000000058000-0x0000000000058fff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000000059000-0x000000000009dfff] usable

參考語法

  • 指定group,一組regex可以指定零到多個group
    • \(match_patter\)
  • 取值
    • \0
      • 前項所有的group
    • \1
      • 第一組group
    • \2
      • 第二組group
    • \3
      • 第三組group
    • 千秋萬世直到永遠

範例

就用上面的訊息當範例吧

1
2
3
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x0000000000057fff] usable
[    0.000000] BIOS-e820: [mem 0x0000000000058000-0x0000000000058fff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000000059000-0x000000000009dfff] usable

範例一: 在[mem …]之後插入test

  • 指令: :%s/\(\[mem.*\]\)/\1 test/g
1
2
3
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x0000000000057fff] test usable
[    0.000000] BIOS-e820: [mem 0x0000000000058000-0x0000000000058fff] test reserved
[    0.000000] BIOS-e820: [mem 0x0000000000059000-0x000000000009dfff] test usable

範例二: 設定三組group,都插入test

  • 指令: :%s/\(^\[.*\]\) \(\BIOS-e820:\) \(\[mem.*\]\)/\1 test1 \2 test2 \3 test3 /g
1
2
3
[    0.000000] test1 BIOS-e820: test2 [mem 0x0000000000000000-0x0000000000057fff] test3  usable
[    0.000000] test1 BIOS-e820: test2 [mem 0x0000000000058000-0x0000000000058fff] test3  reserved
[    0.000000] test1 BIOS-e820: test2 [mem 0x0000000000059000-0x000000000009dfff] test3  usable

Notes on How to C 2016

| Comments

最近看了How to C 2016,反正很多記不起來乾脆寫起來以後剪貼。

GNU Flags

  • -std=c99

Warning flags

-Wall -Wextra -Werror -Wshadow -Wno-missing-field-initializers -Wstrict-overflow -fno-strict-aliasing

Links

  • stdint.h
    • intmax_t,…
    • intptr_t
      • 根據platform int size 調整
  • stdtype.h
    • ptr_diff_t

其他

  • size_tssize_t差別:s->signed,當有錯誤時會為-1
  • #pragma once 可用來取代Header guard

名詞

給自己剪貼用的vim設定

| Comments

分享使用vim 的心得,加上使用Vundle plugin管理工具功能配合外部程式碼分享軟體cscopectags來trace C語言的程式碼以及編輯Python程式碼相關設定。

  • 致謝,感謝網友Scott介紹vim register概念,葉闆介紹的tagbar,和Kyle Lin介紹的airline。

目錄

測試環境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ lsb_release  -a
No LSB modules are available.
Distributor ID:   Ubuntu
Description:  Ubuntu 16.04.3 LTS
Release:  16.04
Codename: xenial


$ ctags --version
Exuberant Ctags 5.9~svn20110310, Copyright (C) 1996-2009 Darren Hiebert
...

$ cscope --version
cscope: version 15.8b

$ vim --version
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Nov 24 2016 16:44:48)
Included patches: 1-1689
...

設定.vimrc以及Vundle plugins

事前準備

您需要確認

  • vim版本為7.4以上
  • 安裝ctags和cscope,指令如下 sudo apt-get install exuberant-ctags cscope

安裝Vundle

Vundle是vim plugin 管理工具,他可以透過URL, github, 以及local FS等方式安裝甚至更新Plugin。類似的工具還有不少,我只是挑看到的第一個而已。

Vundle常用的指令如下,還蠻容易望文生義所以我就不解釋了

  • :PluginList
  • :PluginInstall
  • :PluginClean
  • :PluginUpdate

安裝方式如下

  • 首先你要下載Vundle,指令如下 git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim

  • 接下來在你的.vimrc加入下面這段,我是從官方網頁改的,其實只是把他的範例Plugin幹掉並加上分隔線及分隔線內的註解而已

.vimrc 要加的部份
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
"====================================================================
" Start vundle
"====================================================================
set nocompatible              " be iMproved, required
filetype off                  " required

" set the runtime path to include Vundle and initialize
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()

" alternatively, pass a path where Vundle should install plugins
"call vundle#begin('~/some/path/here')

" let Vundle manage Vundle, required
Plugin 'VundleVim/Vundle.vim'

"===============================================================
" Write your plugins here
"===============================================================
Plugin 'Yggdroot/indentLine'

"====================================================================
" Run vundle
"====================================================================
" All of your Plugins must be added before the following line
call vundle#end()            " required
filetype plugin indent on    " required
" To ignore plugin indent changes, instead use:
"filetype plugin on
"
" Brief help
" :PluginList       - lists configured plugins
" :PluginInstall    - installs plugins; append `!` to update or just :PluginUpdate
" :PluginSearch foo - searches for foo; append `!` to refresh local cache
" :PluginClean      - confirms removal of unused plugins; append `!` to auto-approve removal
"
" see :h vundle for more details or wiki for FAQ
" Put your non-Plugin stuff after this line

注意下面列出的這幾行statements,你要新增或移除Plugin就是改這個地方。這些Plugin將會在後面介紹。剛好我要安裝的Plugin都是在GitHub上開發或有mirror。而Vundle可以用直接指定Plugin 專案在GitHub相對路徑即可安裝。這些描述也是Vundle載入Plugin 的順序,沒寫對順序有可能有相依問題請自行注意。

例如https://github.com/Yggdroot/indentLine 就寫成Yggdroot/indentLine

我安裝的Plugin
1
2
3
4
5
6
7
8
9
10
11
12
13
"===============================================================
" Write your plugins here
"===============================================================
Plugin 'Yggdroot/indentLine'
Plugin 'ntpeters/vim-better-whitespace'
Plugin 'vim-airline/vim-airline'
Plugin 'tpope/vim-fugitive'
Plugin 'chazy/cscope_maps'
Plugin 'vim-scripts/taglist.vim'
Plugin 'scrooloose/nerdtree'
Plugin 'wesleyche/SrcExpl'
Plugin 'wesleyche/Trinity'
Plugin 'majutsushi/tagbar'
  • 確定新增/刪除Plugin後,就可以執行vim/gvim,使用下面命令
    • :PluginInstall
    • :PluginClean

我安裝的Vundle Plugins

因為安裝方式已經在上面了,這邊就以介紹為主

編輯器相關

airline

安裝準備

先看圖,圖中最下方的那行就是airline,可以顯示一些有用的資訊

由左到右我們可以看到Vim 模式,Git branch 等資訊。以及一些比較特別的符號,這表示我們需要

  • 讓airline取得git資訊
  • 讓airline取得特別符號

也就是說,在安裝airline前要做一些前置動作如下

  • 讓airline取得git資訊
    • 很簡單,安裝vim-fugitive plugin即可
  • 讓airline取得特別符號 這也不難,就是安裝特殊字型,並且設定GUI時存取這些字型。方式如下

取得字型

1
git clone https://github.com/powerline/fonts

安裝字型

1
cd fonts && ./install.sh

.vimrc中指定安裝的字型

1
set guifont=Inconsolata\ for\ Powerline\ 20

設定airline

把下面的資料放入.vimrc即可

1
2
let g:airline_powerline_fonts = 1
set laststatus=2

indentLine

當Ident為空白增加以下的Indent 對齊參考資線

注意此Plugin在Ident為tab同時又加上顯示tab字元時自動失效,目前workaround就是顯示tab字元為|,接下來以.延伸作為辨別。範例如下:

vim-better-whitespace

trailing space顯示成明顯的紅色

Trace 程式碼相關

cscope_maps

簡單來說,就是把cscope指令對應到Hot key

先列出find部份的指令

1
2
3
4
5
6
7
8
9
find : Query for a pattern            (Usage: find c|d|e|f|g|i|s|t name)
       c: Find functions calling this function
       d: Find functions called by this function
       e: Find this egrep pattern
       f: Find this file
       g: Find this definition
       i: Find files #including this file
       s: Find this C symbol
       t: Find this text string

他的使用方法也很簡單,就是先把游標移動到你要查的statement,再按ctrl + \ + c|d|e|f|g|i|s|t 其中一個

舉例來說,我在下圖中把游標移動到core_sys_select函數後按下ctrl + \ + c的結果如下

SrcExpl

當啟動時,您的游標在那個敘述,Source explorer 會切割視窗,印出該敘述的定義。舉例來說,當我游標在138行的free_poll_entry的話,顯示的畫面如下。

taglist

列出目前檔案所有symbol並且可以選擇symbol切換到該symbol在檔案中的位置

nerdtree

以樹狀顯示目前檔案所在目錄結構,看圖就知道

Trinity

看完以上三個,你可能會覺得奇怪好像沒提到怎麼啟動。這就是Trinity大顯身手的地方了。你安裝Trinity後,再Vundle後面加上下面的敘述就可以有

  • F8 : 同時打開或關閉nerdtree, Source explorer, 以及tag list
  • F9 : 打開或關閉Source explorer
  • F10: 打開或關閉tag list
  • F11: 打開或關閉nerdtree
.vimrc 的Trinity設定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
"====================================================================
" Trinity Settings
"====================================================================
" Open and close all the three plugins on the same time
nmap <F8>  :TrinityToggleAll<CR>

" Open and close the Source Explorer separately
nmap <F9>  :TrinityToggleSourceExplorer<CR>

" Open and close the Taglist separately
nmap <F10> :TrinityToggleTagList<CR>

" Open and close the NERD Tree separately
nmap <F11> :TrinityToggleNERDTree<CR>

以下是按下F8 的畫面

tagbar

網友推荐的taglist改良版 plugin,為什麼不換掉taglist呢?因為我喜歡source explorer。除了安裝Plugin外,我也順便設定按下F7可以切換,設定如下。

.vimrc 的Trinity設定
1
2
3
4
5
"====================================================================
" Tagbar Settings
"====================================================================
" Open and close the tagbar separately
nmap <F7> :TagbarToggle<CR>

以下是按下F7 的畫面,可以注意右邊視窗會更進一步地顯示資料結構的成員名稱

Markdown 語法支援

vim-pandoc-syntax

單純就是讓vim可以顯示Markdown syntax highlight,範例如下圖:

Python開發相關

準備工作

主要是語法檢查套件相關安裝,指令如下

.vimrc 的Trinity設定
1
sudo apt install -y flake8 python-rope pylint

python-mode

之前有介紹過,偷懶跳過。也許Python用到一陣子可以上手後可以再分享心得。

syntastic

泛用形語法檢查工具,請參考Syntax checking hacks for vim說明。 目前是我靠他幫忙檢查寫的程式是否符合PEP8規範,要注意的是Ubuntu 16.04中vim 套件預設只支援Python 3,要使用vim 編寫Python 2的朋友請自行估狗。我之前是自行編譯vim解決的。

語法檢查範例如下圖

python_match

讓Python 也可以使用vim中切換配對的快捷鍵%

python

提供下列快捷鍵,節錄自Plugin註解:

  • ]t – Jump to beginning of block
  • ]e – Jump to end of block
  • ]v – Select (Visual Line Mode) block
  • ]< – Shift block to left
  • ]> – Shift block to right
  • ]# – Comment selection
  • ]u – Uncomment selection
  • ]c – Select current/previous class
  • ]d – Select current/previous function
  • ]<up> – Jump to previous line with the same/lower indentation
  • ]<down> – Jump to next line with the same/lower indentation

indentpython

確保你的程式碼符合PEP8的indent規範

和Plugin 無關的設定

以下都加在.vimrc中,建議加到Vundle設定結束後以確保可能會用到的Plugin已經啟動

編輯器和顯示特殊字元相關設定

  • 設定gvim 的配色,請自行找Color scheme
    • colorscheme koehler
  • 設定gvim 的字型和大小
    • set guifont=Inconsolata\ for\ Powerline\ 32
  • 將找到的字串設成高亮度
    • set hlsearch
  • 游標在的該行背景高亮度
    • set cursorline
  • 顯示行號
    • set nu
  • 第八十字元地方顯示高亮度區塊(這是連續兩個描述)
    • set colorcolumn=80
    • highlight ColorColumn guibg=#202020
  • 顯示tab (這是連續兩個描述)
    • set listchars=tab:»\
      • 注意\後面有一個空白
    • set list

效果如下圖

Indent相關設定

  • Tab相關設定
    • set ts=4
      • tab space 為4個字元
    • set expandtab
      • 不使用tab,用空白字元代替
    • set shiftwidth=4
      • Auto indent的移動字元數量
  • visual 模式下一次移動一個indent
    • vnoremap < <gv
      • 往左移動一個indent
    • vnoremap > >gv
      • 往右移動一個indent

其他

  • set clipboard+=unnamed
    • PRIMARY selection的register "*包含vim的unnamed register。白話講就是其他的APP如gedit中滑鼠選字後可以用"*p貼到vim,同樣的"*y6y的結果可以貼在其他的APP如gedit上。這部份有vim register副本,建議到參考資料的副本區一讀。再次感謝Scott大大。

參考資料

懶人包

  • 安裝相關軟體,Vundle和airline字型
1
2
3
4
sudo apt-get install -y exuberant-ctags cscope vim-gtk git flake8 python-rope pylint
git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim
git clone https://github.com/powerline/fonts
cd fonts && ./install.sh
  • 剪貼下面的文字並存放到 ~/.vimrc
.vimrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
"====================================================================
" Start vundle
"====================================================================
set nocompatible              " be iMproved, required
filetype off                  " required

" set the runtime path to include Vundle and initialize
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()

" alternatively, pass a path where Vundle should install plugins
"call vundle#begin('~/some/path/here')

" let Vundle manage Vundle, required
Plugin 'VundleVim/Vundle.vim'

"===============================================================
" Write your plugins here
"===============================================================
" Layouts
Plugin 'Yggdroot/indentLine'
Plugin 'ntpeters/vim-better-whitespace'

" Markdown
Plugin 'vim-pandoc/vim-pandoc-syntax'

" Python related
Plugin 'python-mode/python-mode'
Plugin 'vim-scripts/indentpython.vim'
Plugin 'vim-syntastic/syntastic'
Plugin 'vim-scripts/python_match.vim'
Plugin 'vim-scripts/python.vim'

" Misc tools
Plugin 'kien/ctrlp.vim'
Plugin 'vim-airline/vim-airline'
Plugin 'tpope/vim-fugitive'
Plugin 'Valloric/YouCompleteMe'
Plugin 'chazy/cscope_maps'
Plugin 'vim-scripts/taglist.vim'
Plugin 'scrooloose/nerdtree'
Plugin 'wesleyche/SrcExpl'
Plugin 'wesleyche/Trinity'
Plugin 'majutsushi/tagbar'

"====================================================================
" Run vundle
"====================================================================
" All of your Plugins must be added before the following line
call vundle#end()            " required
filetype plugin indent on    " required
" To ignore plugin indent changes, instead use:
"filetype plugin on
"
" Brief help
" :PluginList       - lists configured plugins
" :PluginInstall    - installs plugins; append `!` to update or just :PluginUpdate
" :PluginSearch foo - searches for foo; append `!` to refresh local cache
" :PluginClean      - confirms removal of unused plugins; append `!` to auto-approve removal
"
" see :h vundle for more details or wiki for FAQ
" Put your non-Plugin stuff after this line

"====================================================================
" Tagbar Settings
"====================================================================
" Open and close the tagbar separately
nmap <F7> :TagbarToggle<CR>

"====================================================================
" Trinity Settings
"====================================================================
" Open and close all the three plugins on the same time
nmap <F8>  :TrinityToggleAll<CR>

" Open and close the Source Explorer separately
nmap <F9>  :TrinityToggleSourceExplorer<CR>

" Open and close the Taglist separately
nmap <F10> :TrinityToggleTagList<CR>

" Open and close the NERD Tree separately
nmap <F11> :TrinityToggleNERDTree<CR>

"====================================================================
" Airline settings
"====================================================================
let g:airline_powerline_fonts = 1
set laststatus=2

"====================================================================
" syntastic settings
"====================================================================
set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*

let g:syntastic_always_populate_loc_list = 1
let g:syntastic_auto_loc_list = 1
let g:syntastic_check_on_open = 1
let g:syntastic_check_on_wq = 0
autocmd VimEnter * SyntasticToggleMode " disable syntastic by default


"====================================================================
" pymode settings
"====================================================================
let g:pymode_lint = 0    " Prefer to use syntastic to check lint
let g:pymode_folding = 0 " Unfold all

"====================================================================
" Editor and display Settings
"====================================================================
colorscheme koehler         " Color for gvim

set hlsearch                " Highlight search
set guifont=Inconsolata\ for\ Powerline\ 32 " Font
set cursorline              " Hight background at current cursor line
set nu                      " Display line numbers

" Set background color at colum 80
set colorcolumn=80
highlight ColorColumn guibg=#202020

" Show tabs
set listchars=tab:\|.
set list

" Ensure syntax is on
syntax on

"====================================================================
" Indent Settings
"====================================================================
" Tabs
set ts=4
set expandtab
set shiftwidth=4

" visual indent shift
vnoremap < <gv
vnoremap > >gv

"====================================================================
" MISC Settings
"====================================================================
" Shared unamed regitered with primary selection
set clipboard+=unnamed

" uft-8 encoding: https://stackoverflow.com/questions/16507777/set-encoding-and-fileencoding-to-utf-8-in-vim
set encoding=utf-8
set fileencoding=utf-8

"====================================================================
" Python Settings
"====================================================================
au BufNewFile,BufRead *.py
    \ set tabstop=4 |
    \ set softtabstop=4 |
    \ set shiftwidth=4 |
    \ set textwidth=79 |
    \ set expandtab |
    \ set autoindent |
    \ set fileformat=unix
let python_highlight_all=1
  • gvim -> :PluginInstall 安裝Plugin重新開啟收工

其他

  • cscope產生database供vim使用
    • cscope -bqkR
      • k表示使用kernel mode,不把/usr/include之類的加入資料庫。Cross compile也不會使用host 的header file,所以請自行斟酌。其他參數請自己問男人。
  • ctags產生database供vim使用
    • ctags -R
  • 要在vim使用到ctags和cscope的話,請記得vim一定要開在database同一層目錄!

舉例來說,你在/tmp/linux-stable目錄下了上面兩個指令。要開啟檔案請在/tmp/linux-stable目錄中指定對應路徑。範例如下

1
user@host:/tmp/linux-stable$ gvim fs/select.c

Fix: Qemu X86_64下gdb Debug kernel出現Remote 'g’ Packet Reply Is Too Long:

| Comments

問題描述

本篇文章主要是解決使用gdb 設Qemu x86_64 模擬執行x86_64 buildroot kernel開機的中斷點時遇到下面的錯誤訊息

Remote 'g’ packet reply is too long:

詳細訊息如下

1
2
3
4
5
6
0x0000000000000000 in irq_stack_union ()
(gdb) b x86_64_start_kernel
Breakpoint 1 at 0xffffffff8188429b: file arch/x86/kernel/head64.c, line 134.
(gdb) c
Continuing.
Remote 'g' packet reply is too long: 9b428881ffffffff0000000000000000010100c000000000ffffffff00000000804001000000000080400100000000000000000000000000f03f8081ffffffff00a080010000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000009b428881ffffffff4600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000

目錄

測試環境

  • Buildroot
    • Commit: bfc90a5621c680000f8b19e8afea944da5c2a469
  • Target kernel 版本
1
2
# uname -a
Linux buildroot 4.9.6 #2 SMP Sun Jun 4 18:46:27 CST 2017 x86_64 GNU/Linux
  • Qemu 執行指令
1
2
3
4
$ qemu-system-x86_64 -M pc -kernel output/images/bzImage                        \
                     -drive file=output/images/rootfs.ext2,if=virtio,format=raw \
                     -append "root=/dev/vda console=ttyS0"                      \
                     -net nic,model=virtio -net user -nographic -S -s

基本上是從這邊衍生出來的,挑幾個重點

  • -append "root=/dev/vda console=ttyS0"
    • 指定serial port console,如此一來就可以在terminal 直接顯示Qemu 的執行文字,不過你需要修改rootfs 的/etc/inittab才能在terminal login
  • -S -s
    • 開機的時候就停下來,並開啟port 1234讓gdb從遠端連入除錯
  • -nographic
    • 懶得跳一個視窗,直接terminal當console使用

buildroot 事先準備

  1. 下載buildroot
    • git clone https://git.buildroot.net/buildroot
  2. 設定預設config
    • make qemu_x86_64_defconfig
  3. 手動設定buildroot config如gcc版本,客製化rootfs套件等
    • make menuconfig
  4. 設定Linux kernel 選項,主要是打開debug symbol
    • make linux-menuconfig
  5. 編譯rootfs及kernel
    • make
  6. 設定可以從console 登入

gdb 錯誤訊息解法

OSDev: QEMU and GDB in long mode可以看到可以使用下面指令頂著先(workaround)

  • disconnect
  • set arch i386:x86-64
  • target remote 127.0.0.1:1234

然而作為組裝工,信奉偷懶就是美德,每次要打這麼多指令實在很麻煩。因此我將這些麻煩的方式使用下面的指令自動化

1
2
3
4
5
6
gdb ./vmlinux  -ex "target remote localhost:1234"       \
               -ex "break x86_64_start_kernel"          \
               -ex "continue"                           \
               -ex "disconnect"                         \
               -ex "set architecture i386:x86-64:intel" \
               -ex "target remote localhost:1234"

執行後畫面輸出部份節錄如下

1
2
3
4
5
6
7
8
9
10
11
12
13
Reading symbols from ./vmlinux...done.
Remote debugging using localhost:1234
0x0000000000000000 in irq_stack_union ()
Breakpoint 1 at 0xffffffff8188429b: file arch/x86/kernel/head64.c, line 134.
Continuing.
Remote 'g' packet reply is too long: 9b428881ffffffff0000000000000000010100c000000000ffffffff00000000804001000000000080400100000000000000000000000000f03f8081ffffffff00a080010000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000009b428881ffffffff4600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000
Ending remote debugging.
The target architecture is assumed to be i386:x86-64:intel
Remote debugging using localhost:1234
x86_64_start_kernel (real_mode_data=0x14080 <cpu_tss+6848> <error: Cannot access memory at address 0x14080>) at arch/x86/kernel/head64.c:134
134   {
(gdb) n
151       cr4_init_shadow();

由於gdb command file 遇到錯誤就會停下來,所以把上面的指令放到一個檔案中,執行gdb時將會停在continue這邊,目前懶的找解法了。有興趣的朋友可以自行研究。

懶人包

  • Buildroot
1
2
3
4
5
6
git clone https://git.buildroot.net/buildroot
cd buildroot
make qemu_x86_64_defconfig
make menuconfig
make linux-menuconfig
make
  • 啟動Qemu 假設在buildroot top directory下
1
2
3
4
qemu-system-x86_64 -M pc -kernel output/images/bzImage                          \
                     -drive file=output/images/rootfs.ext2,if=virtio,format=raw \
                     -append "root=/dev/vda console=ttyS0"                      \
                     -net nic,model=virtio -net user -nographic -S -s
  • gdb 假設在buildroot top directory下
1
2
3
4
5
6
7
cd output/build/linux-4.9.6
gdb ./vmlinux  -ex "target remote localhost:1234"       \
               -ex "break x86_64_start_kernel"          \
               -ex "continue"                           \
               -ex "disconnect"                         \
               -ex "set architecture i386:x86-64:intel" \
               -ex "target remote localhost:1234"

讓qemu-system-x86_64 在console 可以登入

/etc/inittab加入下面這行ttyS0::respawn:/sbin/getty -L ttyS0 0 vt100 # GENERIC_SERIAL

/etc/inittab
1
2
3
 # Put a getty on the serial port
 tty1::respawn:/sbin/getty -L  tty1 0 vt100 # GENERIC_SERIAL
+ttyS0::respawn:/sbin/getty -L  ttyS0 0 vt100 # GENERIC_SERIAL

參考資料

Bash下自動完成gvim –remote-tab

| Comments

在gvim需要開tab要打--remote-tab,打久就開始厭煩想偷懶。後來整理網路上的bash_completion相關資料拼湊一個堪用的版本分享一下。因為我只是想偷懶,所以完全沒有去了解bash_completion的細節。嘛,反正可以組裝需要的功能就好。

目錄

測試環境

1
2
3
4
5
6
$ lsb_release  -a
No LSB modules are available.
Distributor ID:   Ubuntu
Description:  Ubuntu 16.04.2 LTS
Release:  16.04
Codename: xenial

安裝方式

  1. 下面文字貼到編輯器,存成/etc/bash_completion.d/gvim
  2. 使用下面指令新增gvim completion
新增gvim completion指令
1
$ . /etc/bash_completion.d/gvim

使用方式

  • 一般使用,直接gvim tab 顯示檔案或目錄
新增gvim completion指令
1
2
3
4
$ gvim `tab`
changelog.Debian.gz  copyright            README.emacs         RelNotes/
changelog.gz         NEWS.Debian.gz       README.md
contrib/             README.Debian        README.source
  • 要使用tab時,下gvim -tab 就會自動填入--remote-tab,接下來再按tab即可選擇檔案或目錄
新增gvim completion指令
1
2
3
4
$ gvim --remote-tab
changelog.Debian.gz  copyright            README.emacs         RelNotes/
changelog.gz         NEWS.Debian.gz       README.md
contrib/             README.Debian        README.source

gvim bash_completion script

gvim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
_gvim()
{
    local cur prev
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts="--remote-tab"

    if [[ ${cur} == -* ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi

    compopt -o default; COMPREPLY=()
    return 0
}
complete -F _gvim gvim

參考資料

筆記 - GNU Coding Style

| Comments

這是沒事亂看的,主要找和C 語言相關的描述,就不要在意文章組織和可讀性了。

閱讀版本:July 25, 2016

CH 3

  • 要保證C程式碼可移植性,compile flag可以使用--ansi, --posix, --compatible
  • 可以使用下面的方式取代原本的巨集條件編譯,現在的gcc已經可以產生一樣的結果了。
原本程式碼
1
2
3
4
5
#ifdef HAS_FOO
...
#else
...
#endif
建議使用方式
1
2
3
4
if (HAS_FOO)
...
else
...

Ch 4

  • --pedantic:產生所有ISO C和ISO C++規範的警告訊息,並將所有C的extension退貨
  • 冷門:POSIX 2.0規範du/df的unit是512 bytes

4.2 Writing Robust Programs

  • 使用動態配置資料方式避免資料長度限制,包含檔案名稱長度、一行長度等
  • 讀檔案時不得丟棄NUL字元以及不可列印字元,並需相容多位元編碼方式如UTF-8
  • 除非要刻意忽略錯誤,使用system call必定檢查回傳值,並使用perrorstrerror等方式列印出錯誤訊息
  • 使用mallicrelloc一定要檢查回傳值是否為NULL。當使用relloc要求分配比原本空間更小時更需要注意,因為實作關係可能最後分配的空間block可能和原本的不同
  • 使用free後就不要留戀還在裏面的資料了吧
  • 一旦malloc出現錯誤時,非互動程式請將他視為嚴重錯誤。互動程式就儘早自殺(abort())吧
  • 使用getopt_long處理命令列參數
  • 避免操作低階UNIX介面,以減少相容性問題
  • 在程式中檢查到不可能發生的狀況,直接給他死。既然不可能發生了,顯然那邊出大問題,儘早發現儘早處理。因為就是不可能發生,而死掉一定從這邊找起,寫程式時就在這邊提供更多註解和資訊吧
  • 使用全域變數或static 變數儘量給初值。(不確定是否有看懂,出處
  • 不要從回傳值傳回發生錯誤的次數,因為只有256個狀態而已,很容易overflow的。
  • 使用存放暫存檔到$TMP_DIR環境變數而不是閉著眼睛寫到/tmp下面
  • 同樣的,暫存檔請將權限設為0600確保資訊不會洩漏

CH 4.3 Library Behavior

  • 儘量讓函數reentrant
  • Name covention 很重要,因為library是給別人用,粗心大意就出現name conflict 的問題,以下是GNU的建議
    • external 函數和變數需加prefix,prefix為兩個字元以上(後面英文太爛看不懂)
    • external 但是不想讓使用者看到(或是文件不會提到的)的函數以_開頭加上prefix用來辨識這是內部函數
    • 內部static 就請自便

CH 4.4 Formatting Error Messages

  • 錯誤訊息格式,我只挑一個,有興趣看全文請參考這邊
    • sourcefile:lineno: message

CH 4.5 Standards for Interfaces Generally

很奇怪的,單字句子都看懂,就是不懂他要表達啥。只能猜測說不要生出一堆很功能類似的執行檔,而是用最少執行檔加上參數取代。以及執行檔儘量device independent

4.12 File Usage

檔案有可能會存放在readonly FS,如果要寫東西寫到必定是可寫的目錄如/var或是/tmp目錄中

Writing C

  • 單行最多79個字元

註解

  • 檔案開頭請加註解說明該檔案的用途
  • 用英文寫註解
  • 每個函數都要說明該函數的用法,參數,回傳值等資訊
  • #endif 後加上對應的#ifdef#ifndef 說明,範例如下:
1
2
3
4
5
6
7
8
9
#ifdef ASDF
...
#else  /* ASDF */
...
#endif /* not ASDF */

#ifnef QWER
...
#endif /* not QWER */

Clean Use of C Constructs

  • 所有的宣告都要明確,例如不要因為預設回傳值是int就省略要回傳int的函數對應宣告
  • 視情況自行決定是否要使用嚴格的語法檢查如-Wall,編譯器是我們的奴隸,你自己清楚要做什麼就好。不要為了避免嚴格語法檢查硬上一些奇怪的語法導致可讀性變差
  • extern 要嘛全部放在C檔案的同一塊地方,要嘛集中到header file,不要東一撮西一撮。更嚴禁在函數內使用
  • 不要在函數中重複使用一些無意義名稱的變數如tmp之類的,個別變數就給予個別有意義的變數名稱,不要偷懶。也可以在需要的最小scope宣告變數增加可讀性。
  • 變數要注意是否和global 變數或是更大scope名稱相同,您可以開啟-Wshadow協助偵測這類的錯誤
  • 多個變數就個別宣告型態,一方面增加可註解的空間,一方面可讀性也較佳。範例如下
1
2
3
4
5
6
/* Bad */
int i_am_bad, i_am_super_bad;

/* Good */
int i_am_good   = 0;
int i_am_better = 0;
  • 不要在判斷式加入assign,這樣很容易出錯,範例如下
1
2
3
4
5
6
7
/* Bad */
if ((my_id = get_id(my_record)) != NONE) {
    /* Prcess data */
}
else {
    return NO_DATA;
}
1
2
3
4
5
6
/* Good */
my_id = get_id(my_record);
if (my_id == NONE) {
    return NO_DATA;
}
/* Prcess data */

Naming Variables, Functions, and Files

  • Global name 要有意義,不要亂取。
    • ps: 個人會加個g prefix提醒一下
  • 縮寫如src等可以使用。但是請確定讀者可以知道該縮寫或是該縮寫可能造成讀者模糊混淆
  • 使用常數時儘量用enum取代巨集

Portability between CPUs

完全看不懂,抱歉

剩下的是平台相容性和國際化字元等,沒興趣所以跳過

參考資料

Linux Kernel Pratice 0.5: 使用gdb 加 Qemu Trace Linux Kernel Runtime 行為

| Comments

目錄

測試環境

Host

  • Host OS
1
2
3
4
5
6
$ lsb_release -a
No LSB modules are available.
Distributor ID:   Ubuntu
Description:  Ubuntu 14.04.5 LTS
Release:  14.04
Codename: trusty
  • Qemu
1
2
$ qemu-system-arm --version
QEMU emulator version 2.0.0 (Debian 2.0.0+dfsg-2ubuntu1.27), Copyright (c) 2003-2008 Fabrice Bellard
  • gdb
1
2
3
4
5
$ arm-none-eabi-gdb --version
GNU gdb (GNU Tools for ARM Embedded Processors) 7.10.1.20160923-cvs
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl
...
  • buildroot 版本
    • commit hash: 14b24726a81b719b35fee70c8ba8be2d682a7313

Target

  • Linux kernerl 版本
    • 4.4.2
  • 模擬平台
    • Vexpress

Linux kernel環境設定

我目前只打開加入debug資訊的選項。接下來重編,編譯的方式請參考這邊

  • Kernel hacking -> Compile-time checks and compiler options ->
    • Compile the kernel with debug info

測試

依照下面兩個步驟執行

  1. 執行qemu,並且加入支援gdb以及開始馬上freeze CPU的參數
  2. 執行gdb,載入symbol並聯到qemu除錯

Qemu

基本上就是原本的指令加入兩個選項

  • -S
    • qemu一開始立即Freeze CPU
  • -s
    • -gdb tcp::1234的縮寫,也就是說gdb可以透過port 1234和連到Qemu除錯

假設你在buildroot最上層,就可以使用下面指令執行qemu 並使用gdb 除錯

1
2
3
4
5
6
qemu-system-arm -M vexpress-a9 -smp 1 -m 256 \
                -kernel /tmp/kernel/linux-stable/arch/arm/boot/zImage  \
                -dtb /tmp/kernel/linux-stable/vexpress-v2p-ca9.dtb     \
                -drive file=output/images/rootfs.ext2,if=sd,format=raw \
                -append "console=ttyAMA0,115200 root=/dev/mmcblk0"     \
                -serial stdio -net nic,model=lan9118 -net user -s -S

gdb

這邊有點瑣碎,先講一下步驟

  1. 載入Linux kernel symbol
    • 假設你在kernel最上層目錄有三種方式載入
      • 直接arm-none-eabi-gdb ./vmlinux
      • arm-none-eabi-gdb -ex "file ./vmlinux"
      • 進入gdb後打file ./vmlinux指令
  2. 連上qemu
    • 一樣兩種方式
      • arm-none-eabi-gdb -ex "target remote :1234"
      • 進入gdb後打target remote :1234指令
  3. 設定breakpoint等你要觀察的資訊
    • b printk
  4. 告訴qemu開始執行
    • continue

1和2可以一起使用如下

懶人包
1
arm-none-eabi-gdb -ex "file ./vmlinux"  -ex "target remote :1234"

現在看一下操作範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ arm-none-eabi-gdb -ex "file ./vmlinux"  -ex "target remote :1234"
GNU gdb (GNU Tools for ARM Embedded Processors) 7.10.1.20160923-cvs
...
Reading symbols from ./vmlinux...done.
Remote debugging using :1234
0x60000000 in ?? ()
(gdb) b printk
Breakpoint 1 at 0x800a2260: file kernel/printk/printk.c, line 1900.
(gdb) c
Continuing.

Breakpoint 1, printk (fmt=0x0 <__vectors_start>) at kernel/printk/printk.c:1900
1900  {
(gdb) bt
#0  printk (fmt=0x0 <__vectors_start>) at kernel/printk/printk.c:1900
#1  0x806178e0 in start_kernel () at init/main.c:508
#2  0x6000807c in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

另外如果有興趣使用Linux kernel提供的指令,在kernel config設定打開gdb script後,可以使用下面的方式在啟動gdb時載入,只要把下面的描述加到你的~/.gdbinit即可

1
add-auto-load-safe-path /tmp/kernel/scripts/gdb/vmlinux-gdb.py

那麼你就可以使用Linux kernel提供的gdb script,詳細的設定和指令說明在這邊

參考資料

補充

當初犯了蠢事載入不正確的kernel image導致一堆不必要的除錯。不過多學到一個gdb Python script除錯指令,當Python script發生exception時可以用下面的指令印出Python錯誤call stack

  • gdb內:set python print-stack full
  • 啟動gdb時加入參數: -ex "set python print-stack full"