1. 程式人生 > >linux-編譯gcc除錯gdb與安裝make與core

linux-編譯gcc除錯gdb與安裝make與core

1,工具gcc:編譯C檔案

1.1. 無選項編譯連結

用法:#gcc test.c
作用:將test.c預處理、彙編、編譯並連結形成可執行檔案。這裡未指定輸出檔案,預設輸出為a.out。

1.2. 選項 -o

用法:#gcc test.c -o test
作用:將test.c預處理、彙編、編譯並連結形成可執行檔案test。-o選項用來指定輸出檔案的檔名。

1.3. 選項 -E

用法:#gcc -E test.c -o test.i
作用:將test.c預處理輸出test.i檔案。

1.4. 選項 -S

用法:#gcc -S test.i
作用:將預處理輸出檔案test.i彙編成test.s檔案。

1.5. 選項 -c

用法:#gcc -c test.s
作用:將彙編輸出檔案test.s編譯輸出test.o檔案。

1.6. 無選項鍊接

用法:#gcc test.o -o test
作用:將編譯輸出檔案test.o連結成最終可執行檔案test。

1.7. 選項-O

用法:#gcc -O1 test.c -o test
作用:使用編譯優化級別1編譯程式。級別為1~3,級別越大優化效果越好,但編譯時間越長。

1.8. 選項-Dmacro

用法:#gcc -DTEST_CONFIGURATION test.c -o test 作用:開啟巨集TEST_CONFIGURATION

1.9. 選項-Umacro

用法:#gcc -UTEST_CONFIGURATION test.c -o test 作用:關閉巨集TEST_CONFIGURATION

1.10. 選項-Wall

用法:#gcc -Wall test.c -o test 作用:開啟警告資訊

1.11 單檔案編譯

$gcc -c hello.c         #只編譯不連結,生成hello.o
$gcc -o hello hello.o   #輸出可執行檔案hello

1.12 多檔案編譯

$gcc -c thanks.c thanks2.c        #thanks.c呼叫了thanks2.c定義的函式
$gcc -o thanks thanks.o thanks2.o #最終檔案thanks
$./thanks

1.13 指定標頭檔案和lib庫引數

$gcc sin.c -lm -L/lib -L/usr/lib -I/usr/include # 還是會有警告,估計是因為libm.so是標準函式庫
# l表示library,加入某函式庫;m表示libm.so函式庫,lib與副檔名(.a或.so)不需要寫
# L/path表示library的搜尋路徑,Linux預設library搜尋路徑為/lib和/usr/lib
# I/path表示include的搜尋路徑,Linux預設include搜尋路徑為/usr/include

舉例說明:

例:
gcc -o hello hello.c -I/home/hello/include -L/home/hello/lib -lworld

上面這句表示在編譯hello.c時:
-I /home/hello/include表示將/home/hello/include目錄作為第一個尋找標頭檔案的目錄,尋找的順序是:/home/hello/include-->/usr/include-->/usr/local/include
-L /home/hello/lib表示將/home/hello/lib目錄作為第一個尋找庫檔案的目錄,尋找的順序是:/home/hello/lib-->/lib-->/usr/lib-->/usr/local/lib
 -lworld表示在上面的lib的路徑中尋找libworld.so動態庫檔案(如果gcc編譯選項中加入了“-static”表示尋找libworld.a靜態庫檔案)

或者如我編譯的:

gcc -I/usr/include/mysql connect.c -L/usr/lib/mysql -lmysqlclient  -lz -o connect
-lz表示連結壓縮庫

2,makefile基本寫法

2.1 目標單檔案示例

simple_write : simple_write.o
        gcc -o simple_write simple_write.o 
simple_write.o : simple_write.c
        gcc -c simple_write.c
clean : 
        rm -rf *.o
do :
        ./simple_write

2.2 通用模板

檔案Makefile
include ./xxx.mk

#變數定義
TBUS_TEST_CFILE=$(wildcard *.c)
TBUS_TEST_OBJ=$(TBUS_TEST_CFILE:.c=.o)
TEST_TOOL=test


.PHONY:all clean

all: $(TEST_TOOL)
    
$(TEST_TOOL): $(TBUS_TEST_OBJ)
    $(CC)    $^ $(LDPATH) ${LIBS} -o [email protected]

%.o: %.c
    $(CC) -c $< $(CFLAGS) ${CINC} -o [email protected]

clean:
    $(RM) core* *.o  
    $(RM) $(TEST_TOOL)
檔案xxx.mk
#--------------work directories----------------------
XXX_HOME=/usr/local/XXX-2.5.2.28879_X86_64_Release
XXX_INC  = $(XXX_HOME)/include

XXX_SERVICES = $(XXX_HOME)/services
XXX_SERVICESRC = $(XXX_HOME)/services_src

XXX_UNITTESTS = $(XXX_HOME)/unittests
XXX_UNITTESTSRC = $(XXX_HOME)/unittests_src

XXX_DEPS = $(XXX_HOME)/deps

XXX_LIB  = $(XXX_HOME)/lib
XXX_LIBSRC  = $(XXX_HOME)/lib_src

XXX_TOOLS = $(XXX_HOME)/tools
XXX_TOOLSRC  = $(XXX_HOME)/tools_src

XXX_PACKLIBDIR  = $(XXX_LIBSRC)/tmp

XXX_UNITTEST = $(XXX_HOME)/unittests

XXX_SERVICES = $(XXX_HOME)/services
XXX_APPS_INC=$(XXX_INC)/apps


#----------------libraris --------------------------
#XXX的庫目錄
LDPATH = -L$(XXX_LIB)/
#LDPATH += -L/usr/lib/ -L/usr/local/lib/ -L./
#XXX的庫檔案
LIBS = -lXXX

#XXX的include,對外使用CFLAGS
CINC  =  -I$(XXX_INC)/ 
CFLAGS= -Wall -g
CXXFLAGS=-Wall

