2010-04-04 21 views
5

Tôi làm việc trên một ứng dụng lớn và thường xuyên sử dụng WinDbg để chẩn đoán các vấn đề dựa trên tệp DMP từ khách hàng. Tôi đã viết một vài phần mở rộng nhỏ cho WinDbg đã tỏ ra rất hữu ích cho việc kéo các bit thông tin ra khỏi các tệp DMP. Trong mã mở rộng của tôi, tôi thấy mình dereferencing C++ lớp đối tượng trong cùng một cách, hơn và hơn, bằng tay. Ví dụ:Làm cách nào để tạo các đối tượng dựa trên bộ nhớ tệp kết xuất trong phần mở rộng WinDbg?

Address = GetExpression("somemodule!somesymbol"); 
ReadMemory(Address, &addressOfPtr, sizeof(addressOfPtr), &cb); 

// get the actual address 
ReadMemory(addressOfObj, &addressOfObj, sizeof(addressOfObj), &cb); 

ULONG offset; 
ULONG addressOfField; 

GetFieldOffset("somemodule!somesymbolclass", "somefield", &offset); 
ReadMemory(addressOfObj+offset, &addressOfField, sizeof(addressOfField), &cb); 

Đó hoạt động tốt, nhưng như tôi đã viết nhiều tiện ích, với chức năng lớn hơn (và tiếp cận đối tượng phức tạp hơn trong các ứng dụng của chúng tôi các file DMP), tôi đã mong muốn một giải pháp tốt hơn. Tôi có quyền truy cập vào nguồn của ứng dụng riêng của chúng tôi, vì vậy tôi phải có cách để sao chép một đối tượng ra khỏi tệp DMP và sử dụng bộ nhớ đó để tạo một đối tượng thực trong tiện ích mở rộng trình gỡ lỗi mà tôi có thể gọi hàm trên (bằng cách liên kết trong các dll từ ứng dụng của chúng tôi). Điều này sẽ giúp tôi tránh được rắc rối khi lôi kéo mọi thứ ra khỏi DMP bằng tay.

Điều này có thể thực hiện được không? Tôi đã thử những thứ hiển nhiên như tạo một đối tượng mới trong phần mở rộng, sau đó ghi đè nó bằng một ReadMemory lớn trực tiếp từ tệp DMP. Điều này dường như để đưa dữ liệu vào các trường bên phải, nhưng bị bối rối khi tôi cố gắng gọi một hàm. Tôi hình tôi thiếu một cái gì đó ... có lẽ c + + kéo một số vtable funky-ness mà tôi không biết về? Mã của tôi trông giống như sau:

SomeClass* thisClass = SomeClass::New(); 
ReadMemory(addressOfObj, &(*thisClass), sizeof(*thisClass), &cb); 

SAU: Có vẻ như POSSIBLY ExtRemoteTyped từ EngExtCpp là những gì tôi muốn? Có ai đã sử dụng thành công điều này không? Tôi cần phải google lên một số mã ví dụ, nhưng tôi không có nhiều may mắn.

THEO D 2I 2: Tôi đang theo đuổi hai tuyến điều tra khác nhau về vấn đề này.
1) Tôi đang nhìn vào ExtRemoteTyped, nhưng nó xuất hiện lớp này thực sự chỉ là một trợ giúp cho các cuộc gọi ReadMemory/GetFieldOffset. Có, nó sẽ giúp tăng tốc độ những thứ lên ALOT, nhưng không thực sự giúp đỡ khi nói đến tái tạo một đối tượng từ một tập tin DMP. Mặc dù tài liệu rất mỏng, vì vậy tôi có thể hiểu nhầm điều gì đó. 2) Tôi cũng đang tìm cách sử dụng ReadMemory để ghi đè lên một đối tượng được tạo trong tiện ích mở rộng của tôi với dữ liệu từ tệp DMP. Tuy nhiên, thay vì sử dụng sizeof (* thisClass) như trên, tôi đã nghĩ rằng tôi sẽ chỉ chọn ra các yếu tố dữ liệu, và để lại vtables bị ảnh hưởng.

+0

Câu hỏi tuyệt vời PJ! –

Trả lời

1

Ý tưởng thú vị, nhưng điều này sẽ có hy vọng chỉ hoạt động trên các đối tượng đơn giản nhất. Ví dụ, nếu đối tượng chứa con trỏ hoặc tham chiếu đến các đối tượng khác (hoặc vtables), thì đối tượng đó sẽ không sao chép rất tốt sang một không gian địa chỉ mới.

Tuy nhiên, bạn có thể có được đối tượng 'proxy' để làm việc khi bạn gọi các phương thức proxy họ thực hiện cuộc gọi thích hợp tới ReadMemory() để nhận thông tin. Điều này nghe có vẻ là một chút công bằng, và tôi nghĩ rằng nó sẽ phải là nhiều hơn hoặc ít hơn một bộ mã tùy chỉnh cho mỗi lớp bạn muốn proxy. Có lẽ có một cách tốt hơn để giải quyết vấn đề này, nhưng đó là những gì xảy đến với tôi trên đầu tôi.

+0

Vâng, tôi cũng đang nghĩ như vậy. Tôi nghĩ rằng các con trỏ sẽ không hoạt động tốt, trừ khi tôi theo con trỏ với ReadMemory và sao chép dữ liệu đó. Nhưng tôi vẫn có thể gọi các chức năng trên lớp, phải không? Ý của bạn về vtables không sao chép tốt? – pj4533

