2018/08/09

執行時期控制 linux kernel 印出的訊息

(based on linux kernel version 3.10.104)

在 embedded linux 開發過程中,常常會為了對 kernel space 進行追蹤而使用 printk,但是每次編譯重燒是很耗費時間的,所以直接在執行時期控制 printk 的訊息要不要顯示出來,會是追蹤的一門重要技巧。

參考

printk 提供了一個在執行時期的控制介面,/proc/sys/kernel/printk

#cat /proc/sys/kernel/printk
7 4 1 7

第一個數字代表要印出來的最低等級,也就是等級高於或等於7 (KERN_DEBUG) 都會被印出來
第二個數字代表 printk 沒有指定等級的預設等級 4 (KERN_WARNING)

因為 KERN_WARNING 等級高於 KERN_DEBUG,所以目前不指定等級的 printk() 都會被印出來。

如果只想看到嚴重等級以上的訊息,可以直接

#echo 2 > /proc/sys/kernel/printk
#cat /proc/sys/kernel/printk
2 4 1 7

這樣未指定等級的訊息就不會顯示出來,甚至等級為 KERN_ERR 的訊息也都忍住不噴出了。

以下列出各等級資料:

Name String Meaning alias function
KERN_EMERG "0" Emergency messages, system is about to crash or is unstable pr_emerg
KERN_ALERT "1" Something bad happened and action must be taken immediately pr_alert
KERN_CRIT "2" A critical condition occurred like a serious hardware/software failure pr_crit
KERN_ERR "3" An error condition, often used by drivers to indicate difficulties with the hardware pr_err
KERN_WARNING "4" A warning, meaning nothing serious by itself but might indicate problems pr_warning
KERN_NOTICE "5" Nothing serious, but notably nevertheless. Often used to report security events. pr_notice
KERN_INFO "6" Informational message e.g. startup information at driver initialization pr_info
KERN_DEBUG "7" Debug messages pr_debug, pr_devel if DEBUG is defined
KERN_DEFAULT "d" The default kernel loglevel
KERN_CONT "" "continued" line of log printout (only done after a line that had no enclosing \n) [1] pr_cont

2018/07/20

[C] 如何反查 function 被誰呼叫

除錯時常常需要逆向追蹤程式流程,如果被呼叫的地方很少,可以直接在呼叫前 printf,但是當很多地方呼叫的時候,一個一個放 printf 似乎不是ㄧ個高效率的作法。

#define FuncName(a, b, c) \
do { \
    printf("[%s %d] called FuncName\n",__func__, __LINE__); \
    FuncNameReal (a, b, c); \
} while (0)

例如原本有個 function:
int max(int aaa, int bbb) {...}

因為不想改變呼叫的地方,所以要先把 function 名稱改成 _max

然後在 header file 裡面追加

#define max(a, b) printf("[%s %d] called max"); _max(a, b)

這樣呼叫 max 的程式就會自動報上自己是哪個 func,而且同一 func 有多的地方呼叫的話,是在哪一行呼叫也會報出來。

帶回傳值的時候
#define FuncName(a, b, c) ({ \
        int retval; \
        printf("[%s %d] called FuncName\n",__func__, __LINE__); \
        retval = FuncNameReal (a, b, c); \
        retval;})

參考來源:

2018/04/08

買書同時在 mooink 跟 kindle paperwhite 上閱讀 (進度同步就別想了)

雖然 Kindle 有家庭共享機制,但是不容易買到正體中文書。而在讀墨上面買的書只能在 mooink 閱讀,無法下載轉到 kindle 上閱讀。最終只能在 Kobo 上面買書,檔案下載回來,再經過幾道程序,就能同時在 kindle 和 mooink 上面閱讀。

所需工具:



處理過程:


上 Kobo 買書,購買時可以留意電子書詳細資料裡面的下載選項,如果是 EPUB 3 (Adobe DRM) 就要經過解鎖。

將書籍下載。Adobe DRM 的書籍下載回來是一個描述檔,副檔名是acsm (在 Google 圖書購買的也是這個格式)。

使用 Adobe Digital Editions 打開 *.acsm,就會自動下載該書籍。

執行 Epubor Ultimate,點選 Adobe 頁籤,就可以看到 ADE 管理的書籍清單,依照畫面指示,將書籍拖曳到右邊,看到已解密就完成了。

執行 calibre
-> 點選偏好設定
-> 點選外掛
-> 勾選址顯示使用者已安裝的外掛 
-> 展開檔案類型外掛 
-> 雙擊 DeDRM
-> 點擊 Adobe Digital Editions ebooks

-> 點擊 Import Existing Keyfiles
-> 開啟 user/.Epubor_Keys,選取要匯入的檔案 *.der,然後按下開啟
這時已經匯入所需的DRM金鑰,退回 calibre 主畫面
回到 ADE,在要處理的書籍典籍滑鼠右鍵,點選項目資訊

點擊位置右邊的箭頭(以檔案總管顯示)
從檔案總管將書籍拖曳到 calibre 主畫面,由於 DeDRM 已經匯入相對應的 Key,所以可以開始轉換至所需的格式。要注意的是放進去的書籍是有 DRM 的,無法直接從 mooink 讀取,所以仍然需要從 EPUB 轉 EPUB。

2018/04/02

git 筆記

只是筆記而已,用到才備忘。找工作很重要,從 svn 要再回到 git 還是有點燒腦。

設定 local (目前 .git 管理的範圍) 的帳號資訊
    #git config user.email "aimwang@gmail.com"
    #git config user.name "Aim Wang"

檢查改了哪些檔案
    #git status

