2013-09-08 33 views
5

Trong trang người đàn ông, những backtrace() chức năng trên Linux nói:Thay thế cho backtrace() trên Linux có thể tìm thấy biểu tượng cho chức năng tĩnh

Lưu ý rằng tên của chức năng "tĩnh" không được tiếp xúc, và won không có sẵn trong backtrace.

Tuy nhiên, với kích hoạt những biểu tượng gỡ lỗi (-g), các chương trình như addr2linegdb vẫn có thể có được tên của chức năng tĩnh. Có cách nào để có được tên của các hàm tĩnh lập trình từ bên trong quá trình không?

Trả lời

2

Có, bằng cách kiểm tra tệp thực thi của riêng nó (/proc/self/exe) bằng cách sử dụng ví dụ: libbfd hoặc thư viện phân tích tệp ELF, để phân tích cú pháp các ký hiệu thực tế. Về cơ bản, bạn muốn viết mã C mà không tương đương với một cái gì đó giống như

env LANG=C LC_ALL=C readelf -s executable | awk '($5 == "LOCAL" && $8 ~ /^[^_]/ && $8 !~ /\./)' 

Theo như tôi biết, giao diện mối liên kết động trong Linux (<dlfcn.h>) không trả lại địa chỉ cho (địa phương) những biểu tượng tĩnh.

Cách tiếp cận đơn giản và mạnh mẽ là thực hiện readelf hoặc objdump từ chương trình của bạn. Lưu ý rằng bạn không thể cung cấp đường dẫn tệp giả /proc/self/exe cho các tệp đó vì nó luôn đề cập đến quá trình thực thi của chính quy trình đó. Thay vào đó, bạn phải sử dụng ví dụ. realpath("/proc/self/exe", NULL) để có được đường dẫn tuyệt đối được cấp phát động cho tệp thi hành hiện tại mà bạn có thể cung cấp cho lệnh. Bạn cũng chắc chắn muốn đảm bảo môi trường chứa LANG=CLC_ALL=C, sao cho đầu ra của lệnh dễ dàng phân tích cú pháp (và không được bản địa hóa cho bất kỳ ngôn ngữ nào mà người dùng hiện tại thích). Điều này có thể cảm thấy một chút kludgy, nhưng nó chỉ yêu cầu gói binutils được cài đặt để hoạt động và bạn không cần phải cập nhật chương trình hoặc thư viện của mình để theo kịp những phát triển mới nhất, vì vậy tôi nghĩ rằng đó là một cách tiếp cận khá tốt .

Bạn có muốn một ví dụ không?

Một cách để dễ dàng hơn, là tạo các mảng riêng biệt với thông tin ký hiệu tại thời gian biên dịch. Về cơ bản, sau khi các tập tin đối tượng được tạo ra, một file nguồn riêng biệt được tạo động bằng cách chạy objdump hoặc readelf qua các tập tin đối tượng liên quan, tạo ra một loạt các tên và con trỏ tương tự như

const struct { 
    const char *const name; 
    const void *const addr; 
} local_symbol_names[] = { 
    /* Filled in using objdump or readelf and awk, for example */ 
    { NULL, NULL } 
}; 

có lẽ với một chức năng tìm kiếm đơn giản xuất khẩu trong một tệp tiêu đề, để khi tệp thực thi cuối cùng được liên kết, nó có thể truy cập dễ dàng và hiệu quả mảng các ký hiệu cục bộ.

Sao chép một số dữ liệu, vì cùng một thông tin đã có trong tệp thi hành và nếu tôi nhớ chính xác, trước tiên bạn phải liên kết tệp thực thi cuối cùng với mảng sơ khai để có được địa chỉ thực tế cho biểu tượng, sau đó liên kết lại với mảng biểu tượng, làm cho nó hơi phức tạp trong một thời gian biên dịch .. Nhưng nó tránh được sự phụ thuộc vào thời gian chạy trên binutils.

3

Nếu tệp thực thi của bạn (và các thư viện được liên kết) được biên dịch với thông tin gỡ lỗi (tức làvới -g cờ để gcc hoặc g++) sau đó bạn có thể sử dụng Ian Taylor libbacktrace (công bố here) từ bên trong GCC - xem mã của nó here

thư viện đó (BSD cấp phép phần mềm miễn phí) đang sử dụng DWARF thông tin gỡ lỗi từ thực thi và thư viện chia sẻ liên kết bởi quá trình. Xem tập tin README của nó.

Hãy coi chừng nếu bạn biên dịch bằng tối ưu hóa, một số chức năng có thể được gạch chân (ngay cả khi không được gắn thẻ rõ ràng inline trong mã nguồn và static chức năng nội dòng có thể không có mã riêng nào phù hợp). Sau đó backtracing sẽ không nói nhiều về họ.

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