2021/03/17

C 將 stdout 轉給 console

daemon 的除錯訊息被殼層吃掉的時候, 將訊息丟到 console 可以方便除錯, 如果是每次呼叫 debug 時都 openfile 和 closefile 會有點浪費資源, 所以直接將 stdout 轉給 console, 就能繼續用 printf 來送出除錯訊息了.

做法就是開個 file handler 給 console, 然後重新將 stdout 設定給 console 的 file handler. 範例程式如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <stdio.h>
int main()
{
	FILE *stdout_bk;
	FILE *fpout = fopen("/dev/console" ,"w" );
	stdout_bk = stdout;
	printf("printf not to console\n");
	stdout = fpout;
	printf("printf to console\n");
	stdout = stdout_bk;
	return 0;
}


做成 MACRO

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#ifdef AIMDBG
#undef AIMDBG
#endif
#define AIMDBG(fmt,...) \
do { \
    FILE *console = fopen("/dev/console" ,"w" ); \
    if (console) { \
        fprintf(console, fmt, __VA_ARGS__); \
        fflush(console); \
        fclose(console); \
    } \
} while(0)


追加 Hexdump

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
static void hexdump (uint8_t* ptr, int len) {
    int i;
    for (i=0; i<len; i++) {
        if (15 == (i % 16)) {
            AIMDBG("%02X\n", ptr[i]);
        }
        else if (7 == (i % 8)) {
            AIMDBG("%02X   ", ptr[i]);
        }
        else {
            AIMDBG("%02X ", ptr[i]);
        }
    }
    AIMDBG("%s", "\n");
}


類似 printf 的用法直接輸出到 console
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
void console_debug(const char *fmt, ...)
{
    static FILE *console_fp = NULL;
    static int tried_open = 0;

    if (!tried_open) {
        console_fp = fopen("/dev/console", "w");
        if (console_fp == NULL) {
            perror("Warning: Cannot open /dev/console, fallback to stderr");
            console_fp = stderr;
        }
        tried_open = 1;
    }
    char log_buf[1024];
    va_list args;
    va_start(args, fmt);
    vsnprintf(log_buf, sizeof(log_buf), fmt, args);
    va_end(args);
    fprintf(console_fp, "[SYSLOGD] %s", log_buf);
    fflush(console_fp);
}

2021/03/05

快速重製 oom 確認 memory leak 的問題

memory leak 會造成記憶體不足而引發 linux 的 oom kill 機制. 假如有 memory leak 的情況發生, 記憶體應該會被佔用而越來越少, 所以要認或是驗證有沒有解決 memory leak, 最簡單的方式就是寫一隻程式來把記憶體占用, 藉此縮短驗證所需的時間.


 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
typedef struct S_ROBBER
{
	char occupy[1024];
} C_ROBBER;

void syntax(char *command)
{
	printf("Syntax:\n");
	printf("\t%s mem_request(MB)\n", command);
	printf("\t\t mem_request between 1 and 128\n", command);
}

int main( int argc, char **argv)
{
	int memreq;
	int i, j;
	char *robber[128][1024];
	C_ROBBER *ptr;
	
	if (argc != 2) {
		syntax(argv[0]);
		return 0;
	}
	
	memreq = atoi(argv[1]);
	
	if (memreq < 1 || memreq > 128) {
		syntax(argv[0]);
		return 0;
	}
	
	for (i=0; i<memreq; i++) {
		for (j=0; j<1024; j++) {
			ptr = (C_ROBBER *)malloc(sizeof(C_ROBBER));
			if (ptr)
			{
				robber[i][j] = ptr;
			} else {
				printf("Your system was very very poor!\n");
				break;
			}
		}
		if (j < 1024) {
			break;
		}
	}
	printf("Robber occupy %dMB memory, now.\n", i);
	
	while(1) {
		sleep(3600);
	}
}

這隻程式會根據船進去的參數, 以 MB 為單位, 霸佔記憶體. 最大占用限制 128MB.

