2008-12-24 30 views
7

Làm cách nào để có được một dấu vết ngăn xếp địa chỉ trên Windows mà không sử dụng dbghelp.dll?Làm cách nào để lấy dấu vết ngăn xếp trên Windows mà không sử dụng dbghelp.dll?

Tôi không cần biết các ký hiệu hoặc tên hàm được liên kết với các địa chỉ, tôi chỉ muốn danh sách địa chỉ - một cái gì đó tương tự như backtrace of *nix systems.

Cảm ơn!

+0

Tại sao bạn muốn thực hiện điều này mà không cần DbgHelp.dll. DbgHelp.dll được xây dựng trong Windows, kể từ Windows 2000. Ngoài ra, hãy kiểm tra Stackwalker của Jochen Kalmbach: http://www.codeproject.com/KB/threads/StackWalker.aspx – Cheeso

Trả lời

9

Kiểm tra chức năng CaptureStackBackTrace(), nằm trong Kernel32.dll. Điều này nên làm tất cả những gì bạn cần.

Chụp lại dấu vết ngăn xếp bằng cách đi lên ngăn xếp và ghi lại thông tin cho mỗi khung.

USHORT WINAPI CaptureStackBackTrace(
    __in  ULONG FramesToSkip, 
    __in  ULONG FramesToCapture, 
    __out  PVOID *BackTrace, 
    __out_opt PULONG BackTraceHash 
); 
+1

Có vẻ tốt. Nhưng tôi đang sử dụng VS 2005, và CaptureStackBackTrace no RtlCaptureBackTrace không được định nghĩa trong winbase.h. Tôi sẽ thử theo cách thủ công bao gồm nguyên mẫu hàm cho RtlCaptureBackTrace (...) và xem liệu nó có hiệu quả với tôi hay không. Cảm ơn! – Uhall

+0

Cách tuyệt vời! Tôi đã viết stack truy tìm mã ateast 3 lần và không có ý tưởng này tồn tại. Cảm ơn bạn! – shoosh

+0

@Uhall: Bạn có thể thử cài đặt Windows SDK mới hơn. Máy khách được hỗ trợ tối thiểu được liệt kê là Windows XP mặc dù trang MSDN liệt kê rằng nó được đưa vào trong Windows SDK bắt đầu bằng Windows Vista. –

2

Nếu bạn muốn làm điều này cực kỳ phi portably, bạn chỉ có thể đọc thanh ghi EBP và đi bộ ngăn xếp chính mình. Điều này sẽ chỉ làm việc cho kiến ​​trúc x86, và nó cũng giả định rằng thời gian chạy C bạn đang sử dụng đúng cách khởi tạo EBP thành 0 trước khi gọi hàm đầu tiên.

uint32_t read_ebp(void) 
{ 
    uint32_t my_ebp; 
    __asm 
    { 
     mov ebp, my_ebp 
    } 

    return my_ebp; 
} 

void backtrace(void) 
{ 
    uint32_t ebp = read_ebp(); 

    printf("backtrace:\n"); 

    while(ebp != 0) 
    { 
     printf("0x%08x\n", ebp); 
     ebp = ((uint32_t *)ebp)[1]; 
    } 
} 
+0

Với bản phát hành bản phát hành này sẽ chỉ cung cấp cho bạn một vài khung hình đầu tiên. Để thực sự làm việc này một cách đáng tin cậy, bạn cần đặt "Bỏ qua con trỏ khung" = Không. – shoosh

+0

đích đến trước, vì vậy bạn cần phải mov my_ebp, ebp .. khác hơn là nó khá tuyệt –

1

biến thể trước không làm việc cho tôi (msvc 6), do đó:

unsigned long prev; 
unsigned long addr; 
__asm { mov prev, ebp } 
while(addr!=0) { 
    addr = ((unsigned long *)prev)[1]; 
    printf("0x%08x\n", addr); 
    prev = ((unsigned long *)prev)[0]; 
} 
Adam, nhờ để làm nổi bật đường đi!

Các vấn đề liên quan