恢復各別回未修改前的狀態,其中 filename 可以是 * 來恢復所有檔案,概念就是重新 checkout 檔案
    #git checkout -- <filename>

看看這次改了什麼
    #git diff -- <filename>

本地提交
    #git commit 

單行列出紀錄
    #git log --oneline

顯示 commit 的詳細內容
    #git show commit_id

只顯示本地工作副本的提交紀錄
    #git reflog

增加追蹤檔案
    #git add filename

停止追蹤
    #git update-index --assume-unchanged filename

繼續追蹤
    #git update-index --no-assume-unchanged filename

Merge 其他分支的某個 commit
    #git cherry-pick commit-hash

++++++++++ 分支相關 ++++++++++
列出分支
    本地
    #git branch --list
    遠端
    #git branch --remotes
    全部
    #git branch --all

切換分支
    #git checkout branch

建立分支
    #git branch branch

在 branch_name_father 建立分支 branch_name_son 並直接切過去
    #git checkout -b branch_name_son branch_name_father

將本地分支 push 成遠端分支
    #git push remote_name branch_name

將本地目前分支掛勾到遠端分支
    #git push --set-upstream-to=remote/branch_r branch_l

直接 Checkout 遠端分支到本地分支
    #git checkout -b branch_l remote/branch_r

將分支 branch 併入 master
    #git checkout master
    #git merge branch

如果有衝突 (conflict) 可以使用 mergetool 進行排除
    #git mergetool

設定 mergetool (使用 kdiff3 會有更好的介面)
    #git config merge.tool vimdiff
    #git config merge.conflictstyle diff3
    #git config mergetool.prompt false

刪除已 merge 過的 branch 分支
    #git branch -d branch

捨棄並刪除 branch 分支
    #git branch -D branch

刪除 remote_name 遠端 branch 分支
    #git push --delete remote_name branch

同步遠端分支清單
    #git fetch

++++++++++ 分支相關 ++++++++++

捨棄前一次提交 (限定未 push,發現前次提交還有問題,可以捨棄前一次提交,working tree 仍會保留修改過後的內容,其中 ^ 表示前一版)
    #git reset HEAD^

現有的專案建立新的 git 管理,然後 push 到空的 repository.
    #git init
    #git add .
    #git commit -m "First commit"
    #git remote add remote_name remote_repository_URL
    #git remote -v
    #git push remote_name master

本地建立分支,將分支推到遠端新分支,並建立連結
    #git checkout -b branch_name_son branch_name_father
    #git push remote_name branch_name
    #git push --set-upstream remote_name branch_name

在 sdk 分支進行修改,然後併入分支 develop
    先確保分支 develop 已經乾淨(完成 commit)且同步
        #git status
        #git fetch --all
        #git pull
    切換到分支 sdk
        #git checkout sdk
    修改後 commit 並 push
        #git commit -a -e
        #git push
    切回分支 develop
        #git checkout develop
    合併分支 sdk 的修改 (如果有衝突需要手動修正)
        #git merge sdk
        #git commit -a -e
        #git push

要存取 GitLab 建立的repository 會需要 ssh key 跟 password,所以請記得去設定 password,產生 ssh key 的指令如下:
    #ssh-keygen -t rsa -b 4096 -C "email address"

merge 衝突處理
    #git checkout br2
    #git merge br1
        Auto-merging file
        CONFLICT (content): Merge conflict in index.html
        Automatic merge failed; fix conflicts and then commit the result.
    #git add file
    #git commit -m "conflict fixed"

修復 .gitignore 有列出卻還出現在 modified 清單上的問題
    #git rm --cached filename


++++++++++ Repository 相關 ++++++++++

建立完整的 repository 鏡像
    一個 repository 在運行一段時間之後,可能會有很多分支。遇到需要移植到新的伺服器的狀況時,直接鏡像整個 repository 是比較單純的做法。
    #git clone --mirror src_git_url target_folder
    #cd target_folder
    #git push --mirror dst_git_url


更新 remote url
    #git remote set-url remote_name new_url

    更新後檢查 url 有沒有改成功
    #git remote -v

建立 tag 並推送到 remote
    #git tag -a tag_name -m 'tag_comment'
    #git push remote_name tag_name

++++++++++ 修改剛剛提交而且已經 push 的 message ++++++++++

先修改本地的提交
    #git commit --amend

重新 push 內容
    #git push --force-with-lease remote branch

例如使用 git bracnh --all 顯示為 remotes/origin/develop 的分支, 就執行 git push --force-with-lease origin develop

如果在重新 push 之前就已經 pull 回來, 就需要 hard reset,但是本地端的修改會消失, 執行前最好先透過 git status 找出修改過的內容並且備份
    #git fetch origin
    #git reset --hard remote/branch


2018/03/29

GNU Makefile 一些筆記

筆記而已

-   開頭,表示該行不報錯
@ 開頭,表示該行只執行,不回顯該行指令

:= 強制改變
+= 追加內容
?= 如果變數已經存在就不改變,如果變數不存在才設定

顯示變數內容(也可以用 error 方便除錯,用完就刪掉)
  $(info $$var is [${var}])

觸發錯誤
  $(error "message")

從 AOSP 看到的整合方式,動態將自己的項目加進編譯流程
  #預設目標指定為 droid
  DEFAULT_GOAL := droid
  $(DEFAULT_GOAL):

  .PHONY: mod1
  mod1:
    @echo "mod1"
  #將 mod1 加入預設目標的依賴,這裡可以透過 if 控制
  $(DEFAULT_GOAL): mod1

  .PHONY: mod2
  mod2:
    @echo "mod2"
  $(DEFAULT_GOAL): mod2