CC = gcc
CXX = g++
RM = /bin/rm -f

2.3 目標多檔案示例

.PHONY : main
main : server client
server : server.o
        gcc -g -o server server.o 
client : client.o
        gcc -g -o client client.o 
server.o : server.c
        gcc -g -c server.c
client.o : client.c
        gcc -g -c client.c
clean : 
        rm -rf *.o
ser :
        ./server
cli :
        ./client

3,工具make:執行makefile

1,make是一個程式,它會尋找一個叫Makefile的檔案,根據這個檔案執行相關的編譯操作(需要相關的編譯工具如gcc)。

2,那麼Makefile是怎麼來的?通常軟體開發商會寫一個叫configure的檢測程式,去檢測使用者的操作環境,根據操作環境生成相應的編譯規則,並把它們儲存在Makefile檔案中。特別的,configure檢測程式會檢測是否有相應的編譯工具(如gcc)、是否有依賴的函式庫或軟體、是否適合當前的作業系統等等,如果發現不妥,並不會產生相應的Makefile檔案。

3.1 C檔案makefile示例

3.1.1 最基本makefile

3個頭檔案,8個c檔案:

注意1:檔名:Makefile或makefile,如果要指定特定的Makefile,你可以使用make的“-f”和“--file”引數,如:make -f Make.Linux或make --file Make.AIX。

注意2:命令一定要以Tab鍵開始

edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o
	cc -o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o
main.o : main.c defs.h
	cc -c main.c
kbd.o : kbd.c defs.h command.h
	cc -c kbd.c
command.o : command.c defs.h command.h
	cc -c command.c
display.o : display.c defs.h buffer.h
	cc -c display.c
insert.o : insert.c defs.h buffer.h
	cc -c insert.c
search.o : search.c defs.h buffer.h
	cc -c search.c
files.o : files.c defs.h buffer.h command.h
	cc -c files.c
utils.o : utils.c defs.h
	cc -c utils.c
clean :
	rm edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o

3.1.2 改進版1:使用變數

objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o
edit : $(objects)
	cc -o edit $(objects)
main.o : main.c defs.h
	cc -c main.c
kbd.o : kbd.c defs.h command.h
	cc -c kbd.c
command.o : command.c defs.h command.h
	cc -c command.c
display.o : display.c defs.h buffer.h
	cc -c display.c
insert.o : insert.c defs.h buffer.h
	cc -c insert.c
search.o : search.c defs.h buffer.h
	cc -c search.c
files.o : files.c defs.h buffer.h command.h
	cc -c files.c
utils.o : utils.c defs.h
	cc -c utils.c
clean :
	rm edit $(objects)

3.1.3 改進版2:Makefile自動推導

自動推導:只要make看到一個[.o]檔案,它就會自動的把[.c]檔案加在依賴關係中:如果make找到一個whatever.o,那麼whatever.c,就會是whatever.o的依賴檔案。並且 cc -c whatever.c 也會被推匯出來。

注意1:“.PHONY”表示,clean是個偽目標檔案。

注意2:rm命令前面加了一個小減號的意思就是,也許某些檔案出現問題,但不要管,繼續做後面的事。

objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o

edit : $(objects)
	cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h

.PHONY : clean
clean :
	-rm edit $(objects)

3.1.4 改進版3:另類風格的Makefile(建議不用)

objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o

edit : $(objects)
	cc -o edit $(objects)

$(objects) : defs.h
kbd.o command.o files.o : command.h
display.o insert.o search.o files.o : buffer.h

.PHONY : clean
clean :
	rm edit $(objects)
這種風格不利於理清依賴關係,如果有新檔案加入,會顯得非常複雜。不易維護。

3.2 C檔案Makefile規則

3.2.1 顯示規則

顯式規則說明了,如何生成一個或多的的目標檔案。這是由Makefile的書寫者明顯指出,要生成的檔案,檔案的依賴檔案,生成的命令。

3.2.2 隱晦規則

由於我們的make有自動推導的功能,所以隱晦的規則可以讓我們比較粗糙地簡略地書寫Makefile,這是由make所支援的。

3.2.3 變數定義

在Makefile中我們要定義一系列的變數,變數一般都是字串,這個有點你C語言中的巨集,當Makefile被執行時,其中的變數都會被擴充套件到相應的引用位置上。

1,自動化變數
其實有很多個,比如[email protected] $< $? $^等
常用的還是[email protected] $< $^這三個,所以這裡整理下這三個的用法:
  1 [email protected]
         比如對於依賴關係   test.o : a.c b.c c.c   
         [email protected]表示的是當前依賴關係的目標集合,這裡就是test.o
   2 $<
         如上例中,就是後面依賴集合中的第一個a.c
 而對於  %.o : %.c這樣的%匹配,實際上是會展開成一條一條,比如test.o : test.c,所以其$<表示的是test.c
   3 $^
 如上例中,就是後面依賴集合中的所有的a.c b.c c.c

2,支援的萬用字元

make支援三各萬用字元:“*”,“?”和“[...]”

用在命令中:

clean:
	rm -f *.o
用在依賴中:
print: *.c
	lpr -p $?
	touch print
用在變數定義中:
#不對,*不會展開
objects = *.o
#正確用法,會展開*
objects := $(wildcard *.o)

3.2.4 檔案指示

1,在一個Makefile中引用另一個Makefile

#filename可以是當前作業系統Shell的檔案模式(可以保含路徑和萬用字元)
include <filename>   
#-include表示無論include過程中出現什麼錯誤,都不要報錯繼續執行。
-include <filename>  

示例:include foo.make *.mk $(bar)

filename可以是當前作業系統Shell的檔案模式(可以保含路徑和萬用字元)

另一個是指根據某些情況指定Makefile中的有效部分,就像C語言中的預編譯#if一樣;

還有就是定義一個多行的命令。有關這一部分的內容,我會在後續的部分中講述。