+0

@ pj4533: bạn có thể gọi các hàm trên lớp, nhưng nếu lớp chứa con trỏ hoặc tham chiếu các hàm đó sẽ tìm thấy một đối tượng rất lộn xộn. Bạn có thể có thể có được với những gì bạn đang làm với các lớp học POD và có thể một số lớp học đơn giản khác, nhưng nó sẽ là công cụ khá iffy. Tất nhiên, bạn cần đảm bảo rằng bạn đang xây dựng tiện ích mở rộng trình gỡ lỗi theo cách bố cục đối tượng sẽ giống nhau. –

+0

@ pj4533: bởi vtables không sao chép tốt, tôi có nghĩa là con trỏ vtable đó là trong bất kỳ lớp học với một chức năng ảo. Nó chỉ ra số tiền cho một bảng nhảy hàm, và vị trí của bảng đó sẽ ở các địa chỉ khác nhau trong các tiến trình gỡ lỗi và trình gỡ lỗi. –

0

Tôi biết việc lưu trữ bộ nhớ luôn là cách để nhận thông tin chẩn đoán, nhưng với ETW dễ dàng hơn nhiều và bạn nhận được thông tin cùng với ngăn xếp cuộc gọi bao gồm các cuộc gọi hệ thống thông tin và mã người dùng. MS đã làm điều này cho tất cả các sản phẩm của họ bao gồm Windows và VS.NET.

Đó là cách gỡ lỗi không xâm nhập. Tôi đã thực hiện gỡ lỗi tương tự cho rất lâu và bây giờ với ETW tôi có thể giải quyết hầu hết các vấn đề của khách hàng mà không tốn nhiều thời gian bên trong trình gỡ rối. Đây là hai xu của tôi.

+0

Tôi thực sự chưa học được nhiều thứ về Event Tracing cho Windows. Có vẻ như nó đòi hỏi nhiều sửa đổi mã (bổ sung các cuộc gọi đến sự kiện truy tìm nhật ký api)? Điều đó thực sự là không thể đối với tất cả các phiên bản khác nhau của ứng dụng của chúng tôi, chưa kể đến nhiều phiên bản cũ mà chúng tôi vẫn hỗ trợ đã có sẵn trong lĩnh vực này! – pj4533

0

Tôi tiếp cận một cái gì đó tương tự khi hack một phần mở rộng tracer rò rỉ gdi cho windbg.Tôi đã sử dụng một container stl để lưu trữ dữ liệu trong máy khách và cần một cách để truyền dữ liệu từ phần mở rộng. Tôi đã kết thúc việc triển khai thực hiện các phần của hash_map mà tôi cần trực tiếp trên phần mở rộng bằng ExtRemoteTyped, điều này đã thỏa mãn nhưng tôi mất một lúc để tìm ra; o) Here là mã nguồn.

+0

Điều đó thật thú vị, nhưng tôi nghĩ mục tiêu thực sự của tôi là có thể truyền các đối tượng từ một tệp kết xuất trở lại thông qua các thường trình tiện ích khác, và xử lý chúng chính xác như các kiểu đối tượng (ví dụ: không phải là loại có nguồn gốc từ xa) . – pj4533

1

Tôi đã kết thúc chỉ sau linh cảm ban đầu của mình và sao chép dữ liệu từ tệp dmp vào một đối tượng mới. Tôi đã thực hiện tốt điều này bằng cách làm cho đối tượng bao bọc từ xa như thế này:

class SomeClassRemote : public SomeClass 
{ 
protected: 
    SomeClassRemote (void); 
    SomeClassRemote (ULONG inRemoteAddress); 

public: 
    static SomeClassRemote *  New(ULONG inRemoteAddress); 
    virtual ~SomeClassRemote (void); 

private: 

    ULONG     m_Address; 

}; 

Và trong việc thực hiện:

SomeClassRemote::SomeClassRemote (ULONG inRemoteAddress) 
{ 
    ULONG cb; 

    m_Address = inRemoteAddress; 

    // copy in all the data to the new object, skipping the virtual function tables 
    ReadMemory(inRemoteAddress + 0x4, (PVOID) ((ULONG)&(*this) +0x4), sizeof(SomeClass) - 4, &cb); 
} 

SomeClassRemote::SomeClassRemote(void) 
{ 
} 

SomeClassRemote::~SomeClassRemote(void) 
{ 
} 

SomeClassRemote* SomeClassRemote::New(ULONG inRemoteAddress) 
{ 
    SomeClassRemote*x = new SomeClassRemote(inRemoteAddress); 

    return (x); 
} 

Đó là những điều cơ bản, nhưng sau đó tôi thêm ghi đè cụ thể trong khi cần thiết để lấy thêm thông tin từ tệp dmp. Kỹ thuật này cho phép tôi truyền các đối tượng từ xa mới này trở lại mã nguồn ban đầu của chúng tôi để xử lý trong các hàm tiện ích khác nhau, vì chúng được bắt nguồn từ lớp gốc. Nó chắc chắn SEEMS như tôi sẽ có thể templatize này bằng cách nào đó ... nhưng luôn luôn có vẻ là một số lý do mà mỗi lớp được thực hiện nhẹ khác nhau, ví dụ một số đối tượng phức tạp hơn của chúng tôi có một vài vtables, cả hai mà phải được bỏ qua.