一般系統在記憶體不足時會觸發 oom kill, 而強盜程式會是被殺的最大目標, 所以要把 oom kill 機制關閉, 讓系統直接 panic. 指令如下

1
echo 1 > /proc/sys/vm/panic_on_oom

這樣就可以先用強盜程式將記憶體占用到只剩下一點點, 當記憶體不足的情形發生時, 會直接 panic 而不是把強盜砍掉, 就可以大幅度的縮短重製及驗證的時間.


2021/02/20

Install tor as proxy

Install tor

sudo apt-get install tor

Test tor

curl --socks5 localhost:9050 --socks5-hostname localhost:9050 --insecure -s https://check.torproject.org/ | cat | grep -m 1 Congratulations | xargs

You will get message "Congratulations. This browser is configured to use Tor." if tor work.

Edit tor config to open listen port on lan

sudo nano /etc/tor/torrc
    Search for "SocksPort 9050" and replace with:
        SocksPort 9050
        SocksPort 192.168.56.4:9051    # open sock port for other stations.

# restart tor service
sudo service tor restart

# check listen port
ss -nlt

Setup your browser proxy


Check if you are tor

https://check.torproject.org/


2021/01/15

U-boot entry point

使用 Qualcomm 的 ipq 平台開發產品, 一個不小心遇到了 uboot 完全不會動的狀況, 連一開始顯示版本資訊的訊息都沒出現, 這下糟糕了, 根本就不能用 printf 去看他停在哪裡!

只好從uboot的進入點開始看了. 由於平台使用的是 armv7 的架構, 所以從 (uboot)/arch/arm/cpu/armv7/start.S 開始看. 雖然是組合語言, 幸好只是要看 b, bl, blx, bx 這一系列的分支指令, 而且很幸運的是整個 start.S 只用到 bl 這個.

ARM branch operation

那就一個一個的來找看看 c 的實作:

save_boot_params

void save_boot_params_default(u32 r0, u32 r1, u32 r2, u32 r3) { } void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3) __attribute__((weak, alias("save_boot_params_default")));

空空的.


cpu_init_cp15

cpu_init_crit

這兩個都在 start.S 後面用組合實作


board_init_f

實作在 uboot/arch/arm/lib/board.c

init_fnc_t *init_sequence[] = {
	arch_cpu_init,		/* basic arch cpu dependent setup */

#if defined(CONFIG_BOARD_EARLY_INIT_F)
	board_early_init_f,
#endif
#ifdef CONFIG_OF_CONTROL
	fdtdec_check_fdt,
#endif
	timer_init,		/* initialize timer */
#ifdef CONFIG_FSL_ESDHC
	get_clocks,
#endif
	env_init,		/* initialize environment */
	init_baudrate,		/* initialze baudrate settings */
	serial_init,		/* serial communications setup */
	console_init_f,		/* stage 1 init of console */
	display_banner,		/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
	print_cpuinfo,		/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
	checkboard,		/* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
	init_func_i2c,
#endif
	dram_init,		/* configure available RAM banks */
	NULL,
};

void board_init_f(ulong bootflag)
{
        ... ...
	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0) {
			hang ();
		}
	}
	... ...
}

這裡會逐一呼叫 *init_sequence[] 裡面定義的 function, 如果有哪個 function 傳回不是 0, 就吊起.

追了這些 function, 終於發現是新增 machid, 還沒把相關的 board_parameter 補齊導致的, 趕緊把內容補上, 就可以結案了.


2020/12/30

用 shell 指令觸發 linux kernel panic

linux kernel sysrq

echo 1 >  /proc/sys/kernel/sysrq

echo c > /proc/sysrq-trigger

例如要測試 external watchdog, 就要 not allow reboot/power off (128), 然後再觸發 kernel panic (c) 停止 WDT toggle.

echo 382 > /proc/sys/kernel/sysrq

echo c > /proc/sysrq-trigger