3.2.5 註釋

註釋用"#"

3.2 C plus plus檔案makefile規則

A.h:

#include <iostream>
using namespace std;

#ifndef A_H
#define A_H
class A
{
	int a;
public:
	A();
	A(int a);
	void printA();
	};
#endif

A.cpp:
/*
 * A.cpp
 *
 *  Created on: 2012-2-28
 *      Author: administrator
 */

#include "A.h"

A::A()
{
	a=9;
	}
A::A(int a)
{
	this->a=a;
	}
void A::printA()
{
	cout<<a<<endl;
	}

main.cpp:
//============================================================================
// Name        : Test1.cpp
// Author      : gexing
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
using namespace std;
#include "A.h"
int main()
{
	A a1;
	A a2(5);
	a1.printA();
	a2.printA();
	return 0;
}

makefile:
main   :   main.o   A.o
	g++   -o  main A.o   main.o   
main.o   :   main.cpp A.h
	g++   -c   main.cpp
A.o   :   A.cpp	A.h
	g++   -c   A.cpp 
clean: 
	rm -rf *.o
do:
	./test

執行命令:

#make
#make clean
#./main或者make do

4,工具gdb:原始碼級除錯工具

4.1 編譯

為了使 gdb 正常工作, 你必須使你的程式在編譯時包含除錯資訊. 除錯資訊包含你程式裡的每個變數的型別和在可執行檔案裡的地址對映以及原始碼的行號.  gdb 利用這些資訊使原始碼和機器碼相關聯.
在編譯時用 -g 選項開啟除錯選項. 

gcc -g eg.c -o eg

4.2 gdb外部引數

引數 說明
-h help,幫助
-c File 把File作為core dump來執行。
-n 不從任何.gdbinit初始化檔案中執行命令。
通常情況下,這些檔案中的命令是在所有命令選項和引數處理完後才執行。
-batch 執行batch模式。
在處理完所有用'-x'選項指定的命令檔案(還有'.gdbi-nit',如果沒禁用)後退出,並返回狀態碼0
-x File 從File中執行GDB命令。
-p pid 繫結程序號
gdb -p 1758 -x gdbcmd -n -batch 這裡直接讓gdb:
不互動(-batch)
不執行.gdbinit(-n)
掛在程序下(-p pid)
執行命令指令碼(-x gdbcmd)並退出

4.3 gdb內部命令

命令 簡寫 描述
file 裝入想要除錯的可執行檔案
list l 列出原始碼(10行)
list          #顯示接上次之後的10行
list func #顯示func之後10行
list -       #上次顯示程式程式碼的前面的十行
list 1      #跳轉到第1行
print p 列印變數
p b            #列印變數,結果b$1 = 15.
p b = 100 #修改變數
p sizeof(b)#列印b長度
set 設定變數
set a = 4
display 顯示變數
display a #在每個斷點或是每執行一步時顯示該敘述值
run r 執行當前被除錯的程式
next n 執行一行原始碼但不進入函式內部
step s 執行一行原始碼而且進入函式內部
continue c 繼續執行
finish 執行現行程式到回到上一層程式為止
quit q 終止 gdb
watch 監控變數,變數變化時列印
watch   #一量表達式值有變化時,馬上停住程式。
rwatch  #當表示式(變數)expr被讀時,停住程式。
awatch #當表示式(變數)的值被讀或被寫時,停住程式。
info watchpoints #列出當前所設定了的所有觀察點。
break b 設定斷點
b 23               #對當前檔案23行中斷
b func             #對函式func進行中斷
b filename.c:23    #對檔案filename.c中指定行23行中斷
b filename.c:func  #對檔案filename.c中指定func位置中斷
b                  #在下一個將被執行的命令設定斷點
b ... if cond      #只有當 cond(C語言) 成立的時候才中斷,break if i=100,表示當i為100時停住程式
clear 清除斷點,格式同 break 
clear filename.c:30
disable 禁止斷點或顯示
disable break 1
disable display 1
delete d 清除斷點,NUM 是在 info break 顯示出來的斷點編號。
delete NUM
call 呼叫函式
call func(args)
kill 終止正在除錯的程式
make 使你能不退出 gdb 就可以重新產生可執行檔案
shell 使你能不離開 gdb 就執行 UNIX shell 命令
catch catch event
當event發生時,停住程式。event可以是下面的內容:
1、throw 一個C++丟擲的異常。(throw為關鍵字)
2、catch 一個C++捕捉到的異常。(catch為關鍵字)
3、exec 呼叫系統呼叫exec時。(exec為關鍵字,目前此功能只在HP-UX下有用)
4、fork 呼叫系統呼叫fork時。(fork為關鍵字,目前此功能只在HP-UX下有用)
5、vfork 呼叫系統呼叫vfork時。(vfork為關鍵字,目前此功能只在HP-UX下有用)
6、load 或 load 載入共享庫(動態連結庫)時。(load為關鍵字,目前此功能只在HP-UX下有用)
7、unload 或 unload 解除安裝共享庫(動態連結庫)時。(unload為關鍵字,目前此功能只在HP-UX下有用)

tcatch event
只設置一次捕捉點,當程式停住以後,應點被自動刪除。。
info i 查詢資訊,如info break
backtrace bt 檢視函式呼叫棧資訊
使用up down命令來檢視上下語句
使用frame 5 來檢視棧中第5條
frame f 進入函式的某層棧
使用frame 5 來檢視棧中第5條
否則會出現No symbol "role" in current context.的報錯
help h 幫助資訊
examine x 檢視記憶體:x/<n/f/u> <addr>
引數 含義 例子
n 記憶體長度 3
f 顯示格式 x [hex]按十六進位制格式顯示變數。
d [decimal]按十進位制格式顯示變數。
u [unsigned decimal]按無符號整型。
o [octal]按八進位制格式顯示變數。
t [binary]按二進位制格式顯示變數。
a [address]按地址格式顯示變數。
c [char]按字元格式顯示變數。
f [float]按浮點數格式顯示變數。
s [string]按字串格式顯示變數。
u 位元組數 b表示單位元組,
h表示雙位元組,
w表示四位元組,
g表示八位元組。

