xref: /reactos/sdk/lib/rtl/dbgbuffer.c (revision 84ccccab)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            lib/rtl/dbgbuffer.c
5  * PROGRAMER:       James Tabor
6  */
7 
8 /* INCLUDES *****************************************************************/
9 
10 #include <rtl.h>
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* FUNCTIONS *****************************************************************/
16 
17 /*
18  * @unimplemented
19  */
20 PRTL_DEBUG_INFORMATION
21 NTAPI
22 RtlCreateQueryDebugBuffer(IN ULONG Size,
23                           IN BOOLEAN EventPair)
24 {
25     NTSTATUS Status;
26     PRTL_DEBUG_INFORMATION Buf = NULL;
27     SIZE_T ViewSize = 100 * PAGE_SIZE;
28 
29     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
30                                      (PVOID*)&Buf,
31                                      0,
32                                      &ViewSize,
33                                      MEM_RESERVE | MEM_COMMIT,
34                                      PAGE_READWRITE);
35     if (!NT_SUCCESS(Status)) return NULL;
36 
37     Buf->ViewBaseClient = Buf;
38     Buf->ViewSize = (ULONG)ViewSize;
39 
40     DPRINT("RtlCQDB: BA: %p BS: 0x%lx\n", Buf->ViewBaseClient, Buf->ViewSize);
41 
42     return Buf;
43 }
44 
45 /*
46  * @unimplemented
47  */
48 NTSTATUS
49 NTAPI
50 RtlDestroyQueryDebugBuffer(IN PRTL_DEBUG_INFORMATION Buf)
51 {
52     NTSTATUS Status = STATUS_SUCCESS;
53     SIZE_T ViewSize = 0;
54 
55     if (NULL != Buf)
56     {
57         Status = NtFreeVirtualMemory(NtCurrentProcess(),
58                                      (PVOID*)&Buf,
59                                      &ViewSize,
60                                      MEM_RELEASE);
61     }
62     if (!NT_SUCCESS(Status))
63     {
64         DPRINT1("RtlDQDB: Failed to free VM!\n");
65     }
66     return Status;
67 }
68 
69 /*
70  *  Based on lib/epsapi/enum/modules.c by KJK::Hyperion.
71  */
72 NTSTATUS
73 NTAPI
74 RtlpQueryRemoteProcessModules(HANDLE ProcessHandle,
75                               IN PRTL_PROCESS_MODULES Modules OPTIONAL,
76                               IN ULONG Size OPTIONAL,
77                               OUT PULONG ReturnedSize)
78 {
79     PROCESS_BASIC_INFORMATION pbiInfo;
80     PPEB_LDR_DATA ppldLdrData;
81     LDR_DATA_TABLE_ENTRY lmModule;
82     PLIST_ENTRY pleListHead;
83     PLIST_ENTRY pleCurEntry;
84 
85     PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL;
86     NTSTATUS Status = STATUS_SUCCESS;
87     ULONG UsedSize = sizeof(ULONG);
88     ANSI_STRING AnsiString;
89     PCHAR p;
90 
91     DPRINT("RtlpQueryRemoteProcessModules Start\n");
92 
93     /* query the process basic information (includes the PEB address) */
94     Status = NtQueryInformationProcess(ProcessHandle,
95                                        ProcessBasicInformation,
96                                        &pbiInfo,
97                                        sizeof(PROCESS_BASIC_INFORMATION),
98                                        NULL);
99 
100     if (!NT_SUCCESS(Status))
101     {
102         /* failure */
103         DPRINT("NtQueryInformationProcess 1 0x%lx \n", Status);
104         return Status;
105     }
106 
107     if (Modules == NULL || Size == 0)
108     {
109         Status = STATUS_INFO_LENGTH_MISMATCH;
110     }
111     else
112     {
113         Modules->NumberOfModules = 0;
114         ModulePtr = &Modules->Modules[0];
115         Status = STATUS_SUCCESS;
116     }
117 
118     /* get the address of the PE Loader data */
119     Status = NtReadVirtualMemory(ProcessHandle,
120                                  &(pbiInfo.PebBaseAddress->Ldr),
121                                  &ppldLdrData,
122                                  sizeof(ppldLdrData),
123                                  NULL);
124 
125     if (!NT_SUCCESS(Status))
126     {
127         /* failure */
128         DPRINT("NtReadVirtualMemory 1 0x%lx \n", Status);
129         return Status;
130     }
131 
132 
133     /* head of the module list: the last element in the list will point to this */
134     pleListHead = &ppldLdrData->InLoadOrderModuleList;
135 
136     /* get the address of the first element in the list */
137     Status = NtReadVirtualMemory(ProcessHandle,
138                                  &(ppldLdrData->InLoadOrderModuleList.Flink),
139                                  &pleCurEntry,
140                                  sizeof(pleCurEntry),
141                                  NULL);
142 
143     if (!NT_SUCCESS(Status))
144     {
145         /* failure */
146         DPRINT("NtReadVirtualMemory 2 0x%lx \n", Status);
147         return Status;
148     }
149 
150     while(pleCurEntry != pleListHead)
151     {
152         UNICODE_STRING Unicode;
153         WCHAR  Buffer[256 * sizeof(WCHAR)];
154 
155         /* read the current module */
156         Status = NtReadVirtualMemory(ProcessHandle,
157                                      CONTAINING_RECORD(pleCurEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks),
158                                      &lmModule,
159                                      sizeof(LDR_DATA_TABLE_ENTRY),
160                                      NULL);
161 
162         if (!NT_SUCCESS(Status))
163         {
164             /* failure */
165             DPRINT( "NtReadVirtualMemory 3 0x%lx \n", Status);
166             return Status;
167         }
168 
169         /* Import module name from remote Process user space. */
170         Unicode.Length = lmModule.FullDllName.Length;
171         Unicode.MaximumLength = lmModule.FullDllName.MaximumLength;
172         Unicode.Buffer = Buffer;
173 
174         Status = NtReadVirtualMemory(ProcessHandle,
175                                      lmModule.FullDllName.Buffer,
176                                      Unicode.Buffer,
177                                      Unicode.Length,
178                                      NULL);
179 
180         if (!NT_SUCCESS(Status))
181         {
182             /* failure */
183             DPRINT( "NtReadVirtualMemory 3 0x%lx \n", Status);
184             return Status;
185         }
186 
187         DPRINT("  Module %wZ\n", &Unicode);
188 
189         if (UsedSize > Size)
190         {
191             Status = STATUS_INFO_LENGTH_MISMATCH;
192         }
193         else if (Modules != NULL)
194         {
195             ModulePtr->Section        = 0;
196             ModulePtr->MappedBase     = NULL;      // FIXME: ??
197             ModulePtr->ImageBase      = lmModule.DllBase;
198             ModulePtr->ImageSize      = lmModule.SizeOfImage;
199             ModulePtr->Flags          = lmModule.Flags;
200             ModulePtr->LoadOrderIndex = 0;      // FIXME:  ??
201             ModulePtr->InitOrderIndex = 0;      // FIXME: ??
202             ModulePtr->LoadCount      = lmModule.LoadCount;
203 
204             AnsiString.Length        = 0;
205             AnsiString.MaximumLength = 256;
206             AnsiString.Buffer        = ModulePtr->FullPathName;
207             RtlUnicodeStringToAnsiString(&AnsiString,
208                                          &Unicode,
209                                          FALSE);
210 
211             p = strrchr(ModulePtr->FullPathName, '\\');
212             if (p != NULL)
213                 ModulePtr->OffsetToFileName = (USHORT)(p - ModulePtr->FullPathName + 1);
214             else
215                 ModulePtr->OffsetToFileName = 0;
216 
217             ModulePtr++;
218             Modules->NumberOfModules++;
219         }
220         UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION);
221 
222         /* address of the next module in the list */
223         pleCurEntry = lmModule.InLoadOrderLinks.Flink;
224     }
225 
226     if (ReturnedSize != 0)
227         *ReturnedSize = UsedSize;
228 
229     DPRINT("RtlpQueryRemoteProcessModules End\n");
230 
231     /* success */
232     return (STATUS_SUCCESS);
233 }
234 
235 /*
236  * @unimplemented
237  */
238 NTSTATUS
239 NTAPI
240 RtlQueryProcessDebugInformation(IN ULONG ProcessId,
241                                 IN ULONG DebugInfoMask,
242                                 IN OUT PRTL_DEBUG_INFORMATION Buf)
243 {
244     NTSTATUS Status = STATUS_SUCCESS;
245     ULONG Pid = (ULONG)(ULONG_PTR) NtCurrentTeb()->ClientId.UniqueProcess;
246 
247     Buf->Flags = DebugInfoMask;
248     Buf->OffsetFree = sizeof(RTL_DEBUG_INFORMATION);
249 
250     DPRINT("QueryProcessDebugInformation Start\n");
251 
252     /*
253     Currently ROS can not read-only from kenrel space, and doesn't
254     check for boundaries inside kernel space that are page protected
255     from every one but the kernel. aka page 0 - 2
256     */
257     if (ProcessId <= 1)
258     {
259         Status = STATUS_ACCESS_VIOLATION;
260     }
261     else
262         if (Pid == ProcessId)
263         {
264             if (DebugInfoMask & RTL_DEBUG_QUERY_MODULES)
265             {
266                 PRTL_PROCESS_MODULES Mp;
267                 ULONG ReturnSize = 0;
268                 ULONG MSize;
269 
270                 Mp = (PRTL_PROCESS_MODULES)((PUCHAR)Buf + Buf->OffsetFree);
271 
272                 /* I like this better than the do & while loop. */
273                 Status = LdrQueryProcessModuleInformation(NULL,
274                                                           0,
275                                                           &ReturnSize);
276                 Status = LdrQueryProcessModuleInformation(Mp,
277                                                           ReturnSize ,
278                                                           &ReturnSize);
279                 if (!NT_SUCCESS(Status))
280                 {
281                     return Status;
282                 }
283 
284                 MSize = Mp->NumberOfModules * (sizeof(RTL_PROCESS_MODULES) + 8);
285                 Buf->Modules = Mp;
286                 Buf->OffsetFree = Buf->OffsetFree + MSize;
287             }
288 
289             if (DebugInfoMask & RTL_DEBUG_QUERY_HEAPS)
290             {
291                 PRTL_PROCESS_HEAPS Hp;
292                 ULONG HSize;
293 
294                 Hp = (PRTL_PROCESS_HEAPS)((PUCHAR)Buf + Buf->OffsetFree);
295                 HSize = sizeof(RTL_PROCESS_HEAPS);
296                 if (DebugInfoMask & RTL_DEBUG_QUERY_HEAP_TAGS)
297                 {
298                     // TODO
299                 }
300                 if (DebugInfoMask & RTL_DEBUG_QUERY_HEAP_BLOCKS)
301                 {
302                     // TODO
303                 }
304                 Buf->Heaps = Hp;
305                 Buf->OffsetFree = Buf->OffsetFree + HSize;
306 
307             }
308 
309             if (DebugInfoMask & RTL_DEBUG_QUERY_LOCKS)
310             {
311                 PRTL_PROCESS_LOCKS Lp;
312                 ULONG LSize;
313 
314                 Lp = (PRTL_PROCESS_LOCKS)((PUCHAR)Buf + Buf->OffsetFree);
315                 LSize = sizeof(RTL_PROCESS_LOCKS);
316                 Buf->Locks = Lp;
317                 Buf->OffsetFree = Buf->OffsetFree + LSize;
318             }
319 
320             DPRINT("QueryProcessDebugInformation end \n");
321             DPRINT("QueryDebugInfo : 0x%lx\n", Buf->OffsetFree);
322         }
323         else
324         {
325             HANDLE hProcess;
326             CLIENT_ID ClientId;
327             OBJECT_ATTRIBUTES ObjectAttributes;
328 
329             Buf->TargetProcessHandle = NtCurrentProcess();
330 
331             ClientId.UniqueThread = 0;
332             ClientId.UniqueProcess = (HANDLE)(ULONG_PTR)ProcessId;
333             InitializeObjectAttributes(&ObjectAttributes,
334                                        NULL,
335                                        0,
336                                        NULL,
337                                        NULL);
338 
339             Status = NtOpenProcess(&hProcess,
340                                    (PROCESS_ALL_ACCESS),
341                                    &ObjectAttributes,
342                                    &ClientId );
343             if (!NT_SUCCESS(Status))
344             {
345                 return Status;
346             }
347 
348             if (DebugInfoMask & RTL_DEBUG_QUERY_MODULES)
349             {
350                 PRTL_PROCESS_MODULES Mp;
351                 ULONG ReturnSize = 0;
352                 ULONG MSize;
353 
354                 Mp = (PRTL_PROCESS_MODULES)((PUCHAR)Buf + Buf->OffsetFree);
355 
356                 Status = RtlpQueryRemoteProcessModules(hProcess,
357                                                        NULL,
358                                                        0,
359                                                        &ReturnSize);
360 
361                 Status = RtlpQueryRemoteProcessModules(hProcess,
362                                                        Mp,
363                                                        ReturnSize ,
364                                                        &ReturnSize);
365                 if (!NT_SUCCESS(Status))
366                 {
367                     return Status;
368                 }
369 
370                 MSize = Mp->NumberOfModules * (sizeof(RTL_PROCESS_MODULES) + 8);
371                 Buf->Modules = Mp;
372                 Buf->OffsetFree = Buf->OffsetFree + MSize;
373             }
374 
375             if (DebugInfoMask & RTL_DEBUG_QUERY_HEAPS)
376             {
377                 PRTL_PROCESS_HEAPS Hp;
378                 ULONG HSize;
379 
380                 Hp = (PRTL_PROCESS_HEAPS)((PUCHAR)Buf + Buf->OffsetFree);
381                 HSize = sizeof(RTL_PROCESS_HEAPS);
382                 if (DebugInfoMask & RTL_DEBUG_QUERY_HEAP_TAGS)
383                 {
384                     // TODO
385                 }
386                 if (DebugInfoMask & RTL_DEBUG_QUERY_HEAP_BLOCKS)
387                 {
388                     // TODO
389                 }
390                 Buf->Heaps = Hp;
391                 Buf->OffsetFree = Buf->OffsetFree + HSize;
392 
393             }
394 
395             if (DebugInfoMask & RTL_DEBUG_QUERY_LOCKS)
396             {
397                 PRTL_PROCESS_LOCKS Lp;
398                 ULONG LSize;
399 
400                 Lp = (PRTL_PROCESS_LOCKS)((PUCHAR)Buf + Buf->OffsetFree);
401                 LSize = sizeof(RTL_PROCESS_LOCKS);
402                 Buf->Locks = Lp;
403                 Buf->OffsetFree = Buf->OffsetFree + LSize;
404             }
405 
406             DPRINT("QueryProcessDebugInformation end \n");
407             DPRINT("QueryDebugInfo : 0x%lx\n", Buf->OffsetFree);
408         }
409 
410     return Status;
411 }
412 
413 /* EOL */
414