- (續 08-11-15@GMT-6)尋找合理懷疑對象:
root@intrepid:~/jfbterm-0.4.7# grep "KD_GRAPHICS" *
vterm.c: ioctl(0, KDSETMODE, KD_GRAPHICS);
root@intrepid:~/jfbterm-0.4.7# grep "KD_TEXT" *
main.c: if (mode == KD_TEXT) {
vterm.c: ioctl(0, KDSETMODE, KD_TEXT);
root@intrepid:~/jfbterm-0.4.7# grep "cannot mmap" *
fbcommon.c: die("cannot mmap(smem)");
fbcommon.c: die("cannot mmap(mmio)");
fbcommon.c: print_message("cannot mmap(mmio) : %s\n", strerror(errno));
- 啟用 DEBUG 旗標,編譯 jfbterm,使用 gdb 追蹤
root@intrepid:~/jfbterm-0.4.7# ./configure --enable-debug
root@intrepid:~/jfbterm-0.4.7# make
root@intrepid:~/jfbterm-0.4.7# gdb ./jfbterm
(gdb) run
- 縱使用 gdb 還是無法正常跳回文字模式,因此直接追原始碼。
- 根據錯誤訊息,應該是錯在 fbcommon.c 的第 572 行,往前追造成錯誤的原因是 566 行的 mmap(),歸屬在 tfbm_open() 函數
< fbcommon.c >
482 void tfbm_open(TFrameBufferMemory* p)
566 p->mmio = (u_char*)mmap(NULL, p->mlen, PROT_READ|PROT_WRITE,
567 MAP_SHARED, p->fh, p->slen);
568 if ((long)p->mmio == -1) {
569 #ifdef JFB_MMIO_CHECK
570 die("cannot mmap(mmio)");
571 #else
572 print_message("cannot mmap(mmio) : %s\n", strerror(errno));
573 #endif
< main.c >
368 int main(int argc, char *argv[])
431 tfbm_open(&gFramebuffer);
- 安裝 manpages-dev 套件,查 mmap 、 strerror 跟 errno 的 manpage。從 cannot mmap(mmio) : Invalid argument 這個錯誤訊息可以判斷 errno 等於 EINVAL。而 mmap 發生 EINVAL 的情形有三種,最可能的原因是第一個:We don't like addr, length, or offset (e.g., they are too large, or not aligned on a page boundary).
- 這裡注意到 mmap 的 offset 參數必須是 sysconf 中定義 _SC_PAGE_SIZE 的倍數。(offset must be a multiple of the page size as returned by sysconf(_SC_PAGE_SIZE).)
root@intrepid:~/jfbterm-0.4.7# apt-get install manpages-dev
root@intrepid:~/jfbterm-0.4.7# man errno
EINVAL Invalid argument (POSIX.1)
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
offset must be a multiple of the page size as returned by sysconf(_SC_PAGE_SIZE).
ERRORS
EINVAL We don't like addr, length, or offset (e.g., they are too large, or not aligned on a page boundary).
EINVAL (since Linux 2.6.12) length was 0.
EINVAL flags contained neither MAP_PRIVATE or MAP_SHARED, or contained both of these values.
- 使用 gdb 設定中斷點在 fbcomm.c 第 566 行並觀察變數狀態
root@intrepid:~/jfbterm-0.4.7# gdb
(gdb) file jfbterm
Reading symbols from /root/jfbterm-0.4.7/jfbterm...done.
(gdb) set args -e ls
(gdb) show args
Argument list to give program being debugged when it is started is "-e ls".
(gdb) break fbcommon.c:566
Breakpoint 1 at 0x4034ba: file fbcommon.c, line 566.
(gdb) run
... 略 ...
Breakpoint 1, tfbm_open (p=0x6146e0) at fbcommon.c:566
566 p->mmio = (u_char*)mmap(NULL, p->mlen, PROT_READ|PROT_WRITE,
(gdb) l
561 }
562 p->smem = (char *)p->smem + p->soff;
563
564 p->moff = (u_long)(fb_fix.mmio_start) & (~PAGE_MASK);
565 p->mlen = (fb_fix.mmio_len + p->moff + ~PAGE_MASK) & PAGE_MASK;
566 p->mmio = (u_char*)mmap(NULL, p->mlen, PROT_READ|PROT_WRITE,
567 MAP_SHARED, p->fh, p->slen);
568 if ((long)p->mmio == -1) {
569 #ifdef JFB_MMIO_CHECK
570 die("cannot mmap(mmio)");
(gdb) p fb_fix.mmio_len
$1 = 0
(gdb) p p->moff
$2 = 0
(gdb) p p->mlen
$3 = 0
(gdb) p p->fh
$4 = 6
(gdb) p p->slen
$5 = 1572864
(gdb) p fb_fix.smem_len
$6 = 1572864