generate-core-file g 主動產生core檔案
set follow-fork-mode [parent|child] 除錯fork父子程序,預設進入父程序

dis  :失效所有斷點

enable 5:有效5號斷點

until 700 :跳出迴圈,直接到700行

b item_serialize_to_db if src->type ==16726  :條件斷點

b scene_recv_client_package if (xypkg.stHeader.nMsgid==8042 && xypkg->stBody.stLogin_pkg.nSelector==8042)

4.4 gdb除錯core檔案

core dump又叫核心轉儲, 當程式執行過程中發生異常, 程式異常退出時, 由作業系統把程式當前的記憶體狀況儲存在一個core檔案中, 叫core dump。類unix作業系統中使用efi格式儲存coredump檔案。

4.4.1 core檔案位置


core檔案生成的位置一般於執行程式的路徑相同。

echo "/corefile/core-%e-%p-%t" > core_pattern,可以將core檔案統一生成到/corefile目錄下,產生的檔名為core-命令名-pid-時間戳。

4.4.2 core檔名稱

檔名一般為core.程序號

4.4.3 系統設定是否產生core dump

命令ulimit:
選項 [options] 含義例子
-H 設定硬資源限制,一旦設定不能增加。 
ulimit – Hs 64;限制硬資源,執行緒棧大小為 64K。
-S 設定軟資源限制,設定後可以增加,但是不能超過硬資源設定。 
ulimit – Sn 32;限制軟資源,32 個檔案描述符。
-a 顯示當前所有的 limit 資訊。 
ulimit – a;顯示當前所有的 limit 資訊。
-c 最大的 core 檔案的大小, 以 blocks 為單位。 
ulimit – c unlimited; 對生成的 core 檔案的大小不進行限制。
-d 程序最大的資料段的大小,以 Kbytes 為單位。 
ulimit -d unlimited;對程序的資料段大小不進行限制。
-f 程序可以建立檔案的最大值,以 blocks 為單位。 
ulimit – f 2048;限制程序可以建立的最大檔案大小為 2048 blocks。
-l 最大可加鎖記憶體大小,以 Kbytes 為單位。 
ulimit – l 32;限制最大可加鎖記憶體大小為 32 Kbytes。
-m 最大記憶體大小,以 Kbytes 為單位。 
ulimit – m unlimited;對最大記憶體不進行限制。
-n 可以開啟最大檔案描述符的數量。 
ulimit – n 128;限制最大可以使用 128 個檔案描述符。
-p 管道緩衝區的大小,以 Kbytes 為單位。 
ulimit – p 512;限制管道緩衝區的大小為 512 Kbytes。
-s 執行緒棧大小,以 Kbytes 為單位。 
ulimit – s 512;限制執行緒棧的大小為 512 Kbytes。
-t 最大的 CPU 佔用時間,以秒為單位。 
ulimit – t unlimited;對最大的 CPU 佔用時間不進行限制。
-u 使用者最大可用的程序數。 
ulimit – u 64;限制使用者最多可以使用 64 個程序。
-v 程序最大可用的虛擬記憶體,以 Kbytes 為單位。 
ulimit – v 200000;限制最大可用的虛擬記憶體為 200000 Kbytes。
#ulimit -c 1024       #設定core檔案大小,這裡的size的單位是blocks,一般1block=512bytes
#ulimit -c unlimited  #設定core檔案可以產生
-c是顯示:core file size          (blocks, -c)

/proc/sys/kernel/core_uses_pid決定core檔案的檔名中是否新增pid作為擴充套件(設定1或0)。
/proc/sys/kernel/core_pattern決定core檔案的檔名格式和位置(當前為core_%p,表示命名格式)。

1,core dump檔案可以配置到/data/corefile/目錄下, 但是不好,因為這樣所有的core(包括程式設計師的)都會匯入到這個位置。
2,core dump檔案可以使用ulimit來設定檔案大小,但是最好設定為0或unlimited。0表示不生成,unlimited表示都生成,其他數字如100表示小於100的才產生。

3,如果想讓修改永久生效,則需要修改配置檔案,如 .bash_profile、/etc/profile或/etc/security/limits.conf。

4.4.4 core輸出位置

一般預設是當前目錄,可以在/proc/sys/kernel中找到core-user-pid,通過
1.使core檔名加上pid號

如果這個檔案的內容被配置成1,那麼即使core_pattern中沒有設定%p,最後生成的core dump檔名仍會加上程序ID。

echo "1" > /proc/sys/kernel/core_uses_pid
2.控制core檔案儲存位置和檔名格式

在程序當前工作目錄的下建立。通常與程式在相同的路可能改變了當前工作目錄。這時core檔案建立在chdir指定的路徑下。有好多程式崩潰了,我們卻找不到core檔案放在什麼位置。和chdir函式就有關係。當然程式崩潰了不一定都產生core檔案。

vi /proc/sys/kernel/core_pattern

通過下面的命令可以更改coredump檔案的儲存位置,若你希望把core檔案生成到/data/coredump/core目錄下(如果在上述檔名中包含目錄分隔符“/”,那麼所生成的core檔案將會被放到指定的目錄中):

echo "/data/coredump/core"> /proc/sys/kernel/core_pattern  <span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255);">   </span>

如果是預設輸出在本地目錄下:

echo "core_%e_%p_%t"> /proc/sys/kernel/core_pattern   

