1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
*
*/
#include <pspkernel.h>
#include <pspdebug.h>
#include <stdarg.h>
#include <stdio.h>
#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "common/scummsys.h"
int psp_debug_indent = 0;
bool firstWriteToFile = true;
void PspDebugTrace(bool alsoToScreen, const char *format, ...) {
va_list opt;
char buffer[2048];
int bufsz;
FILE *fd = 0;
va_start(opt, format);
bufsz = vsnprintf(buffer, (size_t) sizeof(buffer), format, opt);
va_end(opt);
if (firstWriteToFile) {
fd = fopen("SCUMMTRACE.TXT", "wb"); // erase the file the first time we write
firstWriteToFile = false;
} else {
fd = fopen("SCUMMTRACE.TXT", "ab");
}
if (fd == 0)
return;
fwrite(buffer, 1, bufsz, fd);
fclose(fd);
if (alsoToScreen)
fprintf(stderr, buffer);
}
// Assembly functions to get the Return Address register and the Stack pointer register
#define GET_RET(retAddr) \
asm volatile ("move %0,$ra\n\t" \
: "=&r" (retAddr) : )
#define GET_SP(stackPtr) \
asm volatile ("move %0,$sp\n\t" \
: "=&r" (stackPtr) : )
// Function to retrieve a backtrace for the MIPS processor
// This is not trivial since the MIPS doesn't use a frame pointer.
// Takes the number of levels wanted above the calling function (included) and an array of void *
//
void mipsBacktrace(uint32 levels, void **addresses) {
// get the current return address
register byte *retAddr;
register byte *stackPointer;
GET_RET(retAddr);
GET_SP(stackPointer);
char string[100];
if (!levels)
return;
memset(addresses, 0, sizeof(void *) * levels);
uint32 curLevel = 0;
const uint32 SP_SUBTRACT = 0x27bd8000; // The instruction to subtract from the SP looks like this
const uint32 SP_SUB_HIGH_MASK = 0xffff8000; // The mask to check for the subtract SP instruction
const uint32 SP_SUB_LOW_MASK = 0x0000ffff; // The mask that gives us how much was subtracted
// make sure we go out of the stack of this current level
// we already have the return address for this level from the register
if (curLevel < levels) {
void *thisFunc = (void *)mipsBacktrace;
for (uint32 *seekPtr = (uint32 *)thisFunc; ; seekPtr++) {
if ((*seekPtr & SP_SUB_HIGH_MASK) == SP_SUBTRACT) {
// we found the $sp subtraction at the beginning of the function
int16 subAmount = (int16)((*seekPtr) & SP_SUB_LOW_MASK);
//sprintf(string, "found local $sp sub at %p. Data[%x]. Sub amount %d\n", seekPtr, *seekPtr, subAmount);
//fputs(string, stderr);
stackPointer -= subAmount;
byte *testRetAddr = (byte *)*((uint32 *)(stackPointer - 4));
if (testRetAddr != retAddr) {
sprintf(string, "mismatch in testretAddr.\n");
fputs(string, stderr);
}
break;
}
}
}
// keep scanning while more levels are requested
while (curLevel < levels) {
// now scan backwards from the return address to find the size of the stack
for(uint32 *seekPtr = (uint32 *)retAddr; ; seekPtr--) {
if (((*seekPtr) & SP_SUB_HIGH_MASK) == SP_SUBTRACT) {
// we found the $sp subtraction at the beginning of the function
int16 subAmount = (int16)((*seekPtr) & SP_SUB_LOW_MASK);
//sprintf(string, "found $sp sub at %p. Data[%x]. Sub amount %d\n", seekPtr, *seekPtr, subAmount);
//fputs(string, stderr);
stackPointer -= subAmount;
retAddr = (byte *)*((uint32 *)(stackPointer - 4));
if (retAddr < (byte *)0x8900000 || retAddr > (byte *)0xC900000) {
sprintf(string, "invalid retAddr %p\n", retAddr);
fputs(string, stderr);
return;
}
//sprintf(string, "retAddr[%p]\n", retAddr);
//fputs(string, stderr);
addresses[curLevel++] = retAddr;
break;
}
}
}
}
|