2009-07-29 3 views
5

chương trình của tôi:Tại sao DTrace thỉnh thoảng cho tôi lỗi địa chỉ không hợp lệ nhưng không phải lúc nào?

typedef struct objc_class { 
    struct objc_class *isa; 
    struct objc_class *super_class; 
    char *name; 
    long version; 
    long info; 
    long instance_size; 
    void *ivars; 
    void *methodLists; 
    void *cache; 
    void *protocols; 
} *Class; 
struct objc_object { 
    Class isa; 
}; 

/* Code to extract the class name from arg0 based on a snippet by Bill Bumgarner: http://friday.com/bbum/2008/01/26/objective-c-printing-class-name-from-dtrace/ */ 

objc$target:NSObject:-init:entry { 
    printf("time: %llu\n", timestamp); 
    printf("arg0: %p\n", arg0); 
    obj = (struct objc_object *)copyin(arg0, sizeof(struct objc_object)); 
    printf("obj: %p\n", obj); 
    printf("obj->isa: %p\n", obj->isa); 
    isa = (Class)copyin((user_addr_t)obj->isa, sizeof(struct objc_class)); 
    printf("isa: %p\n", obj->isa); 
    classname = copyinstr((user_addr_t)(isa->name)); 
    printf("classname: %s\n", classname); 
} 

Một số đầu ra:

dtrace: script 'test.d' matched 1 probe 
dtrace: error on enabled probe ID 1 (ID 61630: objc5936:NSObject:-init:entry): invalid address (0x90206b98) in action #8 at DIF offset 28 
dtrace: error on enabled probe ID 1 (ID 61630: objc5936:NSObject:-init:entry): invalid address (0x90206b98) in action #8 at DIF offset 28 
dtrace: error on enabled probe ID 1 (ID 61630: objc5936:NSObject:-init:entry): invalid address (0x90206b98) in action #8 at DIF offset 28 
CPU  ID     FUNCTION:NAME 
    0 61630      -init:entry time: 28391086668386 
arg0: 1291ae10 
obj: 6f0a1158 
obj->isa: a023f360 
isa: a023f360 
classname: NSBitmapImageRep 

    1 61630      -init:entry time: 28391586872297 
arg0: 12943560 
obj: 6f4a1158 
obj->isa: 2fca0 
isa: 2fca0 
classname: GrowlApplicationTicket 

    1 61630      -init:entry time: 28391586897807 
arg0: 152060 
obj: 6f4a1280 
obj->isa: 2fe20 
isa: 2fe20 
classname: GrowlNotificationTicket 

    2 61630      -init:entry time: 28391079142905 
arg0: 129482d0 
obj: 700a1128 
obj->isa: a0014140 
isa: a0014140 
classname: NSDistributedObjectsStatistics 

    2 61630      -init:entry time: 28391079252640 
arg0: 147840 
obj: 700a1250 
obj->isa: a0014780 
isa: a0014780 
classname: NSDistantObjectTableEntry 

Tại sao các lỗi? Nó có vẻ là tên lớp (đó là chỉ %s, và tôi không nhận được bất kỳ lỗi nào nếu tôi xóa nó), nhưng tại sao nó nghĩ rằng một số tên của lớp là con trỏ không hợp lệ?

Có cách nào để nhận được thông báo lỗi thực sự cho tôi biết dòng chương trình DTrace nào của tôi gây ra sự cố không?

Có cách nào để gọi object_getClassName thay vì thực hiện điệu nhảy kiểm tra cấu trúc này không?

Đối với những gì đáng giá, chương trình tôi truy tìm hoạt động tốt — nó không bị lỗi, vì vậy tôi không tin rằng các lớp thực sự bị hỏng.

Trả lời

0

Đây là dự đoán tốt nhất của tôi dựa trên thông tin được cung cấp.

DTrace được thiết kế có mục đích theo cách như vậy để làm cho tập lệnh DTrace trở nên xác định nhất có thể. Đây là lý do tại sao không có câu lệnh if, vòng lặp, chương trình con (ngoài các chương trình con giả được cung cấp bởi chính DTrace), v.v. Điều này là do mã trong kịch bản lệnh DTrace của bạn đang chạy ở chế độ hạt nhân, không phải là vùng người dùng như một phần của quá trình được truy tìm. Nói chung, thông tin mà DTrace có quyền truy cập là "chỉ đọc" (giống như hầu hết các khái quát hóa, điều này không đúng), có thể vặn bit trong chương trình hoặc hạt nhân, với thứ gì đó mạnh mẽ như DTrace có thể khiến mọi thứ rất, rất sai, rất rất nhanh.

