24/05/2018, 14:36

Trình bày lỗi (Lỗi xử lý)

Lỗi luôn luôn phát sinh trong chương trình. Một số người trong số họ bắt đầu với chương trình lỗi, hoặc trong mã riêng của chúng tôi hoặc các thành viên trong-chế độ gọi các ứng dụng mà mã của chúng tôi. Một số người trong số họ liên quan đến hệ thống nạp ...

Lỗi luôn luôn phát sinh trong chương trình. Một số người trong số họ bắt đầu với chương trình lỗi, hoặc trong mã riêng của chúng tôi hoặc các thành viên trong-chế độ gọi các ứng dụng mà mã của chúng tôi. Một số người trong số họ liên quan đến hệ thống nạp hoặc làm ngay trong tiểu bang của phần cứng. Bất nguyên nhân, hoàn cảnh không bình thường là một nhu cầu linh hoạt của chúng tôi phản hồi từ mã

Trong phần này, tôi sẽ mô tả ba khía cạnh của xử lý lỗi: tình trạng mã số, ngoại trừ cấu trúc xử lý, và kiểm tra lỗi. Nhìn chung, chế độ hỗ trợ hạt nhân-thói quen báo cáo lỗi không mong muốn bằng cách trả ra một mã trạng thái, trong khi họ báo cáo dự kiến các biến thể bình thường trong dòng chảy bằng cách trả ra một giá trị số Boolean hoặc khác hơn là một trạng thái thức mã

Cấu trúc xử lý ngoại lệ cung cấp một tiêu chuẩn nhất để dọn sạch sau khi thực sự không mong muốn các sự kiện, chẳng hạn như dereferencing một người dùng không hợp lệ-chế độ trỏ, hoặc để tránh đụng xe mà các hệ thống thông thường ensues sau khi những sự kiện. Một lỗi kiểm tra nội bộ là tên gọi cho một thất bại thảm cho đó là một hệ thống tắt là chỉ chữa khỏi.

Kernel_mode hỗ trợ thói quen (và mã của bạn ,cho rằng vấn đề) cho biết thành công hay thất bại bằng cách trả ra một mã trạng thái của họ để gọi. NTSTATUS một giá trị là 32-bit integer gồm một số subfields, như minh họa trong hình 3-2. Cao-bit 2 trật tự biểu các mức độ nghiêm trọng của các điều kiện được báo cáo-thành công, thông tin, cảnh báo, hoặc lỗi. Tôi sẽ giải thích sự tác động của các khách hàng sớm cờ

Các thiết bị mã đó cho biết thành phần hệ thống nguồn gốc tin nhắn và decouple cơ bản để phục vụ phát triển các nhóm từ mỗi khi nói đến số điện thoại để gán mã. Trong phần còn lại trong tình trạng mã 16-bit 'giá trị-cho biết chính xác điều kiện được báo cáo.

Bạn nên luôn luôn kiểm tra tình trạng tra ra từ thủ tục mà họ cung cấp. Tôi đang dừng kết quả nguyên tắc này thường xuyên trong một số các đoạn mã tôi cho bạn bởi vì bao gồm tất cả các lỗi cần thiết xử lý mã thường xuyên che lấp các expository

đích của đoạn này. Nhưng bạn không mô phỏng thực hành động

Nếu bit-cao, trật tự của một mã trạng thái là 0, bất kỳ số bit còn lại có thể được thiết lập và các mã vẫn còn cho biết sẽ thành công. Do đó, không bao giờ cần so sánh với tình trạng mã số 0 để xem liệu bạn đang đối phó với sự thành công-thay vì, sử dụng các macro NT_SUCCESS:

NTSTATUS status = SomeFunction(...);

if (!NT_SUCCESS(status))

  {

  //handle error

 }

Không chỉ làm bạn muốn kiểm tra tình trạng mã số mà bạn nhận được từ thói quen bạn gọi , nhưng bạn cũng muốn trả ra trạng thái mã số thủ tục bạn gọi. Trong chương trước, tôi xử lý với hai trình điều khiển subroutines-DriverEntry và AddDevice-được định nghĩa là cả hai lại NTSTATUS mã

Như tôi đã thảo luận, bạn muốn trả về STATUS_SUCCESS như sự thành công từ những thói quen. Nếu có gì đó sai, bạn thường muốn trả ra một mã trạng thái thích hợp, mà đôi khi là cùng một giá trị trả ra cho bạn. Ví dụ, đây là một số bước đầu tiên trong hàm AddDevice , với tất cả các lỗi kiểm tra ở bên trái:

NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo)

  {

  NTSTATUS status;

  PDEVICE_OBJECT fdo;

  status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),

    NULL, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE,

    &fdo);

  if (!NT_SUCCESS(status))

    {

    KdPrint(("IoCreateDevice failed - %X ", status));

    return status;

    }

  PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

  pdx->DeviceObject = fdo;

  pdx->Pdo = pdo;

  pdx->state = STOPPED;

  IoInitializeRemoveLock(&pdx->RemoveLock, 0, 0, 0);

  status = IoRegisterDeviceInterface(pdo, &GUID_SIMPLE, NULL,

    &pdx->ifname);

  if (!NT_SUCCESS(status))

    {

    KdPrint(("IoRegisterDeviceInterface failed - %X ", status));

    IoDeleteDevice(fdo);

    return status;

    }

  }

  1. IoCreateDevice chúng tôi sẽ trở lại trong cùng một mã trạng thái nó đã cho chúng tôi. Lưu ý việc sử dụng các macro NT_SUCCESS như được mô tả trong văn bản.
  2. Nó đôi khi là một ý tưởng tốt, đặc biệt là một khả năng gỡ lỗi trong trình điều khiển , để in tình trạng lỗi nào bạn khám phá. Tôi sẽ thảo luận về cách sử dụng chính xác của KdPrint sau trong chương này (trong phần "Mẫu Debugging Easier" ).
  3. IoInitializeRemoveLock, thảo luận trong Chương 6, không thể không thành công. Do đó, không cần phải kiểm tra mã trạng thái. Nói chung, hầu hết các hàm tuyên bố với các loại VOID đang có trong cùng một loại "không thể không" . Một số hàm VOID có văn bản bị thất bại do nuôi một ngoại lệ, nhưng các tài liệu DDK rằng hành vi rất rõ ràng.
  4. IoRegisterDeviceInterface nên không thành công, chúng tôi có một số ngẫu nhiên để làm trước khi chúng tôi quay trả lại gọi ; cụ thể,chúng tôi phải gọi IoDeleteDevice để tiêu diệt các thiết bị đối tượng, chúng tôi chỉ cần tạo ra.

Bảng 3-1 cho thấy những thư quan trọng nhất đối với tình trạng mã số.

Sự khác biệt giữa một lỗi và cảnh báo có thể được đáng kể. Ví dụ, không một METHOD_BUFFERED kiểm soát hoạt động (xem Chương 9) với STATUS_BUFFER_OVERFLOW-a-gây ra các cảnh báo I / O Trưởng đại diện để sao chép dữ liệu đối với người sử dụng chế độ-buffer. Việc không cùng một hoạt động với STATUS_BUF ¬ FER_TOO_SMALL-một lỗi-nguyên nhân của I / O Trưởng đại diện cho bất kỳ không được sao chép dữ liệu.

Gia đình của hệ điều hành Windows cung cấp một phương pháp xử lý điều kiện đặc biệt giúp bạn tránh những tiềm năng hệ thống treo. Tích hợp chặt chẽ với các biên của mã Máy phát điện, cấu trúc xử lý ngoại lệ cho phép bạn dễ dàng đặt ra một sự bảo vệ trên các phần của mã của bạn và xử lý gọi ngoại trừ khi có gì đó sai trong phần guarded

Cấu trúc ngoại lệ xử lý cũng cho phép bạn dễ dàng cung cấp các tài liệu kiếm mà bạn có thể chắc chắn sẽ luôn luôn được thực hiện như thế nào không có vấn đề kiểm soát lá guarded một phần của mã. Rất ít các buổi hội thảo của tôi đã được học sinh quen thuộc với cấu trúc ngoại lệ, vì thế tôi sẽ giải thích một số Những vấn đề cơ bản của đây. Mà bạn có thể viết tốt hơn, thêm bulletproof mã nếu bạn sử dụng những tiện nghi. Trong nhiều tình huống, các tham số mà bạn nhận được trong một trình điều khiển WDM đã được quán triệt vetted do các mã và sẽ không cau