以下是引數列表:

    %p - insert pid into filename 新增pid
    %u - insert current uid into filename 添加當前uid
    %g - insert current gid into filename 添加當前gid
    %s - insert signal that caused the coredump into the filename 新增導致產生core的訊號
    %t - insert UNIX time that the coredump occurred into filename 新增core檔案生成時的unix時間
    %h - insert hostname where the coredump happened into filename 新增主機名
    %e - insert coredumping executable name into filename 新增命令名

4.4.5 core檔案產生原因

關於Core產生的原因很多,比如過去一些Unix的版本不支援現代Linux上這種GDB直接附著到程序上進行除錯的機制,需要先向程序傳送終止訊號,然後用工具閱讀core檔案。在Linux上,我們就可以使用kill向一個指定的程序傳送訊號或者使用gcore命令來使其主動出Core並退出。如果從淺層次的原因上來講,出Core意味著當前程序存在BUG,需要程式設計師修復從深層次的原因上講,是當前程序觸犯了某些OS層級的保護機制,逼迫OS向當前程序傳送諸如SIGSEGV(即signal 11)之類的訊號, 例如訪問空指標或陣列越界出Core,實際上是觸犯了OS的記憶體管理,訪問了非當前程序的記憶體空間,OS需要通過出Core來進行警示,這就好像一個人身體記憶體在病毒,免疫系統就會通過發熱來警示,並導致人體發燒是一個道理(有意思的是,並不是每次陣列越界都會出Core,這和OS的記憶體管理中虛擬頁面分配大小和邊界有關,即使不出Core,也很有可能讀到髒資料,引起後續程式行為紊亂,這是一種很難追查的BUG)。

4.4.6 例子test.c

例子還是比較難找的,比如除0等會再編譯階段檢測到報錯。

/*test.c*/
#include <stdio.h>
void a()
{
    char *p = NULL;
    printf("%d/n", *p);
}

int main()
{
    a();
    return 0;
}
編譯:
gcc -g -o test test.c
執行:
$ ./test
結果:
Segmentation fault (core dumped)

並生成core檔案:core.25805

除錯:

gdb [exec file] [core file]