Đô la cho bánh rán, sự cố bạn gặp phải là do trang con trỏ trỏ tới không được ánh xạ vào lõi của hệ thống VM. DTrace chỉ có thể kiểm tra thông tin cho bộ nhớ trong lõi - nó không thể bị lỗi kép để có được hệ thống VM tải trong trang.

Bạn có thể giúp giảm bớt vấn đề nếu bạn có ý tưởng về các lớp "nên" và buộc các trang được ánh xạ vào lõi bằng cách thực hiện một loạt các câu lệnh NSLog() giả để tham khảo các lớp học tại một số điểm thuận tiện sớm trong các chương trình của bạn khởi động.

+0

Tôi đã có một suy nghĩ về đêm qua. Thiết kế của DTrace giữ số lượng 'mã' chạy trong hạt nhân đến mức tối thiểu, và là 'an toàn' càng tốt. Độ phân giải tên biểu tượng xảy ra bên ngoài hạt nhân. Hạt nhân chỉ ghi lại địa chỉ trong bộ đệm, một chương trình bên ngoài dịch thành một cái gì đó có thể đọc được sau khi thực tế. Ý tưởng là - tại sao không thêm độ phân giải tên lớp ObjC vào một trong những hoạt động "bên ngoài hạt nhân" đó? Có thể có giá trị một chút điều tra để xem nó có khả thi hay không, và sau đó báo cáo lỗi RFE cho Apple. – johne

2

Tôi chưa hoàn toàn tự theo dõi điều này. Có thể DTrace đang cố gắng giải quyết một số ký hiệu Objective-C. Mặc dù DTrace là một cơ sở truy tìm động nhưng nó không hoạt động tốt với Objective-C tự động tải mọi thứ khi chạy. Khi Objective-C tải các lớp mới, vv DTrace phải giải quyết vấn đề này và mất một chút thời gian, đặc biệt là khi ứng dụng của bạn mới bắt đầu. Ngay cả khi nó tải các thứ mới, và ứng dụng objc của bạn vẫn đang nạp các lớp mới vào thời gian chạy objc, DTrace có thể bị sai và in các phương thức sai (nếu bạn quan tâm đến việc xem các phương thức đặt hàng chính xác đang được thực thi) , in kết quả thời gian không chính xác, v.v.

5

Colin khá gần đúng.

Xem:

http://www.friday.com/bbum/2008/01/03/objective-c-using-dtrace-to-trace-messages-to-nil/

Nhiều khả năng hơn không, bạn cần phải thiết lập các biến môi trường DYLD_SHARED_REGION để avoid. dtrace chỉ thực sự hoạt động dựa trên bộ nhớ được ánh xạ thực sự nằm trong bộ nhớ vật lý.

Bạn có thể tìm ra những gì còn thiếu bằng cách sử dụng công cụ dòng lệnh vmmap.

Thực hiện vmmap PID trên ứng dụng của bạn sau khi các thông báo lỗi trên được tạo. Nhìn vào đầu ra, xem những địa chỉ nào trong vùng như 0x90206b98 rơi vào. Với địa chỉ đó, nó có thể nằm trong một đoạn bộ nhớ chia sẻ không thể ghi được mà có lẽ không phải là cư dân và, do đó, dtrace không thể đọc từ nó.

3

Lỗi này xảy ra khi copyin/copyinstr được sử dụng trên trang chưa bị lỗi. Cách giải quyết chung là để cho hàm sử dụng dữ liệu được đề cập, sau đó copyin [str] trong một mệnh đề return :::. Ví dụ:

syscall::open:entry 
{ 
    self->filename = arg0; /* Hang on to the file name pointer. */ 
} 

syscall::open:return 
/self->filename/ 
{ 
    @files[copyinstr(self->filename)] = count(); 
    self->filename = 0; 
} 

END 
{ 
    trunc(@files, 5); 
}