Tốt hương vị có thể, do đó, các chỉ được đà để bạn có thể sử dụng các công cụ Tôi mô tả trong phần này. Như là một quy luật chung, tuy nhiên, bạn luôn luôn muốn bảo vệ tài liệu tham khảo trực tiếp với người sử dụng bộ nhớ ảo-chế độ với một cấu trúc khung ngoại lệ. Những tài liệu tham khảo xảy ra khi bạn trực tiếp tham chiếu bộ nhớ và khi bạn gọi MmProbeAndLockPages, ProbeForRead, và ProbeForWrite, và có lẽ ở những thời gian khác

Các SEHTEST mẫu minh hoạ driver cơ khí của các cấu trúc ngoại lệ trong một trình điều khiển WDM. Ngoại lệ nào có thể trở thành trapped

Gary Nebbett nghiên cứu các câu hỏi trong đó có trường hợp ngoại lệ có thể được trapped với các cấu trúc ngoại trừ cơ chế và báo cáo kết quả của mình trong một newsgroup đăng bài nhiều năm trước đây. SEHTEST các mẫu hợp những gì ông được học. Nói tóm lại, các trường hợp ngoại lệ sau đây sẽ được khi họ bị bắt lại xảy ra tại IRQL nhỏ hơn hoặc bằng DISPATCH_LEVEL (lưu ý rằng một số trong số này là cụ thể cho các bộ xử lý Intel x86):

• Bất kỳ ký do ExRaiseStatus và liên quan hàm để lại dự

• dereference không hợp lệ cho người dùng trỏ-chế độ bộ nhớ

• Debug hoặc Breakpoint ngoại lệ

• Integer overflow (hướng dẫn nhập)

• opcode không hợp lệ

Lưu ý rằng một tham chiếu đến một chế độ không hợp lệ hạt nhân-trỏ dẫn trực tiếp đến một lỗi kiểm tra và có thể không được trapped. Tương tự, một chia-do-hay không ngoại trừ một ngoại lệ RÀNG BUỘC hướng dẫn đã dẫn tới một lỗi kiểm tra.

Chương trình hạt nhân-chế độ sử dụng cấu trúc ngoại trừ trường hợp ngoại lệ bằng cách xây dựng khung trên cùng một cây rơm được sử dụng cho các đối số qua, subroutine gọi điện thoại, và tự động các biến. Một dành để xử lý đăng ký điểm hiện tại ngoại trừ khung. Mỗi phòng trong khung điểm đến trước khung.

Bất cứ khi nào một trong các ngoại lệ xảy ra, hạt nhân tìm kiếm trong danh sách các ngoại lệ cho một ngoại trừ khung handler. Nó sẽ luôn luôn tìm thấy một bởi vì có một ngoại lệ khung tại rất trên cùng của stack mà sẽ xử lý bất kỳ khác unhandled ngoại lệ. Một khi hạt nhân nằm một ngoại lệ handler, nó unwinds việc thực hiện và ngoại trừ khung stacks song song, kêu gọi sự xử lý dọc theo đường đi. Sau đó, nó điều khiển cho các ngoại lệ handler.

Khi bạn sử dụng biên của Microsoft, bạn có thể sử dụng Microsoft mở rộng cho C / C + + ngôn ngữ mà ẩn một số trong các phức tạp của nguyên liệu làm việc với các hệ điều hành primitives. Bạn sử dụng __try tuyên bố để chỉ một phức hợp tuyên bố như là guarded cơ thể cho một ngoại trừ khung, và bạn sử dụng hoặc các __finally tuyên bố thành lập một handler hoặc chấm dứt các __except tuyên bố thành lập một ngoại lệ handler.

Đầu tiên các máy tính thi guarded trong cơ thể. Khi kiểm soát các lá guarded cơ thể cho bất cứ lý do gì, máy tính handler thi chấm dứt. Xem Hình 3-3.

Hình 3-3. Kiểm soát dòng chảy của trong một thử-cuối cùng khối.

Đây là một trong rất đơn giản Illustration:

LONG counter = 0;

__try

  {

  ++counter;

  }

__finally

  {

  --counter;

  }

KdPrint(("%d ", counter));

Guarded đầu tiên trong cơ thể và thi increments quầy biến từ 0 đến 1. Khi kiểm soát "bỏ qua" quyền brace ở cuối của guarded cơ thể, chấm dứt handler thi và decrements cập quay lại 0. Giá trị do đó sẽ được in ra 0. Đây là biến thể hơi phức tạp hơn:

VOID RandomFunction(PLONG pcounter)

  {

  __try

    {

    ++*pcounter;

    return;

    }

  __finally

    {

    --*pcounter;

    }

  }

Kết quả của hàm này, không có thay đổi để các nguyên ở cuối của pcounter trỏ: bất cứ khi nào kiểm soát các lá guarded cơ thể cho bất cứ lý do gì, bao gồm một tuyên bố trở lại hoặc một goto, chấm dứt handler thi. Đây là những sự tăng dần thận trọng trong cơ thể truy cập và thực hiện một trở lại.

static LONG counter = 0;

__try

  {

  ++counter;

  BadActor();

  }

__finally

  {

  --counter;

  }

Hãy thử-Ngoại trừ Blocks Các cách khác để sử dụng cấu trúc ngoại lệ bao gồm việc xử lý một thử-ngoại trừ khối:

__try

  {

  <guarded body>

  }

__except(<filter expression>)

  {

  <exception handler>

  }

EXCEPTION_EXECUTE_HANDLER được nhiều bằng 1 và cho các hệ điều hành để chuyển giao kiểm soát của bạn ngoại trừ handler. Nếu handler té ngã của bạn thông qua việc kết thúc quyền brace, tiếp tục kiểm soát của bạn trong chương trình tại các tuyên bố ngay lập tức sau đó phải brace. (Tôi đã thấy Platform SDK tài liệu hướng dẫn cho rằng có hiệu lực trở về để kiểm soát các điểm của các ngoại lệ, nhưng đó là không chính xác

• EXCEPTION_CONTINUE_SEARCH được nhiều bằng 0 và cho các hệ điều hành mà bạn có thể không xử lý các ngoại lệ. Hệ thống giữ hàm quét up the stack đang tìm kiếm các handler khác. Nếu không có người đã cung cấp một handler cho các ngoại lệ, một hệ thống sụp đổ sẽ xảy ra.

• EXCEPTION_CONTINUE_EXECUTION được nhiều bằng -1 và cho các hệ điều hành để trở lại điểm, nơi các ngoại lệ đã được nâng lên. Tôi sẽ có thêm một chút để nói về việc này biểu hiện giá trị thêm vào một ít. Hãy xem ở Hình 3-4 cho các con đường có thể kiểm soát trong và xung quanh là một thử-trừ khối.

Bottom of Form

Bottom of Form

Hình 3-3. Luồng của điều khiển khối try - finally .

Đây là một ví dụ đơn giản:

LONG counter = 0;

__try

  {

  ++counter;

  }

__finally

  {

  --counter;

  }

KdPrint(("%d ", counter));

Trước tiên thực thi phần thân và tăng biến đếm từ 0 lên 1. Khi điều khiển “drops through” ở cuối của phần thân, kết thúc quá trình xử lý và giảm biến đếm tới 0. Bởi vậy giá trị in ra sẽ là 0.

Đây là một ví dụ phức tạp hơn.

VOID RandomFunction(PLONG pcounter)

  {

  __try

    {

    ++*pcounter;

    return;

    }

  __finally

    {

    --*pcounter;

    }

  }

Kết quả của hàm này là không thay đổi giá trị nguyên ở cuói của con trỏ: bất cứ lúc nào điều khiển dời dến phần thân với bất kỳ lý do gi, bao gồm một câu lệnh trả về hoặc một goto, viếc thực thi kết thúc. Đây là phần tăng biến đếm và trả ra giá trị. Ở đoạn code tiếp theo thực thi và giảm biến đếm. sau đó chương trình con sẽ thực hiện lại.

Một ví dụ hoàn chỉnh của khối try-finally:

static LONG counter = 0;

__try

  {

  ++counter;

  BadActor();

  }

__finally

  {

  --counter;

  }

Chúng ta gọi đây là một hàm, BadActor, nó sẽ xuất hiện một vài sự sắp xếp của ngoại lệ kích hoạt một stack hoạt động. Như một phần của tiến trình nghỉ thực hiện và ngoại lệ ngăn xếp, hệ điều hành sẽ gọi mã code của chúng ta để khôi phục lại biến đếm tới giá trị trước nó. hệ thống sẽ tiếp tục giải phóng stack, vì vậy bất cứ câu lệnh nào viết sau khối finally sẽ không được thực hiện.

Một cách khác để sử dụng cấu trúc xử lý ngoại lệ là khối try-Except

__try

  {

  <guarded body>

  }

__except(<filter expression>)

  {

  <exception handler>

  }

Phần thân của khối try-except là mã có sức mạnh phá vỡ những phát sinh ngoại lệ. Có lẽ là bạn đang gọi tới phần chính của hàm như MmProbeAndLockPages sử dụng con trỏ chuyển hoá từ chế độ người dùng không cần kiểm tra giá trị rõ ràng. Có thể bạn có lý do khác. Trong mọi trường hợp nếu bạn quản lý tất cả các cách thông qua phần thân không có lỗi, điều khiển sẽ tiếp tục mã code xử lý ngoại lệ ở phần sau. Bạn sẽ nghĩ trường hợp này trở lên bình thường. Nếu một ngoại lệ xuất hiện trong mã code của bạn hoặc trong bất kỳ tiến trình con nào mà bạn gọi, tuy nhiên, hệ điều hành sẽ giải phóng stack, đánh giá biểu thức trong câu lệnh Except. Những biểu thức này sinh ra một trong những giá trị sau:

  • EXCEPTION_EXECUTE_HANDLER có giá trị bàng 1 và thông báo cho hệ điều hành để chuyển điều khiển tới việc xử lý ngoại lệ của bạn. Nếu việc xử lý của bạn thất bại, đièu khiẻn sẽ tiếp tục chương trình của bạn ở câu lệnh ngay sau đó.( Tôi đã xem tài liệu Platform SDK nói về hiệu ứng mà điều khiển trả ra ngoại lệ tại điểm của ngoại lệ, nhưng đièu đó không đúng)
  • EXCEPTION_CONTINUE_SEARCH có giá trị bằng 0 và thông báo với hệ điều hành rằng bạn không thể xử lý ngoại lệ. Hệ thống sẽ quét qua stack để tìm kiếm xử lý khác. Nếu không ai cung cấp một xử lý nào cho ngoại lệ thì một hệ thống đổ vỡ sẽ xảy ra.
  • EXCEPTION_CONTINUE_EXECUTION có giá trị bằng -1 và thông báo cho hệ điều hành trả ra một diểm nơi mà ngoại lệ được sinh ra. Tôi sẽ có mọt bài để nói về giá trị biểu thức này nhièu hơn nữa.

Nhìn hình 3-4 có thể điều khiển đường dẫn trong và xung quanh một khối try-except.

Hình 3-4. Flow of control in a try-except block.

Cho ví dụ, bạn có thể bảo vệ chính bạn khỏi nhận một con trơ sai bằng sử dụng mã code sau đây.

PVOID p = (PVOID) 1;

__try

  {

  KdPrint(("About to generate exception "));

  ProbeForWrite(p, 4, 4);

  KdPrint(("You shouldn't see this message "));

  }

__except(EXCEPTION_EXECUTE_HANDLER)

  {

  KdPrint(("Exception was caught "));

  }

KdPrint(("Program kept control after exception "));

ProbeForWrite kiểm tra một vùng dữ liệu cho tính hợp lệ. Ở ví dụ này, nó sẽ gây ra một ngoại lệ bởi vì con trỏ mà chúng ta cung cấp chưa được liên kết tới 4 byte. Việc xử lý ngoại lệ tăng tốc đièu khiển. Điều khiển sau đó sẽ thực hiện câu lệnh sau xử lý ngoại lệ và tiếp tục chương trình của bạn.

Trong ví dụ trước, có bạn được trả ra giá trị EXCEPTION_CONTINUE_SEARCH, hệ điều hành tiếp tục giải phóng stack tìm kiếm một xử lý ngoại lệ. Không có mã code xử lý ngoại lệ của bạn cũng không có mã sau nó được thực thi: Mọi hệ thống sẽ bị phá huỷ hoặc sẽ được xử lý ngoại lệ ở mức cao hơn. Bạn không nên trả về EXCEPTION_CONTINUE_EXECUTION trong phần nhân vì bạn không có cách nào dể thay đổi những nguyên nhân gây ra ngoại lệ để cho phép thử lại.

Chú ý rằng bạn không thể bẫy những ngoại lệ số học, hoặc những trang lỗi liên kết một con trỏ kiểu nhân sai, bằng việc sử dụng cấu trúc ngoại lệ. Bạn chỉ cần viết mã để không phát sinh những ngoại lệ như vậy. Đó là làm thế nào để tránh chia cho 0.

Như ví dụ sau đây.

ULONG numerator, denominator;  // <== numbers someone gives you

ULONG quotient;

if (!denominator)

  <handle error>else

  quotient = numerator / denominator;

Nhưng làm thế nào để con trỏ có thể đến tới bạn từ phần khác của nhân? Đó không phải là hàm mà bạn có thể sử dụng để kiểm tra giá trị của một nhân con trỏ. Bạn cần chú ý những quy tắc dưới đây:

Theo cách thông thường, giá trị thực mà một nhân thành phần đưa cho bạn.

Tôi không cho rằng bạn không nên chia nhỏ đoận mã của bạn với câu lệnh ASSERT - bạn nên bởi vì bạn có thể không hiểu tất cả bên trong và bên ngoài cách làm việc của thành phần nhân khác như thế nào. Tôi cho rằng bạn không cần đè nặng trình điều khiẻn của bạn với sự phòng thử quá mức chống lại lỗi ở chỗ khác, được kiểm tra kỹ, một phần của hệ thống trừ khi bạn cần làm việc xung quanh một lỗi.

Vì những hạn chế trên bạn sử dụng hai biểu thức này như thế nào trong chương trình của bạn, bạn sẽ hầu như chắc chắn muốn sử dụng chúng trong một hàm để gọi một vài hàm điều kiện, giống như:

LONG EvaluateException(NTSTATUS status, PEXCEPTION_POINTERS xp)

  {

.

.

.

  }

.

.

.

__except(EvaluateException(GetExceptionCode(),

  GetExceptionInformation()))

Chương trình lỗi là một cách bạn có thể đưa ra ngoại lệ mà gọi cấu trúc xử lý ngoại lệ. Chương trình ứng dụng là quen thuộc với Win32 hàm API đưa ra ngoại lệ, cái mà cho phép bạn tạo ra một cái gì đó ngoại lệ cho chính bạn. Ở trình điều khiển WDM bạn có thể gọi tiến trình lắng nghe trong bảng 3-2. tôi không đưa cho bạn một ví dụ cụ thể để gọi hàm này bởi vì những lý do sau:

Nói cụ thể, đưa ra ngoại lệ không phải là cách tốt để nói cho đối tượng gọi của bạn thông tin mà bạn khám phá ra trong việc xử lý các tiến trình thông thường. Nó tốt hơn nhiều để trả về một trạng thái mã, thậm chí như thể là sự chỉ dẫn từ bên ngoài khó đọc hơn. Bạn nên tránh những ngoại lệ bởi vì máy móc rất dắt tiền. Thậm chí giá của khung ngoại lệ là quan trọng và một vài thứ cần tránh khi bạn có thể.

Bảng 3-2. Dịch vụ hàm cho Raising Exceptions
Service Function Description
ExRaiseStatus Raise exception with specified status code
ExRaiseAccessViolation Raise STATUS_ACCESS_VIOLATION
ExRaiseDatatypeMisalignment Raise STATUS_DATATYPE_MISALIGNMENT

Mặc dù phí tổn của việc cài đặt lên và phá hỏng một ngoại lệ, bạn phải sử dụng quy tắc cấu trúc ngoại lệ trong một trình điều khiển trong trường hợp đặc biệt.

Một trong những lần bạn phải thiết lập một xử lý ngoại lệ là khi bạn gọi MmProbeAndLockPages để tìm kiếm trang cho một bộ nhớ danh sách mieu tả(MDL) bạn tạo ra:

PMDL mdl = MmCreateMdl(...);

__try

  {

  MmProbeAndLockPages(mdl, ...);

  }

__except(EXCEPTION_EXECUTE_HANDLER)

  {

  NTSTATUS status = GetExceptionCode();

  IoFreeMdl(mdl);

  return CompleteRequest(Irp, status, 0);

  }

(CompleteRequest là một hàm giúp đỡ tôi sử dụng để xử lý đòi hỏi hoàn thành I/O. Chương 5 giải thích tất cả về yêu cầu I/O và hoàn thành chúng.)

Lần khác khi sử dụng một xử lý ngoại lệ là khi bạn muốn truy cập bộ nhớ người dùng sử dụng một con trỏ từ nguồn không đáng tin. Trong ví dụ dưới đây, cho rằng bạn thu được con trỏ p từ một chương trình người dùng và chắc chắn nó trỏ tới một số nguyên:

PLONG p;        // from user-mode

__try

  {

  ProbeForRead(p, 4, 4);

  LONG x = *p;

.

.

.

  }

__except(EXCEPTION_EXECUTE_HANDLER)

  {

  NTSTATUS status = GetExceptionCode();

.

.

.

  }

Bug Checks

Những lỗi không thể phục hồi đươc trong kiểu nhân có thể biêur thị chính nó trong cái goi là màn hình xanh của sự chết(BSOD) đó là tất cả quá quen thuộc đối với lập trình viên. Hình 3-5 là một ví dụ .

Bên trong, những lỗi này được gọi là kiẻm tra rối,sau đó dịch vụ hàm bạn sử dụng để chuẩn đoán sự cố của chúng: KeBugCheckEx. Đặc tính chính của sự kiểm tra rối là hệ thống đóng chính nó trong thứ tự một cách như hợp lý và hiện tại BSOD. Một BSOD xuất hiện hệ thống sẽ không hoạt động và phải khởi động lại

Hình 3-5. Mà hình xanh của sự không hoạt động

Bạn có thể gọi KeBugCheckEx như sau:

KeBugCheckEx(bugcode, info1, info2, info3, info4);

bugcode là một giá trị số xác định nguyên nhân lỗi và info1, info2, vân vân là những số mà xuất hiện trên màn hình BSOD để giúp người lập trình hiểu được các lỗi. Hàm này không trả ra giá trị.

Như một người phát triển bạn không có thông tin từ màn hình xanh. Nếu bạn may mắn. thông tin sẽ bao gồm cả hướng dẫn been trong trình điều khiển của bạn. Sau đó bạn có thể xem xét vị trí này trong nhân trình gỡ rối, có lẽ, suy luận có thể thực hiện được vì kiểm tra rối. Chính kiểm tra rối của Microsoft xuất hiện trong bugcodes.h Sụ giải thích về mã của họ có thể tìm thấy trong Những kiến thức cơ bản Q103059. a fuller explanation of the codes and their various parameters can be found in Knowledge Base article Q103059, “Descriptions of Bug Codes for Windows NT,” cái mà có sẵn trong MSDN, giữa những chỗ khác.

Ví dụ điều khiển BUGCHECK cung cấp cách làm thế nào để gọi KeBugCheckEx. Tôi sử dụng nó để phát sinh hình ảnh ở hình 3-5.

Bạn có thể tạo debug-check cho chính bạn nếu bạn muốn. Những giá trị của Microsoft là những giá trị đơn giản bắt dầu từ 1(APC_INDEX_MISMATCH) và (hiện giờ) mở rộng dến 0xF6 (PCI_VERIFIER_DETECTED_VIOLATION), cùng với một số cái khác.

Để tạo ra mã kiểm tra của mình, dịnh nghĩa một hằng số số nguyên như nếu bạn ở trạng thái STATUS_SEVERITY_SUCCESS , nhưng những yêu cầu khác của khách hàng hoặc một mã khác không.

Ví dụ:

#define MY_BUGCHECK_CODE 0x002A0001

KeBugCheckEx(MY_BUGCHECK_CODE, 0, 0, 0, 0);

Bạn sử dụng một mã trạng thái khác 0 (42 trong ví dụ) hoặc cờ của khách hàng(cái mà tôi viết 0 trong ví dụ này) vì vậy mà bạn có thể thông báo chính mã của bạn từ một người sử dụng Microsoft.

Bây giơ tôi nói cho bạn cách làm thế nào tạo BSOD cho chính bạn, cho phép tôi nói khi nào bạn làm nó: không bao giờ. Hoặc trong khi xây dựng kiểm tra của trình điều khiển đẻ sử dụng trong suốt bên trong quá trình gỡ rối. Bạn và tôi đều không chắc chắn để viết một trình diều khiển mà sẽ phát hiện một lỗi nghiêm túc đến nỗi lấy xuống hệ thống là cách giải quyết duy nhất. Nó sẽ tốt hơn nhiều gỡ lỗi( sử dụng gỡ lỗi tôi sẽ mô tả trong chương 14 ) và trả ra một mã tình trạng.

Chú ý rằng người dùng cuối có thể cấu hình hành động của KeBugCheckEx trong những sự thiết lập cho máy tính của tôi. Người sử dụng có thể chọn khởi động một cách tự động hoặc phát sinh BSOD. Người dùng cuối có thể như vậy chọn vài mức của chi tiết( kể cả không) cho một file.

0