gdb ./test core.25805
可以使用backtrace或where方法來檢查程式執行到哪裡
[New LWP 25805]
Core was generated by `./core_dump_test'.
Program terminated with signal 11, Segmentation fault.
#0  0x00000000004004d8 in a () at core_dump_test.c:6
6           printf("%d/n", *p);
Missing separate debuginfos, use: debuginfo-install glibc-2.14.90-24.fc16.9.x86_64
(gdb) backtrace
#0  0x00000000004004d8 in a () at core_dump_test.c:6
#1  0x0000000000400502 in main () at core_dump_test.c:11
(gdb)
#系統生成的core檔案
gdb -c core_8122
可以檢視到什麼命令生成了這個core,等資訊。

4.5 gdb除錯帶引數程式

程式執行引數設定:
set args 可指定執行時引數。(如:set args 10 20 30 40 50) 
show args 命令可以檢視設定好的執行引數。 

4.6 gdb除錯正在執行的程序

4.6.1 先gdb後起程序

#gdb server
>r

4.6.2 先起程序後gdb

這種情況一般在於該指令碼是開機啟動的,沒辦法先gdb後啟動程序。

#gdb server 5566  #5566是程序號
>b 58
>c
>detach

#gdb -p 5566
>b 58
>c
>detach

#gdb
>attach 5566
>b 58 
>c
>detach

5 linux發行版本分類

Linux 的發行版本可以大體分為三類,
1,一類是商業公司維護的發行版本【以著名的Redhat(RHEL)為代表】
Redhat(.rpm  [yum|zypper]),應該稱為Redhat系列,包括
1,RHEL(Redhat Enterprise Linux,也就是所謂的Redhat Advance Server,收費版本)、
2,FedoraCore(由原來的Redhat桌面版本發展而來,免費版本)、CentOS(RHEL的社群克隆版本,免費)。
3,SUSELinux(使用zypper)
2,一類是社群組織維護的發行版本【以 Debian為代表】。
Debian(.deb  [apt-get|dpkg]),或者稱Debian系列,包括Debian和Ubuntu 等。
1,Debian是社群類Linux的典範,是迄今為止最遵循GNU規範的Linux系統。
2,Ubuntu是基於 Debian的unstable版本加強而來

5 Linux下軟體安裝方法總結

5.1 rpm包安裝方式步驟

rpm -ivh soft.version.rpm
rpm(命令) -i  install -v 檢視安裝資訊 -h 以安裝資訊欄顯示安裝進度

5.2 deb包安裝方式步驟

dpkg -i xxx.deb          //安裝deb軟體包
dpkg -r xxx.deb          //刪除軟體包
dpkg -r --purge xxx.deb  //連同配置檔案一起刪除
dpkg -info xxx.deb       //檢視軟體包資訊
dpkg -L xxx.deb          //檢視檔案拷貝詳情
dpkg -l                  //檢視系統中已安裝軟體報資訊
dpkg-reconfigure xxx     //重新配置軟體包

5.3 tar.gz原始碼包安裝方式

1、找到相應的軟體包,比如soft.tar.gz,下載到本機某個目錄;
2、開啟一個終端,su -成root使用者;
3、cd soft.tar.gz所在的目錄;
4、tar -xzvf soft.tar.gz //一般會生成一個soft目錄
5、cd soft
6、你觀察一下這個目錄中包含了以下哪一個檔案:configure、Makefile還是Imake。
1)如果是configure檔案,就執行:
  #./configure 
  #make
  #make install
2)如果是Makefile檔案,就執行:
  #make
  #make install
3)如果是Imake檔案,就執行:
  #xmkmf
  #make
  #make install
7、刪除安裝時產生的臨時檔案:
  #make clean 
  解除安裝軟體:
  #make uninstall

5.4 apt方式安裝

sudo apt-cache search softname    //搜尋軟體包
sudo apt-get install softname     //安裝軟體
sudo apt-get remove softname      //解除安裝軟體
sudo apt-get remove --purge softname //解除安裝並清除配置
sudo apt-get update               //更新軟體資訊資料庫
【命令“sudo apt-get update”用來從軟體源伺服器獲取最新的可用軟體包的列表,在/etc/apt/sources.list檔案中添加了某個軟體源伺服器的地址後,需要執行上面的命令來更新資訊.】

5.5 yum方式安裝

列出資源庫中所有可以安裝或更新的rpm包
# yum list

列出資源庫中特定的可以安裝或更新以及已經安裝的rpm包的資訊
# yum info perl           //列出perl 包資訊
# yum info perl*          //列出perl 開頭的所有包的資訊

搜尋匹配特定字元的rpm包
# yum search perl         //在包名稱、包描述等中搜索

安裝rpm包
# yum install perl        //安裝perl 包
# yum install perl*       //安裝perl 開頭的包

刪除rpm包,包括與該包有倚賴性的包
# yum remove perl*        //會刪除perl-* 所有包

更新指定的rpm包,如更新perl
# yum update perl

5.6 zypper方式安裝

設定好源以後,就需要先重新整理源軟體,請耐心等待,尤其是第一次使用的時候會需要較長時間。
zypper refresh
查詢某個軟體包
zypper search package_name
檢視軟體包資訊
zypper info package_name
安裝某個軟體包
zypper install package_name
解除安裝某個軟體包
zypper remove package_name
升級某個軟體包
zypper update package_name

5.7 bin檔案安裝

如果你下載到的軟體名是soft.bin,一般情況下是個可執行檔案,安裝方法如下:
1、開啟一個終端,su -成root使用者;
2、chmod +x soft.bin
3、./soft.bin //執行這個命令就可以安裝軟體了

5.8 不需要安裝的軟體

有了些軟體,比如lumaqq,是不需要安裝的,自帶jre解壓縮後可直接執行。假設下載的是lumaqq.tar.gz,使用方法如下:
1、開啟一個終端,su -成root使用者;
2、tar -xzvf lumaqq.tar.gz //這一步會生成一個叫LumaQQ的目錄
3、cd LumaQQ
4、chmod +x lumaqq //設定lumaqq這個程式檔案為可執行
5、此時就可以執行lumaqq了,用命令./lumaqq即可,但每次執行要輸入全路徑或切換到剛才生成的LumaQQ目錄裡
6、為了保證不設定路徑就可以用,你可以在/bin目錄下建立一個lumaqq的連結,用命令ln -s lumaqq /bin/ 即可,以後任何時候開啟一個終端輸入lumaqq就可以啟動QQ聊天軟體了
7、如果你要想lumaqq有個選單項,使用選單編輯工具,比如Alacarte Menu Editor,找到上面生成的LumaQQ目錄裡的lumaqq設定一個選單項就可以了,當然你也可以直接到/usr/share/applications目錄,按照裡面其它*.desktop檔案的格式生成一個自己的desktop檔案即可。


建議開發者們不要用red hat/red flag/suse等第一代Linux作業系統,用這些除了方便(也就是說比較傻瓜型)、介面豪華點外沒什麼好。用debian/ubuntu等第二代吧,apt命令安裝軟體是最簡單的。apt命令會自動解決軟體安裝過程中的依賴問題,會把沒有的包安裝上,會把版本低的包自動升級,當然,都是要經你確認一次的。
如果你使用Red Hat等第1代Linux系統,安裝軟體是比較麻煩的事,rpm -ivh softA.rpm是用來安裝softA軟體的,但通常情況下可能遇到的問題是提示說需要安裝softB1, softB2, softB3等一堆軟體,然後你安裝softB1軟體包時,可能又會提示你說需要安裝softC1, softC2, softC3, softC4等一堆軟體……這樣一來你就只夠時間到處去找這些軟體包了。光碟上沒有就得去網上下載,網上還得搜尋半天,時間都花在搜尋軟體包了。而且就算找到這些軟體包,還可能會遇到的問題是:softC2軟體包必須在softC1軟體包之前安裝才可以,順序錯了也安裝不成功。但這誰知道呢?難啊。所以,你沒有時間來安裝體驗軟體的功能了,更別說開發軟體了。
建議你安裝第2代Linux作業系統,典型的是Debian Linux和Ubuntu Linux,我之前在文章“如何在安裝了Windows作業系統的電腦上安裝Linux作業系統”裡提到一個簡明安裝手冊,你下載來照著操作就可以安裝Ubuntu了。
第2代作業系統在安裝軟體方面相當簡單:第一步,搜尋你要的軟體,比如你要找一個遊戲軟體,它的名稱叫myward,這個遊戲軟體的說明是:my own war game。搜尋這個軟體包就只需要輸入命令apt-cache search myward,或者輸入軟體名稱的一部分apt-cache search war,或者你不知道軟體名稱,輸入軟體說明裡的一部分文字apt-cache search game,都可以找到個軟體,找到後進行第二步,只需要輸入apt-get install myward,即後面跟上軟體名稱就可以安裝了。


5.9 在Debian系統上安裝RadHat系統的.rpm檔案

1、獲取正向rpm->deb軟體alien
2、sudo apt-get install alien
3、然後就可以對rpm 格式的軟體轉換成deb 格式了:alien -d *.rpm
4、然後就可以用deb 的安裝方式進行軟體安裝,也可以不需轉換而直接對rpm 包進行安裝:alien -i *.rpm,更多的alien 使用方法可以用-h 引數檢視相應說明文

6 Linux中常用巨集定義

6.1 防止一個頭檔案被重複包含

#ifndef COMDEF_H
#define COMDEF_H

//標頭檔案內容 …
#endif

6.2 重新定義一些型別

防止由於各種平臺和編譯器的不同,而產生的型別位元組數差異,方便移植。
typedef  unsigned long int  uint32;      /* Unsigned 32 bit value */

6.3 得到指定地址上的一個位元組或字

#define  MEM_B( x )  ( *( (byte *) (x) ) )
#define  MEM_W( x )  ( *( (word *) (x) ) )

6.4 求最大值和最小值

#define  MAX( x, y )  ( ((x) > (y)) ? (x) : (y) )
#define  MIN( x, y )  ( ((x) < (y)) ? (x) : (y) )

6.5 得到一個field在結構體(struct)中的偏移量

#define FPOS( type, field )   ( (dword) &(( type *) 0)-> field )

6.6 得到一個結構體中field所佔用的位元組數

#define FSIZ( type, field ) sizeof( ((type *) 0)->field )

6.7 按照LSB格式把兩個位元組轉化為一個word

#define  FLIPW( ray ) ( (((word) (ray)[0]) * 256) + (ray)[1] )

6.8 按照LSB格式把一個word轉化為兩個位元組

#define  FLOPW( ray, val ) 
(ray)[0] = ((val) / 256); 
(ray)[1] = ((val) & 0xFF)

6.9 得到一個變數的地址(word寬度)

#define  B_PTR( var )  ( (byte *) (void *) &(var) )
#define  W_PTR( var )  ( (word *) (void *) &(var) )

6.10 得到一個字的高位和低位位元組

#define  WORD_LO(xxx)  ((byte) ((word)(var) & 255))
#define  WORD_HI(xxx)  ((byte) ((word)(var) >> 8))

6.11 返回一個比X大的最接近的8的倍數

#define RND8( x )       ((((x) + 7) / 8 ) * 8 )

6.12 將一個字母轉換為大寫

#define  UPCASE( c ) ( ((c) >= ’a' && (c) <= ’z') ? ((c) - 0×20) : (c) )

6.13 判斷字元是不是10進值的數字

#define  DECCHK( c ) ((c) >= ’0′ && (c) <= ’9′)

6.14 判斷字元是不是16進值的數字

#define  HEXCHK( c ) ( ((c) >= ’0′ && (c) <= ’9′) ||
((c) >= ’A' && (c) <= ’F') ||
((c) >= ’a' && (c) <= ’f') )

6.15 防止溢位的一個方法

#define  INC_SAT( val )  (val = ((val)+1 > (val)) ? (val)+1 : (val))

6.16 返回陣列元素的個數

#define  ARR_SIZE( a )  ( sizeof( (a) ) / sizeof( (a[0]) ) )

6.17 對於IO空間對映在儲存空間的結構,輸入輸出處理

#define inp(port)         (*((volatile byte *) (port)))
#define inpw(port)        (*((volatile word *) (port)))
#define inpdw(port)       (*((volatile dword *)(port)))

#define outp(port, val)   (*((volatile byte *) (port)) = ((byte) (val)))
#define outpw(port, val)  (*((volatile word *) (port)) = ((word) (val)))
#define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))

6.18 使用一些巨集跟蹤除錯

ANSI標準說明了五個預定義的巨集名。它們是:
__LINE__
__FILE__
__DATE__
__TIME__
__STDC__
如果編譯不是標準的,則可能僅支援以上巨集名中的幾個,或根本不支援。記住編譯程式也許還提供其它預定義的巨集名。
__FILE__ 是內建巨集 代表原始檔的檔名
__LINE__ 是內建巨集,代表該行程式碼的所在行號
__DATE__巨集指令含有形式為月/日/年的串,表示原始檔被翻譯到程式碼時的日期。
__TIME__原始碼翻譯到目的碼的時間作為串包含在__TIME__ 中。串形式為時:分:秒。
__STDC__如果實現是標準的,則巨集__STDC__含有十進位制常量1。如果它含有任何其它數,則實現是非標準的。

可以定義巨集,例如:
當定義了_DEBUG,輸出資料資訊和所在檔案所在行
#ifdef _DEBUG
#define DEBUGMSG(msg,date) printf(msg);printf(“%d%d%d”,date,_LINE_,_FILE_)
#else
#define DEBUGMSG(msg,date)
#endif

6 執行庫

6.1 靜態庫

.a檔案是簡單的把一些.o檔案打包產生的。

6.2 動態庫

6.2.1 動態庫

.so檔案,但和共享庫不同,由程式自己決定什麼時候載入/解除安裝
我的理解是這種是【動態庫中動態載入方式】,在程式開始執行前,程式完全不瞭解這些庫的細節,也不會載入,只有在執行到呼叫這個函式時,才會去動態載入這個庫。

6.2.2 共享庫

.so檔案,在需要時由作業系統自動載入
我的理解是這種是【動態庫中靜態載入方式】,在程式開始執行前,就將載入這些庫。

6.3 動態庫與靜態庫區別

動態庫.so是已經編譯好的二進位制檔案,可以動態載入。這樣不需要每個使用者重新編譯自己的所有檔案(因為.a檔案還是.o的集合,需要再生成為二進位制,所以.a的改動會造成全部需要重新編)

相關推薦

linux-編譯gcc除錯gdb安裝makecore

1,工具gcc:編譯C檔案 1.1. 無選項編譯連結 用法:#gcc test.c 作用:將test.c預處理、彙編、編譯並連結形成可執行檔案。這裡未指定輸出檔案,預設輸出為a.out。1.2. 選項 -o 用法:#gcc test.c -o test 作用:將test.

linux應用程式除錯gdb+gdbserver

rlx平臺 在目標板子上gdbserver ip:port /bin/xxx 在pc上xxxx/xxx-linux-gdb /bin/xxx,進入gdb後target remote ip:port開

手把手教你製作linux U盤啟動盤及安裝Ubuntuwin7雙系統

      linux系統簡介         與Windows系統相比,linux系統有很多優點,在開發中,linux也是一項必不可少的技能。基本後臺伺服器都部署在linux上。linux是基於Un

Linux 平臺下 MySQL 5.5 安裝 說明 示例

一.下載說明 前期的一些準備說明,參考: MySQL 分為Community Server 和 Enterprise Edition。 其中Community Server 可以直接從mysql 的官網下載。Enterprice Edition 只能從Oracl

arm-linux-gdb除錯工具的安裝交叉編譯gdbserver

arm-linux-gdb除錯工具的安裝與交叉編譯gdbserver 分類:嵌入式 開發環境:LPC3250 開發板:安裝linux2.6.39; 交叉編譯工具:arm-none-linux-gnueabi-gcc pc的虛擬機器:Linux version 2.6.32.

Linux學習筆記八】Linux程式設計-編譯(gcc)除錯(gdb)

【注】文章中的所有截圖均為centos下實驗結果,親測命令正確= ̄ω ̄= 【參考資料】《Linux從入門到精通(第2版)》劉憶智 等編著 1、編譯一個C程式:以用vim寫成的summa

linuxgdb安裝除錯

1 安裝gdb 在Debian GNU/Linux Desktop中,應用程式 >> 附件 >> Root Terminal。輸入密碼,在Root許可權下的終端下輸入: apt-get update …… apt-get install 

Linux下編輯、編譯除錯命令總結——gccgdb描述

GCC   gcc是linux系統整合的編譯器。在linux環境下編輯程式,首先需要克服的便是沒有整合開發環境的一鍵式操作所帶來的麻煩。這其中涉及命令列操作、編譯選項的設定、檔案依賴關係的書寫(makefile)等問題。這裡主要介紹的是關於gcc的常用命令列引

Linux 環境下 PHP 擴展的變異編譯安裝

font spa mysql 所有 sqli 技術 php 操作 size (操作系統 Centos7, 已安裝 mysqli 為例) 1,進入到 PHP 解壓後的源碼包的的 ext 文件夾 2,查看是否存在 mysqli 擴展 => ls 3,這裏既是所有 PHP

Linux下的開發工具:vim,gccgdb,makefile以及yum語句安裝軟體

Linux下的開發工具:vim,gcc,gdb,makefile以及yum語句安裝軟體 1. vi/vim  vi/vim都是多模式編譯器,vim是vi的升級版本。vim有12個模式,在這我們先說3種模式,命令模式,插入模式,底行模式。 2. vim基本操作: $vim t

Linux編譯安裝中configure、makemake install各自的作用

./configure是用來檢測你的安裝平臺的目標特徵的。比如它會檢測你是不是有CC或GCC,並不是需要CC或GCC,它是個shell指令碼。 make是用來編譯的,它從Makefile中讀取指令,然後編譯。 make install是用來安裝的,它也從Makefile中讀取指令,安裝到指定

Linux學習_005_Linux下使用命令安裝gcc、g++、gdb

注意:本博文在CentOS7.5版本上進行了測試,不同的版本可能會出現差異。以下均為root使用者下的操作,安裝時請確保你的Linux可以上網。 Linux下使用命令安裝gcc、g++、gdb 使用gcc用來編譯C程式 使用g++用來編譯C++程式 使用gdb來除錯程式

Linux安裝vim gcc/g++ gdb

在Linux下,編輯一個程式碼需要用到vim,編譯c語言需要gcc,編譯c++需要g++,除錯程式需要gdb。這個工具都需要自己進行安裝。那麼他們是怎麼安裝的?vim 1.在命令列輸入vi,檢視vim資訊如下: 2.退出後在命令列輸入ls -a,檢視是否有.vimrc和

linux常用命令以及gccgdb、vim的安裝和配置

1.       linux是一個類unix作業系統       vmware--虛擬出一個硬體環境用於安裝一個作業系統       虛擬機器--在vmware中的這個虛擬的這個硬體環境/安裝的這個作業系統       xshell功能:遠端連線到虛擬機器/伺服器上堆虛擬機器

Linux下重要命令,許可權及gcc/g++,gdb,vim的安裝

Linux重要命令: su 切換使用者 -c<指令>或–command=<指令>:執行完指定的指令後,即恢復原來的身份; -f或——fast:適用於csh與tsch,使shell不用去讀取啟動檔案; -l或——login:改變身份時,

鳥哥的Linux私房菜讀書筆記--核心的編譯安裝

1、編譯核心與核心模組 [[email protected] linux-3.10.89]# make vmlinux <==未經壓縮的核心 [[email protected] linux-3.10.89]# make modules <

Linux編譯動態庫和gdb除錯命令

Linux編譯動態庫和gdb除錯命令TOC IPC命令: 拷貝到當前目錄: cp …/day01/cleanipc . 清除ipc命令: cleanipc zhidao101 all 檢視網路連線: netstat -an | grep 8001 檢視使用者程序: ps -u

飛凌嵌入式(Forlinx)TE/OK6410核心編譯:“make: arm-none-linux-gnueabi-gcc:命令未找到”

Ubuntu10.04下編譯飛凌嵌入式(Forlinx)TE/OK6410開發板提供的核心2.6.36 本以為按照使用者手冊的操作,不會有任何問題的,可能是因為核心是在Unbuntu10.10下測試通過的吧,在Ubuntu10.04下反而出了問題。 已經執行export P

Linux編譯安裝GDB-7.7

    上文中說明了Linux中比較常用的GCC編譯器的編譯安裝方式,當然,光有編譯器還是不夠的,我們還需要一個好用的除錯工具來對程式碼中可能出現的問題進行相應除錯。下面我們就來說說最新版的GDB-7.7的編譯安裝方式(同上文,建議以root使用者身份操作):     1.

ARP報文的傳送接收(Linuxgcc編譯

ARP報文的傳送與接收 這篇文章主要是關於ARP報文的傳送與接收,學習TCP/IP協議,還是多動手做一些測試對協議的理解比較深刻,所以自己寫了一份比較簡單的關於ARP的原始碼, 主要是起到記錄作用,方便以後回顧,當然,如果有大俠能提出問題,幫助我改進缺點是萬