1 // SoftEther VPN Source Code - Stable Edition Repository
2 // Mayaqua Kernel
3 //
4 // SoftEther VPN Server, Client and Bridge are free software under the Apache License, Version 2.0.
5 //
6 // Copyright (c) Daiyuu Nobori.
7 // Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan.
8 // Copyright (c) SoftEther Corporation.
9 // Copyright (c) all contributors on SoftEther VPN project in GitHub.
10 //
11 // All Rights Reserved.
12 //
13 // http://www.softether.org/
14 //
15 // This stable branch is officially managed by Daiyuu Nobori, the owner of SoftEther VPN Project.
16 // Pull requests should be sent to the Developer Edition Master Repository on https://github.com/SoftEtherVPN/SoftEtherVPN
17 //
18 // License: The Apache License, Version 2.0
19 // https://www.apache.org/licenses/LICENSE-2.0
20 //
21 // DISCLAIMER
22 // ==========
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 // SOFTWARE.
31 //
32 // THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN, UNDER
33 // JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY, MERGE, PUBLISH,
34 // DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS SOFTWARE, THAT ANY
35 // JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS SOFTWARE OR ITS CONTENTS,
36 // AGAINST US (SOFTETHER PROJECT, SOFTETHER CORPORATION, DAIYUU NOBORI OR OTHER
37 // SUPPLIERS), OR ANY JURIDICAL DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND
38 // OF USING, COPYING, MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING,
39 // AND/OR SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
40 // CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO EXCLUSIVE
41 // JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO, JAPAN. YOU MUST WAIVE
42 // ALL DEFENSES OF LACK OF PERSONAL JURISDICTION AND FORUM NON CONVENIENS.
43 // PROCESS MAY BE SERVED ON EITHER PARTY IN THE MANNER AUTHORIZED BY APPLICABLE
44 // LAW OR COURT RULE.
45 //
46 // USE ONLY IN JAPAN. DO NOT USE THIS SOFTWARE IN ANOTHER COUNTRY UNLESS YOU HAVE
47 // A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY CRIMINAL LAWS OR CIVIL
48 // RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS SOFTWARE IN OTHER COUNTRIES IS
49 // COMPLETELY AT YOUR OWN RISK. THE SOFTETHER VPN PROJECT HAS DEVELOPED AND
50 // DISTRIBUTED THIS SOFTWARE TO COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING
51 // CIVIL RIGHTS INCLUDING PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER
52 // COUNTRIES' LAWS OR CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES.
53 // WE HAVE NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR
54 // INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+ COUNTRIES
55 // AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE WORLD, WITH
56 // DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY COUNTRIES' LAWS, REGULATIONS
57 // AND CIVIL RIGHTS TO MAKE THE SOFTWARE COMPLY WITH ALL COUNTRIES' LAWS BY THE
58 // PROJECT. EVEN IF YOU WILL BE SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A
59 // PUBLIC SERVANT IN YOUR COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE
60 // LIABLE TO RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL
61 // RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT JUST A
62 // STATEMENT FOR WARNING AND DISCLAIMER.
63 //
64 // READ AND UNDERSTAND THE 'WARNING.TXT' FILE BEFORE USING THIS SOFTWARE.
65 // SOME SOFTWARE PROGRAMS FROM THIRD PARTIES ARE INCLUDED ON THIS SOFTWARE WITH
66 // LICENSE CONDITIONS WHICH ARE DESCRIBED ON THE 'THIRD_PARTY.TXT' FILE.
67 //
68 //
69 // SOURCE CODE CONTRIBUTION
70 // ------------------------
71 //
72 // Your contribution to SoftEther VPN Project is much appreciated.
73 // Please send patches to us through GitHub.
74 // Read the SoftEther VPN Patch Acceptance Policy in advance:
75 // http://www.softether.org/5-download/src/9.patch
76 //
77 //
78 // DEAR SECURITY EXPERTS
79 // ---------------------
80 //
81 // If you find a bug or a security vulnerability please kindly inform us
82 // about the problem immediately so that we can fix the security problem
83 // to protect a lot of users around the world as soon as possible.
84 //
85 // Our e-mail address for security reports is:
86 // softether-vpn-security [at] softether.org
87 //
88 // Please note that the above e-mail address is not a technical support
89 // inquiry address. If you need technical assistance, please visit
90 // http://www.softether.org/ and ask your question on the users forum.
91 //
92 // Thank you for your cooperation.
93 //
94 //
95 // NO MEMORY OR RESOURCE LEAKS
96 // ---------------------------
97 //
98 // The memory-leaks and resource-leaks verification under the stress
99 // test has been passed before release this source code.
100
101
102 // Tracking.c
103 // Object tracking module
104
105 #include <GlobalConst.h>
106
107 #include <stdio.h>
108 #include <stdlib.h>
109 #include <string.h>
110 #include <wchar.h>
111 #include <stdarg.h>
112 #include <time.h>
113 #include <errno.h>
114 #include <Mayaqua/Mayaqua.h>
115
116 // Global variables
117 static LOCK *obj_lock;
118 static LOCK *obj_id_lock;
119 static UINT obj_id;
120 static LOCK *cs_lock;
121 static bool disable_tracking = false;
122 static TRACKING_LIST **hashlist;
123
124 static bool do_not_get_callstack;
125
126 // Enable the tracking
TrackingEnable()127 void TrackingEnable()
128 {
129 disable_tracking = false;
130 }
131
132 // Disable the tracking
TrackingDisable()133 void TrackingDisable()
134 {
135 disable_tracking = true;
136 }
137
138 // Get whether the tracking is enabled
IsTrackingEnabled()139 bool IsTrackingEnabled()
140 {
141 return !disable_tracking;
142 }
143
144 // Memory debug menu
MemoryDebugMenu()145 void MemoryDebugMenu()
146 {
147 char tmp[MAX_SIZE];
148 TOKEN_LIST *t;
149 char *cmd;
150 Print("Mayaqua Kernel Memory Debug Tools\n"
151 "Copyright (c) SoftEther Corporation. All Rights Reserved.\n\n");
152 g_memcheck = false;
153 while (true)
154 {
155 Print("debug>");
156 GetLine(tmp, sizeof(tmp));
157 t = ParseToken(tmp, " \t");
158 if (t->NumTokens == 0)
159 {
160 FreeToken(t);
161 DebugPrintAllObjects();
162 continue;
163 }
164 cmd = t->Token[0];
165 if (!StrCmpi(cmd, "?"))
166 {
167 DebugPrintCommandList();
168 }
169 else if (!StrCmpi(cmd, "a"))
170 {
171 DebugPrintAllObjects();
172 }
173 else if (!StrCmpi(cmd, "i"))
174 {
175 if (t->NumTokens == 1)
176 {
177 Print("Usage: i <obj_id>\n\n");
178 }
179 else
180 {
181 DebugPrintObjectInfo(ToInt(t->Token[1]));
182 }
183 }
184 else if (!StrCmpi(cmd, "q"))
185 {
186 break;
187 }
188 else if (ToInt(cmd) != 0)
189 {
190 DebugPrintObjectInfo(ToInt(t->Token[0]));
191 }
192 else
193 {
194 Print("Command Not Found,\n\n");
195 }
196 FreeToken(t);
197 }
198 FreeToken(t);
199 g_memcheck = true;
200 }
201
202 // Sort the objects by chronological order
SortObjectView(void * p1,void * p2)203 int SortObjectView(void *p1, void *p2)
204 {
205 TRACKING_OBJECT *o1, *o2;
206 if (p1 == NULL || p2 == NULL)
207 {
208 return 0;
209 }
210 o1 = *(TRACKING_OBJECT **)p1;
211 o2 = *(TRACKING_OBJECT **)p2;
212 if (o1 == NULL || o2 == NULL)
213 {
214 return 0;
215 }
216
217 if (o1->Id > o2->Id)
218 {
219 return 1;
220 }
221 else if (o1->Id == o2->Id)
222 {
223 return 0;
224 }
225 return -1;
226 }
227
228 // Display the information of the object
PrintObjectInfo(TRACKING_OBJECT * o)229 void PrintObjectInfo(TRACKING_OBJECT *o)
230 {
231 SYSTEMTIME t;
232 char tmp[MAX_SIZE];
233 // Validate arguments
234 if (o == NULL)
235 {
236 return;
237 }
238
239 UINT64ToSystem(&t, o->CreatedDate);
240 GetDateTimeStrMilli(tmp, sizeof(tmp), &t);
241
242 Print(" TRACKING_OBJECT ID: %u\n"
243 " TRACKING_OBJECT TYPE: %s\n"
244 " ADDRESS: 0x%p\n"
245 " TRACKING_OBJECT SIZE: %u bytes\n"
246 " CREATED DATE: %s\n",
247 o->Id, o->Name, UINT64_TO_POINTER(o->Address), o->Size, tmp);
248
249 PrintCallStack(o->CallStack);
250 }
251
252 // Display the object information
DebugPrintObjectInfo(UINT id)253 void DebugPrintObjectInfo(UINT id)
254 {
255 UINT i;
256 TRACKING_OBJECT *o;
257
258 // Search
259 o = NULL;
260 LockTrackingList();
261 {
262 for (i = 0;i < TRACKING_NUM_ARRAY;i++)
263 {
264 if (hashlist[i] != NULL)
265 {
266 TRACKING_LIST *t = hashlist[i];
267
268 while (true)
269 {
270 if (t->Object->Id == id)
271 {
272 o = t->Object;
273 break;
274 }
275
276 if (t->Next == NULL)
277 {
278 break;
279 }
280
281 t = t->Next;
282 }
283
284 if (o != NULL)
285 {
286 break;
287 }
288 }
289 }
290 }
291 UnlockTrackingList();
292
293 if (o == NULL)
294 {
295 // The ID could not be found
296 Print("obj_id %u Not Found.\n\n", id);
297 return;
298 }
299
300 PrintObjectInfo(o);
301 Print("\n");
302 }
303
304 // Show a Summary of the object
PrintObjectList(TRACKING_OBJECT * o)305 void PrintObjectList(TRACKING_OBJECT *o)
306 {
307 char tmp[MAX_SIZE];
308 SYSTEMTIME t;
309 UINT64ToSystem(&t, o->CreatedDate);
310 GetTimeStrMilli(tmp, sizeof(tmp), &t);
311 TrackGetObjSymbolInfo(o);
312 Print("%-4u - [%-6s] %s 0x%p size=%-5u %11s %u\n",
313 o->Id, o->Name, tmp, UINT64_TO_POINTER(o->Address), o->Size, o->FileName, o->LineNumber);
314 }
315
316 // Display all the objects
DebugPrintAllObjects()317 void DebugPrintAllObjects()
318 {
319 UINT i;
320 LIST *view;
321
322 // Creating a List
323 view = NewListFast(SortObjectView);
324 LockTrackingList();
325 {
326 for (i = 0;i < TRACKING_NUM_ARRAY;i++)
327 {
328 if (hashlist[i] != NULL)
329 {
330 TRACKING_LIST *t = hashlist[i];
331
332 while (true)
333 {
334 Add(view, t->Object);
335
336 if (t->Next == NULL)
337 {
338 break;
339 }
340
341 t = t->Next;
342 }
343 }
344 }
345 }
346 UnlockTrackingList();
347
348 // Sort
349 Sort(view);
350
351 // Drawing
352 for (i = 0;i < LIST_NUM(view);i++)
353 {
354 TRACKING_OBJECT *o = (TRACKING_OBJECT *)LIST_DATA(view, i);
355 PrintObjectList(o);
356 }
357
358 // Release the list
359 ReleaseList(view);
360
361 Print("\n");
362 }
363
364 // List of the commands
DebugPrintCommandList()365 void DebugPrintCommandList()
366 {
367 Print(
368 "a - All Objects\n"
369 "i - Object Information\n"
370 "? - Help\n"
371 "q - Quit\n\n"
372 );
373 }
374
375 // Display the usage of the memory
PrintMemoryStatus()376 void PrintMemoryStatus()
377 {
378 MEMORY_STATUS s;
379 GetMemoryStatus(&s);
380 Print("MEMORY STATUS:\n"
381 " NUM_OF_MEMORY_BLOCKS: %u\n"
382 " SIZE_OF_TOTAL_MEMORY: %u bytes\n",
383 s.MemoryBlocksNum, s.MemorySize);
384 }
385
386 // Get the using state of the memory
GetMemoryStatus(MEMORY_STATUS * status)387 void GetMemoryStatus(MEMORY_STATUS *status)
388 {
389 UINT i, num, size;
390 // Validate arguments
391 if (status == NULL)
392 {
393 return;
394 }
395
396 LockTrackingList();
397 {
398 size = num = 0;
399
400 for (i = 0;i < TRACKING_NUM_ARRAY;i++)
401 {
402 if (hashlist[i] != NULL)
403 {
404 TRACKING_LIST *t = hashlist[i];
405
406 while (true)
407 {
408 TRACKING_OBJECT *o = t->Object;
409
410 if (StrCmpi(o->Name, "MEM") == 0)
411 {
412 num++;
413 size += o->Size;
414 }
415
416 if (t->Next == NULL)
417 {
418 break;
419 }
420
421 t = t->Next;
422 }
423 }
424 }
425 }
426 UnlockTrackingList();
427
428 status->MemoryBlocksNum = num;
429 status->MemorySize = size;
430 }
431
432 // Get the symbol information by the object
TrackGetObjSymbolInfo(TRACKING_OBJECT * o)433 void TrackGetObjSymbolInfo(TRACKING_OBJECT *o)
434 {
435 // Validate arguments
436 if (o == NULL)
437 {
438 return;
439 }
440
441 if (!(o->LineNumber == 0 && o->FileName[0] == 0))
442 {
443 return;
444 }
445
446 if (o->CallStack != NULL)
447 {
448 GetCallStackSymbolInfo(o->CallStack);
449 if (StrLen(o->CallStack->filename) != 0 && o->CallStack->line != 0)
450 {
451 StrCpy(o->FileName, sizeof(o->FileName), o->CallStack->filename);
452 o->LineNumber = o->CallStack->line;
453 }
454 }
455 }
456
457 // Put a new object into the tracking list
TrackNewObj(UINT64 addr,char * name,UINT size)458 void TrackNewObj(UINT64 addr, char *name, UINT size)
459 {
460 TRACKING_OBJECT *o;
461 UINT new_id;
462 // Validate arguments
463 if (addr == 0 || name == NULL)
464 {
465 return;
466 }
467
468 if (IsMemCheck() == false)
469 {
470 // Don't track in the release mode
471 return;
472 }
473
474 if (disable_tracking)
475 {
476 return;
477 }
478
479 // Generate a new ID
480 OSLock(obj_id_lock);
481 {
482 new_id = ++obj_id;
483 }
484 OSUnlock(obj_id_lock);
485
486 o = OSMemoryAlloc(sizeof(TRACKING_OBJECT));
487 o->Id = new_id;
488 o->Address = addr;
489 o->Name = name;
490 o->Size = size;
491 o->CreatedDate = LocalTime64();
492 o->CallStack = WalkDownCallStack(GetCallStack(), 2);
493
494 o->FileName[0] = 0;
495 o->LineNumber = 0;
496
497 LockTrackingList();
498 {
499 InsertTrackingList(o);
500 }
501 UnlockTrackingList();
502 }
503
504 // Remove the object from the tracking list
TrackDeleteObj(UINT64 addr)505 void TrackDeleteObj(UINT64 addr)
506 {
507 TRACKING_OBJECT *o;
508 // Validate arguments
509 if (addr == 0)
510 {
511 return;
512 }
513
514 if (IsMemCheck() == false)
515 {
516 // Don't track in the release mode
517 return;
518 }
519
520 if (disable_tracking)
521 {
522 return;
523 }
524
525 LockTrackingList();
526 {
527 o = SearchTrackingList(addr);
528 if (o == NULL)
529 {
530 UnlockTrackingList();
531
532 if (IsDebug())
533 {
534 printf("TrackDeleteObj: 0x%x is not Object!!\n", (void *)addr);
535 }
536 return;
537 }
538 DeleteTrackingList(o, true);
539 }
540 UnlockTrackingList();
541 }
542
543 // Change the size of the object being tracked
TrackChangeObjSize(UINT64 addr,UINT size,UINT64 new_addr)544 void TrackChangeObjSize(UINT64 addr, UINT size, UINT64 new_addr)
545 {
546 TRACKING_OBJECT *o;
547 // Validate arguments
548 if (addr == 0)
549 {
550 return;
551 }
552
553 if (IsMemCheck() == false)
554 {
555 // Don't track in the release mode
556 return;
557 }
558
559 if (disable_tracking)
560 {
561 return;
562 }
563
564 LockTrackingList();
565 {
566 o = SearchTrackingList(addr);
567 if (o == NULL)
568 {
569 UnlockTrackingList();
570 return;
571 }
572
573 DeleteTrackingList(o, false);
574
575 o->Size = size;
576 o->Address = new_addr;
577
578 InsertTrackingList(o);
579 }
580 UnlockTrackingList();
581 }
582
583 // Memory address comparison function
CompareTrackingObject(const void * p1,const void * p2)584 int CompareTrackingObject(const void *p1, const void *p2)
585 {
586 TRACKING_OBJECT *o1, *o2;
587 // Validate arguments
588 if (p1 == NULL || p2 == NULL)
589 {
590 return 0;
591 }
592 o1 = *(TRACKING_OBJECT **)p1;
593 o2 = *(TRACKING_OBJECT **)p2;
594 if (o1 == NULL || o2 == NULL)
595 {
596 return 0;
597 }
598
599 if (o1->Address > o2->Address)
600 {
601 return 1;
602 }
603 if (o1->Address == o2->Address)
604 {
605 return 0;
606 }
607 return -1;
608 }
609
610 // Search an object in the tracking list
SearchTrackingList(UINT64 Address)611 TRACKING_OBJECT *SearchTrackingList(UINT64 Address)
612 {
613 UINT i;
614 // Validate arguments
615 if (Address == 0)
616 {
617 return NULL;
618 }
619
620 i = TRACKING_HASH(Address);
621
622 if (hashlist[i] != NULL)
623 {
624 TRACKING_LIST *tt = hashlist[i];
625
626 while (true)
627 {
628 if (tt->Object->Address == Address)
629 {
630 return tt->Object;
631 }
632
633 tt = tt->Next;
634
635 if (tt == NULL)
636 {
637 break;
638 }
639 }
640 }
641
642 return NULL;
643 }
644
645 // Remove an object from a tracking list
DeleteTrackingList(TRACKING_OBJECT * o,bool free_object_memory)646 void DeleteTrackingList(TRACKING_OBJECT *o, bool free_object_memory)
647 {
648 UINT i;
649 // Validate arguments
650 if (o == NULL)
651 {
652 return;
653 }
654
655 i = TRACKING_HASH(o->Address);
656
657 if (hashlist[i] != NULL)
658 {
659 TRACKING_LIST *ft = NULL;
660
661 if (hashlist[i]->Object == o)
662 {
663 ft = hashlist[i];
664 hashlist[i] = hashlist[i]->Next;
665 }
666 else
667 {
668 TRACKING_LIST *tt = hashlist[i];
669 TRACKING_LIST *prev = NULL;
670
671 while (true)
672 {
673 if (tt->Object == o)
674 {
675 prev->Next = tt->Next;
676 ft = tt;
677 break;
678 }
679
680 if (tt->Next == NULL)
681 {
682 break;
683 }
684
685 prev = tt;
686 tt = tt->Next;
687 }
688 }
689
690 if (ft != NULL)
691 {
692 OSMemoryFree(ft);
693
694 if (free_object_memory)
695 {
696 FreeCallStack(o->CallStack);
697 OSMemoryFree(o);
698 }
699 }
700 }
701 }
702
703 // Insert an object into the tracking list
InsertTrackingList(TRACKING_OBJECT * o)704 void InsertTrackingList(TRACKING_OBJECT *o)
705 {
706 UINT i;
707 TRACKING_LIST *t;
708 // Validate arguments
709 if (o == NULL)
710 {
711 return;
712 }
713
714 t = OSMemoryAlloc(sizeof(TRACKING_LIST));
715 t->Object = o;
716 t->Next = NULL;
717
718 i = TRACKING_HASH(o->Address);
719
720 if (hashlist[i] == NULL)
721 {
722 hashlist[i] = t;
723 }
724 else
725 {
726 TRACKING_LIST *tt = hashlist[i];
727 while (true)
728 {
729 if (tt->Next == NULL)
730 {
731 tt->Next = t;
732 break;
733 }
734
735 tt = tt->Next;
736 }
737 }
738 }
739
740 // Lock the tracking list
LockTrackingList()741 void LockTrackingList()
742 {
743 OSLock(obj_lock);
744 }
745
746 // Unlock the tracking list
UnlockTrackingList()747 void UnlockTrackingList()
748 {
749 OSUnlock(obj_lock);
750 }
751
752 // Initialize the tracking
InitTracking()753 void InitTracking()
754 {
755 UINT i;
756 CALLSTACK_DATA *s;
757
758 // Hash list initialization
759 hashlist = (TRACKING_LIST **)OSMemoryAlloc(sizeof(TRACKING_LIST *) * TRACKING_NUM_ARRAY);
760
761 for (i = 0;i < TRACKING_NUM_ARRAY;i++)
762 {
763 hashlist[i] = NULL;
764 }
765
766 obj_id = 0;
767
768 // Create a lock
769 obj_lock = OSNewLock();
770 obj_id_lock = OSNewLock();
771 cs_lock = OSNewLock();
772
773 s = GetCallStack();
774 if (s == NULL)
775 {
776 do_not_get_callstack = true;
777 }
778 else
779 {
780 do_not_get_callstack = false;
781 FreeCallStack(s);
782 }
783 }
784
785 // Release the tracking
FreeTracking()786 void FreeTracking()
787 {
788 UINT i;
789 // Delete the lock
790 OSDeleteLock(obj_lock);
791 OSDeleteLock(obj_id_lock);
792 OSDeleteLock(cs_lock);
793 cs_lock = NULL;
794 obj_id_lock = NULL;
795 obj_lock = NULL;
796
797 // Release all of the elements
798 for (i = 0;i < TRACKING_NUM_ARRAY;i++)
799 {
800 if (hashlist[i] != NULL)
801 {
802 TRACKING_LIST *t = hashlist[i];
803
804 while (true)
805 {
806 TRACKING_LIST *t2 = t;
807 TRACKING_OBJECT *o = t->Object;
808
809 FreeCallStack(o->CallStack);
810 OSMemoryFree(o);
811
812 t = t->Next;
813
814 OSMemoryFree(t2);
815
816 if (t == NULL)
817 {
818 break;
819 }
820 }
821 }
822 }
823
824 // Release the list
825 OSMemoryFree(hashlist);
826 }
827
828 // Show the call stack
PrintCallStack(CALLSTACK_DATA * s)829 void PrintCallStack(CALLSTACK_DATA *s)
830 {
831 char tmp[MAX_SIZE * 2];
832
833 GetCallStackStr(tmp, sizeof(tmp), s);
834 Print("%s", tmp);
835 }
836
837 // Convert the call stack to a string
GetCallStackStr(char * str,UINT size,CALLSTACK_DATA * s)838 void GetCallStackStr(char *str, UINT size, CALLSTACK_DATA *s)
839 {
840 char tmp[MAX_SIZE];
841 char tmp2[MAX_SIZE];
842 char tmp3[MAX_SIZE];
843 UINT num, i;
844 // Validate arguments
845 if (str == NULL)
846 {
847 return;
848 }
849
850 if (s == NULL)
851 {
852 StrCpy(str, size, "(Unknown)\n");
853 }
854 else
855 {
856 num = 0;
857 str[0] = 0;
858 while (true)
859 {
860 if (s == NULL)
861 {
862 break;
863 }
864
865 GetCallStackSymbolInfo(s);
866
867 if (s->name == NULL)
868 {
869 Format(tmp, sizeof(tmp), "0x%p ---", UINT64_TO_POINTER(s->offset));
870 }
871 else
872 {
873 Format(tmp, sizeof(tmp), "0x%p %s() + 0x%02x",
874 (void *)s->offset, s->name, UINT64_TO_POINTER(s->disp));
875 }
876 for (i = 0;i < num;i++)
877 {
878 tmp2[i] = ' ';
879 }
880 tmp2[i] = '\0';
881 StrCpy(tmp3, sizeof(tmp3), tmp2);
882 StrCat(tmp3, sizeof(tmp3), tmp);
883 Format(tmp, sizeof(tmp), "%-55s %11s %u\n", tmp3, s->filename, s->line);
884 StrCat(str, size, tmp);
885 num++;
886 s = s->next;
887 }
888 }
889 }
890
891 // Get the current call stack
GetCallStack()892 CALLSTACK_DATA *GetCallStack()
893 {
894 CALLSTACK_DATA *s;
895 if (do_not_get_callstack)
896 {
897 // Not to get the call stack
898 return NULL;
899 }
900
901 OSLock(cs_lock);
902 {
903 // Get the call stack
904 s = OSGetCallStack();
905 }
906 OSUnlock(cs_lock);
907 if (s == NULL)
908 {
909 return NULL;
910 }
911
912 // Descend in the call stack for 3 steps
913 s = WalkDownCallStack(s, 3);
914
915 return s;
916 }
917
918 // Get the symbol information of the call stack
GetCallStackSymbolInfo(CALLSTACK_DATA * s)919 bool GetCallStackSymbolInfo(CALLSTACK_DATA *s)
920 {
921 bool ret;
922 // Validate arguments
923 if (s == NULL)
924 {
925 return false;
926 }
927
928 OSLock(cs_lock);
929 {
930 ret = OSGetCallStackSymbolInfo(s);
931 }
932 OSUnlock(cs_lock);
933
934 return ret;
935 }
936
937 // Descend in the call stack by a specified number
WalkDownCallStack(CALLSTACK_DATA * s,UINT num)938 CALLSTACK_DATA *WalkDownCallStack(CALLSTACK_DATA *s, UINT num)
939 {
940 CALLSTACK_DATA *cs, *tmp;
941 UINT i;
942 // Validate arguments
943 if (s == NULL)
944 {
945 return NULL;
946 }
947
948 cs = s;
949 i = 0;
950
951 while (true)
952 {
953 if (i >= num)
954 {
955 return cs;
956 }
957 i++;
958 tmp = cs;
959 cs = tmp->next;
960 OSMemoryFree(tmp->name);
961 OSMemoryFree(tmp);
962
963 if (cs == NULL)
964 {
965 return NULL;
966 }
967 }
968 }
969
970 // Release the call stack
FreeCallStack(CALLSTACK_DATA * s)971 void FreeCallStack(CALLSTACK_DATA *s)
972 {
973 // Validate arguments
974 if (s == NULL)
975 {
976 return;
977 }
978
979 while (true)
980 {
981 CALLSTACK_DATA *next = s->next;
982 OSMemoryFree(s->name);
983 OSMemoryFree(s);
984 if (next == NULL)
985 {
986 break;
987 }
988 s = next;
989 }
990 }
991
992
993