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