動態

詳情 返回 返回

解決:Reworks上開發node-exporter報錯—內存篇 - 動態 詳情

Reworks為嵌入式實時操作系統,arm架構

編譯報錯

1.報錯:編譯庫缺失
分析:__atomic_load_8,屬於原子操作庫libatomic
正則表達式庫 libregex相關函數 : __atomic_store_8 中的 "8" 代表8 字節,也就是64 位操作。意味着在編譯器確定 self->r_value 的類型時,它被判定為 64 位類型(例如 long longdouble),因此需要 64 位的原子操作。
解決:換成64位qemu

2.從內存讀出來的數據是u32類型,但是prom_counter_add()傳入的r_value是double型,更改強制類型轉化

運行報錯(在64位QEMU中跑elf鏡像)

1.調用初始化函數foo_metric_init報錯:系統異常以及堆棧回溯,訪問了無效內存

image.png
問題定位: r = pthread_rwlock_init(self->lock, NULL);初始化失敗返回非零值,導致進入destyoy函數

分析:根據堆棧信息,最頂的函數通常為異常函數,向下依次是它的上層調用關係。所以最可能的異常發生在 prom_linked_list_purge 函數,極有可能是這個函數在執行過程中訪問了無效的內存,進而引發了數據中止異常
從寄存器值看,X0通用寄存器可能訪問了無效地址(例如 NULL 指針)

原因:多次銷燬或釋放內存

解決:要單獨在資源配置裏勾選【讀寫鎖模塊】

調試過程:在prom_map.c中把maxsize改成2,方便調試,原來是32 #define PROM_MAP_INITIAL_SIZE 2

2.輸出的鍵值對和正確的對不上
image.png

分析:懷疑是執行完返回的時候報錯

image.png

image.png

調完是正確的

注:如果要打印 size_t 類型的整數值,應該使用 %zu 格式符來打印 size_t 類型的數據。

3.跑完之後報錯:
image.png

分析:問題出在prom_gauge_set()函數上,應該是在運行這個函數的過程中的異常和崩潰日誌。報錯信息這麼長的原因:程序陷入了異常處理的循環,重複調用異常處理函數default_exception_handlerreworks_exception_handler,在異常處理函數中又出發了異常,沒有一個異常被解決,所以棧幀越來越長。

thread_handler 在處理線程時調用了其他函數,可能是從 UserInitupdate 再到 prom_gauge_set 的鏈條。在某個函數調用中,棧幀可能被覆蓋,導致返回地址被修改為無效的值(例如 0x415A2E1000000000)。

update() 結束,函數返回時,程序嘗試跳轉到這個無效地址,導致 Data Abort。由於 prom_gauge_set() 在圖中標註了異常的地址 0x802665bc

在arm體系結構中,當程序執行BL指令進行函數調用時,LR保存返回地址,函數執行完成後會使用RET指令從LR中讀取返回地址進行跳轉。
Exception Program Counter(PC)程序計數器:發生異常時執行指令的地址(可以定位異常)
exception stack pointer(SP):發生異常時的棧指針
DFSR:狀態碼,在 ARM 架構中,不同的 DFSR 值代表不同的異常原因。
DFAR:程序試圖訪問該地址的內存,但是發生了異常。

PC是發生異常時的指令位置,DFAR是發生異常時的內存位置。

stack frame:函數調用棧
FP (Frame Pointer): 棧幀指針,指向當前棧幀的基地址。
LR (Link Register): 通常存儲函數返回地址。
CPSR: 當前程序狀態寄存器,保存狀態標誌和當前的 CPU 模式。
Instruction Abort 取指異常,處理器試圖獲取一條指令(即嘗試讀取並執行一條指令)時發生的異常
Data Abort 數據訪問異常,處理器嘗試訪問數據(讀或寫操作)時發生的異常。

異常信息解讀:
(1)第一次異常
Exception Program Counter:0x415A2E1000000000,程序試圖執行位於 0x415A2E1000000000 處的指令,但該地址是無效的。所以不會執行指令也不會訪問內存,導致instruction abort異常。
DFAR is 0x415A2E1000000000 程序在這個地址處嘗試執行一條指令,並且這條指令試圖訪問同一個地址

(2)第二次異常
發生instruction abort異常後,程序自動進入異常處理流程,在處理過程中,又一次異常data abort,因為訪問了無效內存 0x755F6C656E726573,此時異常指令的位置是有效的為0x802079B0

(3)後續異常
依舊是在異常處理過程中的異常,所以和第二次一樣,進入了循環。
異常原因分析:PC被修改為0x415A2E1000000000,棧上的返回地址被錯誤地覆蓋成了 0x415A2E1000000000。當程序從當前函數返回時,會試圖跳轉到這個錯誤的地址執行。

解決:

mapMi_t *mapMemInfo = (mapMi_t *)malloc(4 * sizeof(mapMi_t));
parseMemInfo(&mem, mapMemInfo);
//mapMemInfo沒有分配內存!導致覆蓋了棧上的返回地址,報錯

3.buf輸出是空的
原因:初始化創建收集器時,先添加了收集器裏的指標,結果在註冊收集器到註冊表裏時又重新創建了一個新的收集器,導致註冊進去的收集器裏沒有任何指標,是空的。

移植成功後的效果展示:
image.png
image.png
image.png
image.png
image.png

Add a new 評論

Some HTML is okay.