├── .clang-format ├── .github └── workflows │ └── compilation.yml ├── .gitignore ├── Makefile ├── README ├── ee ├── Makefile ├── gdb-low.S ├── gdb-stub.h ├── inst.h ├── ps2gdbStub.c └── r5900_regs.h ├── ps2.sh └── sample ├── Makefile └── testgdb.c /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: true 6 | AlignConsecutiveBitFields: AcrossEmptyLinesAndComments 7 | AlignConsecutiveDeclarations: false 8 | AlignConsecutiveMacros: AcrossComments 9 | AlignEscapedNewlines: Left 10 | AlignOperands: Align 11 | AlignTrailingComments: true 12 | AllowAllArgumentsOnNextLine: false 13 | AllowAllConstructorInitializersOnNextLine: true 14 | AllowAllParametersOfDeclarationOnNextLine: true 15 | AllowShortBlocksOnASingleLine: Empty 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortEnumsOnASingleLine: true 18 | AllowShortFunctionsOnASingleLine: All 19 | AllowShortIfStatementsOnASingleLine: Never 20 | AllowShortLambdasOnASingleLine: Empty 21 | AllowShortLoopsOnASingleLine: false 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: false 24 | AlwaysBreakTemplateDeclarations: true 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BitFieldColonSpacing : Both 28 | BreakBeforeBraces: Custom 29 | BraceWrapping: 30 | AfterCaseLabel: false 31 | AfterClass: true 32 | AfterControlStatement: false 33 | AfterEnum: false 34 | AfterFunction: true 35 | AfterNamespace: true 36 | AfterObjCDeclaration: false 37 | AfterStruct: true 38 | AfterUnion: true 39 | AfterExternBlock: false 40 | BeforeCatch: false 41 | BeforeElse: false 42 | BeforeLambdaBody: false 43 | BeforeWhile: false 44 | IndentBraces: false 45 | SplitEmptyFunction: true 46 | SplitEmptyRecord: true 47 | SplitEmptyNamespace: true 48 | BreakBeforeBinaryOperators: None 49 | BreakBeforeConceptDeclarations: true 50 | BreakBeforeTernaryOperators: false 51 | BreakConstructorInitializers: BeforeComma 52 | BreakStringLiterals: true 53 | ColumnLimit: 0 54 | CommentPragmas: '^ (IWYU pragma:|NOLINT)' 55 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 56 | ConstructorInitializerIndentWidth: 4 57 | ContinuationIndentWidth: 4 58 | Cpp11BracedListStyle: true 59 | DeriveLineEnding: true 60 | DerivePointerAlignment: false 61 | DisableFormat: false 62 | EmptyLineBeforeAccessModifier: LogicalBlock 63 | FixNamespaceComments: true 64 | ForEachMacros: [] 65 | IncludeBlocks: Preserve 66 | IndentExternBlock: NoIndent 67 | IndentCaseBlocks: false 68 | IndentCaseLabels: true 69 | IndentGotoLabels: true 70 | IndentWidth: 4 71 | IndentWrappedFunctionNames: false 72 | KeepEmptyLinesAtTheStartOfBlocks: true 73 | MacroBlockBegin: '' 74 | MacroBlockEnd: '' 75 | MaxEmptyLinesToKeep: 3 76 | NamespaceIndentation: None 77 | ObjCBlockIndentWidth: 2 78 | ObjCSpaceAfterProperty: false 79 | ObjCSpaceBeforeProtocolList: true 80 | PenaltyBreakAssignment: 80 81 | PenaltyBreakBeforeFirstCallParameter: 19 82 | PenaltyBreakComment: 300 83 | PenaltyBreakFirstLessLess: 120 84 | PenaltyBreakString: 1000 85 | PenaltyBreakTemplateDeclaration: 80 86 | PenaltyExcessCharacter: 1000000 87 | PenaltyIndentedWhitespace: 80 88 | PenaltyReturnTypeOnItsOwnLine: 60 89 | PointerAlignment: Right 90 | # uncomment below when clang >13 will be out 91 | # IndentPPDirectives: AfterHash 92 | # PPIndentWidth: 1 93 | ReflowComments: true 94 | SortIncludes: false 95 | SpaceAfterCStyleCast: false 96 | SpaceAfterLogicalNot: false 97 | SpaceAroundPointerQualifiers: Default 98 | SpaceBeforeAssignmentOperators: true 99 | SpaceBeforeCaseColon: false 100 | SpaceBeforeCpp11BracedList: true 101 | SpaceBeforeInheritanceColon: false 102 | SpaceBeforeParens: ControlStatements 103 | SpaceBeforeRangeBasedForLoopColon: true 104 | SpaceBeforeSquareBrackets: false 105 | SpaceInEmptyBlock: false 106 | SpaceInEmptyParentheses: false 107 | SpacesBeforeTrailingComments: 1 108 | SpacesInAngles: false 109 | SpacesInConditionalStatement: false 110 | SpacesInContainerLiterals: true 111 | SpacesInCStyleCastParentheses: false 112 | SpacesInParentheses: false 113 | SpacesInSquareBrackets: false 114 | Standard: Cpp11 115 | TabWidth: 4 116 | UseTab: Never 117 | -------------------------------------------------------------------------------- /.github/workflows/compilation.yml: -------------------------------------------------------------------------------- 1 | name: CI-compile 2 | 3 | on: 4 | push: 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | container: ghcr.io/ps2dev/ps2dev:latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | with: 13 | fetch-depth: 0 14 | 15 | - name: Install dependencies 16 | run: | 17 | apk add build-base git 18 | 19 | - name: Compile build 20 | run: | 21 | make clean all 22 | 23 | - name: Upload sample 24 | if: ${{ success() }} 25 | uses: actions/upload-artifact@v4 26 | with: 27 | name: sample 28 | path: | 29 | sample/*.elf 30 | sample/*.irx 31 | 32 | - name: Create release 33 | if: github.ref == 'refs/heads/master' 34 | uses: marvinpinto/action-automatic-releases@latest 35 | with: 36 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 37 | automatic_release_tag: "latest" 38 | title: "Latest development build" 39 | files: | 40 | sample/*.elf 41 | sample/*.irx 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.elf 3 | *.erl 4 | *.irx 5 | *.o 6 | 7 | .* 8 | !.gitignore 9 | !.github 10 | !.clang-format 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # _____ ___ ____ 2 | # ____| | ____| PSX2 OpenSource Project 3 | # | ___| |____ (C)2002, Ray Donnelly ( rdonnelly@polygoons.com ) 4 | # -------------------------------------------------------------------------- 5 | 6 | 7 | all: 8 | $(MAKE) -C ee 9 | $(MAKE) -C sample 10 | 11 | debug: 12 | $(MAKE) -C ee debug 13 | $(MAKE) -C sample 14 | 15 | install: 16 | $(MAKE) -C ee install 17 | 18 | clean: 19 | $(MAKE) -C ee clean 20 | $(MAKE) -C sample clean 21 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2024 Current State by crt0 2 | 3 | Writing/Reading variables, memory, registers (only as 32bit), call stack - works. 4 | 5 | Example usage: run sample with ps2link: 6 | ps2client -h 192.168.1.13 execee host:testgdb.elf 7 | in nanother terminal 8 | mips64r5900el-ps2-elf-gdb -x ps2.sh 9 | 10 | TODO: rewrite metwork stack 11 | 12 | 13 | INTRODUCTION 14 | ---------------------------------------------------------------------------- 15 | 16 | ps2gdbStub is a tcp stub for the gnu debugger. It could be easily changed 17 | to not use tcp. The low level portion reads 128 bits for the 32 gprs and 18 | also for lo and hi, although these are converted down to 32 bits before 19 | sending to the remote GDB. 20 | 21 | Currently, the code *must* be uploaded via pukklink or ps2link. Naplink 22 | won't do it! 23 | 24 | As for building the remote GDB, I configured gdb as mips-idt-elf and hacked 25 | about with it a bit. I managed to get the latest weekly snapshot (which at 26 | time of writing was gdb+dejagnu-20030801.tar.bz2) to work, after some hacking 27 | around. I've included a .cmd file for use with the remote GDB. You'll need 28 | to change the target line with the correct IP of your ps2. To invoke, from 29 | the shell, type 30 | 31 | With reference to the frame pointer, gpr $30 should be the frame pointer, 32 | this is what the MIPS abi says anyway. However, our toolchain appears to use 33 | grp $30 as another saved register (s8), so I just report the fp to be the 34 | same as the sp at the moment. 35 | 36 | 37 | COPYRIGHT FOR PS2GDBSTUB 38 | ---------------------------------------------------------------------------- 39 | 40 | Copyright (c) 2003 Ray Donnelly (rdonnelly@polygoons.com) 41 | All rights reserved. 42 | 43 | Redistribution and use in source and binary forms, with or without 44 | modification, are permitted provided that the following conditions are met: 45 | 46 | 1. Redistributions of source code must retain the above copyright notice, 47 | this list of conditions and the following disclaimer. 48 | 2. The author grants you a license to use ps2gdbStub for academic, research 49 | and non-commercial purposes only. 50 | 3. The author imposes no restriction on any code developed using the 51 | software. However, the author retains a non-exclusive royalty-free 52 | license to any modification to the distribution made by the licensee. 53 | 4. Any Licensee wishing to make commercial use of the Softare must 54 | contact the author to execute the appropriate license for such 55 | commercial use. Commercial use includes 56 | - Integration of all or part of the source code into a product for sale 57 | or commercial license by or on behalf Licensee to third parties, or 58 | - distribution of the binary code or source code to third parites that 59 | need it to utilize a commercial product sold or licensed by or on 60 | behalf of Licensee. 61 | 62 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 63 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 64 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 65 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 66 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 67 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 68 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 69 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 70 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 71 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 72 | THE POSSIBILITY OF SUCH DAMAGE. 73 | 74 | -------------------------------------------------------------------------------- /ee/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile template 3 | # 4 | DEBUG ?= 0 5 | 6 | EE_LIB_DIR = ../lib/ 7 | EE_LIB = $(EE_LIB_DIR)libps2gdbStub.a 8 | EE_OBJS = ps2gdbStub.o gdb-low.o 9 | 10 | EE_CFLAGS += -g -w 11 | # -DDEBUG 12 | EE_LDFLAGS += -Wl,-Map,ps2gdbStub.map -L. -L../lib -L$(PS2SDK)/ee/lib 13 | 14 | ifeq ($(DEBUG),1) 15 | EE_CFLAGS += -DDEBUG 16 | endif 17 | 18 | all: $(EE_LIB) 19 | @mkdir -p $(EE_LIB_DIR) 20 | $(EE_AR) rcs $(EE_LIB) $(EE_OBJS) 21 | 22 | debug: 23 | $(MAKE) DEBUG=1 all 24 | 25 | install: all 26 | cp -f $(EE_LIB) $(PS2SDK)/ports/lib 27 | 28 | clean: 29 | rm -rf $(EE_OBJS) $(EE_LIB) $(EE_LIB_DIR) 30 | 31 | include $(PS2SDK)/samples/Makefile.pref 32 | include $(PS2SDK)/samples/Makefile.eeglobal 33 | -------------------------------------------------------------------------------- /ee/gdb-low.S: -------------------------------------------------------------------------------- 1 | /* 2 | _____ ___ ____ 3 | ____| | ____| PSX2 OpenSource Project 4 | | ___| |____ (C)2003, Ray Donnelly ( rdonnelly@polygoons.com ) 5 | -------------------------------------------------------------------------- 6 | gdb-low.S PS2 REMOTE GDB STUB USING TCP 7 | */ 8 | 9 | #define __ASSEMBLY__ 10 | 11 | #include "r5900_regs.h" // For nicer names. 12 | #include "gdb-stub.h" // For frame pointer offsets. 13 | 14 | .text 15 | .align 5 16 | .global faked_ra 17 | .global gdbstub_ps2_regs 18 | .global trap_low 19 | .type trap_low,@function 20 | .ent trap_low 21 | 22 | trap_low: 23 | .set push 24 | .set noreorder 25 | .set noat 26 | 27 | la k0,gdbstub_ps2_regs 28 | sq v0,GDB_FR_REG2(k0) 29 | nop 30 | 31 | // Save the cop0, hi and lo registers. 32 | mfc0 v0,CP0_STATUS 33 | sw v0,GDB_FR_STATUS(k0) 34 | mfc0 v0,CP0_CAUSE 35 | sw v0,GDB_FR_CAUSE(k0) 36 | mfc0 v0,CP0_EPC 37 | sw v0,GDB_FR_EPC(k0) 38 | mfc0 v0,CP0_BADVADDR // Not restored. 39 | sw v0,GDB_FR_BADVADDR(k0) 40 | pmfhi v0 41 | sq v0,GDB_FR_HI(k0) 42 | pmflo v0 43 | sq v0,GDB_FR_LO(k0) 44 | 45 | // Integer registers. 46 | sq zero,GDB_FR_REG0(k0) // Yeah, whatever! 47 | sq at,GDB_FR_REG1(k0) 48 | sq v1,GDB_FR_REG3(k0) 49 | sq a0,GDB_FR_REG4(k0) 50 | sq a1,GDB_FR_REG5(k0) 51 | sq a2,GDB_FR_REG6(k0) 52 | sq a3,GDB_FR_REG7(k0) 53 | sq t0,GDB_FR_REG8(k0) 54 | sq t1,GDB_FR_REG9(k0) 55 | sq t2,GDB_FR_REG10(k0) 56 | sq t3,GDB_FR_REG11(k0) 57 | sq t4,GDB_FR_REG12(k0) 58 | sq t5,GDB_FR_REG13(k0) 59 | sq t6,GDB_FR_REG14(k0) 60 | sq t7,GDB_FR_REG15(k0) 61 | sq s0,GDB_FR_REG16(k0) 62 | sq s1,GDB_FR_REG17(k0) 63 | sq s2,GDB_FR_REG18(k0) 64 | sq s3,GDB_FR_REG19(k0) 65 | sq s4,GDB_FR_REG20(k0) 66 | sq s5,GDB_FR_REG21(k0) 67 | sq s6,GDB_FR_REG22(k0) 68 | sq s7,GDB_FR_REG23(k0) 69 | sq t8,GDB_FR_REG24(k0) 70 | sq t9,GDB_FR_REG25(k0) 71 | // k0 already saved. 72 | // k1 already saved. 73 | sq gp,GDB_FR_REG28(k0) 74 | sq sp,GDB_FR_REG29(k0) 75 | sq fp,GDB_FR_REG30(k0) 76 | sq ra,GDB_FR_REG31(k0) 77 | 78 | // Floating point registers 79 | mfc0 v0,CP0_STATUS // FPU enabled? 80 | srl v0,v0,16 81 | andi v0,v0,(ST0_CU1 >> 16) 82 | beqz v0,2f // Disabled, skip 83 | nop 84 | 85 | swc1 $0,GDB_FR_FPR0(k0) 86 | swc1 $1,GDB_FR_FPR1(k0) 87 | swc1 $2,GDB_FR_FPR2(k0) 88 | swc1 $3,GDB_FR_FPR3(k0) 89 | swc1 $4,GDB_FR_FPR4(k0) 90 | swc1 $5,GDB_FR_FPR5(k0) 91 | swc1 $6,GDB_FR_FPR6(k0) 92 | swc1 $7,GDB_FR_FPR7(k0) 93 | swc1 $8,GDB_FR_FPR8(k0) 94 | swc1 $9,GDB_FR_FPR9(k0) 95 | swc1 $10,GDB_FR_FPR10(k0) 96 | swc1 $11,GDB_FR_FPR11(k0) 97 | swc1 $12,GDB_FR_FPR12(k0) 98 | swc1 $13,GDB_FR_FPR13(k0) 99 | swc1 $14,GDB_FR_FPR14(k0) 100 | swc1 $15,GDB_FR_FPR15(k0) 101 | swc1 $16,GDB_FR_FPR16(k0) 102 | swc1 $17,GDB_FR_FPR17(k0) 103 | swc1 $18,GDB_FR_FPR18(k0) 104 | swc1 $19,GDB_FR_FPR19(k0) 105 | swc1 $20,GDB_FR_FPR20(k0) 106 | swc1 $21,GDB_FR_FPR21(k0) 107 | swc1 $22,GDB_FR_FPR22(k0) 108 | swc1 $23,GDB_FR_FPR23(k0) 109 | swc1 $24,GDB_FR_FPR24(k0) 110 | swc1 $25,GDB_FR_FPR25(k0) 111 | swc1 $26,GDB_FR_FPR26(k0) 112 | swc1 $27,GDB_FR_FPR27(k0) 113 | swc1 $28,GDB_FR_FPR28(k0) 114 | swc1 $29,GDB_FR_FPR29(k0) 115 | swc1 $30,GDB_FR_FPR30(k0) 116 | swc1 $31,GDB_FR_FPR31(k0) 117 | 118 | // FPU control registers 119 | mfc1 v0,CP1_STATUS 120 | sw v0,GDB_FR_FSR(k0) 121 | mfc1 v0,CP1_REVISION 122 | sw v0,GDB_FR_FIR(k0) 123 | 124 | 2: 125 | // Current stack frame ptr 126 | // Why? In case it differs from sp because of alloca, with our tool-chains, fp's used as another saved register (s8). As 127 | // such, I don't know which ABI we're using! 128 | sw sp,GDB_FR_FRP(k0) 129 | 130 | // CP0 registers (R4000/R4400 unused registers skipped) 131 | mfc0 v0,CP0_INDEX 132 | sw v0,GDB_FR_CP0_INDEX(k0) 133 | mfc0 v0,CP0_RANDOM 134 | sw v0,GDB_FR_CP0_RANDOM(k0) 135 | mfc0 v0,CP0_ENTRYLO0 136 | sw v0,GDB_FR_CP0_ENTRYLO0(k0) 137 | mfc0 v0,CP0_ENTRYLO1 138 | sw v0,GDB_FR_CP0_ENTRYLO1(k0) 139 | mfc0 v0,CP0_CONTEXT 140 | sw v0,GDB_FR_CP0_CONTEXT(k0) 141 | mfc0 v0,CP0_PAGEMASK 142 | sw v0,GDB_FR_CP0_PAGEMASK(k0) 143 | mfc0 v0,CP0_WIRED 144 | sw v0,GDB_FR_CP0_WIRED(k0) 145 | mfc0 v0,CP0_ENTRYHI 146 | sw v0,GDB_FR_CP0_ENTRYHI(k0) 147 | mfc0 v0,CP0_PRID 148 | sw v0,GDB_FR_CP0_PRID(k0) 149 | 150 | // Playstation 2 Specific registers 151 | mtc1 $0,fp0 // This saves acc. 152 | madd.s fp0,fp0,fp0 // FPR[0] <- ACC + FPR[0] * FPR[0] 153 | mfc1 v0,fp0 154 | sw v0,GDB_FR_CP1_ACC(k0) 155 | mfsa v0 156 | sw v0,GDB_FR_SHFT_AMNT(k0) 157 | mflo1 v0 158 | sw v0,GDB_FR_LO1(k0) 159 | mfhi1 v0 160 | sw v0,GDB_FR_HI1(k0) 161 | 162 | // Arg 0 for handle_exception is gdbstub_regs. 163 | move a0,k0 164 | 165 | // Faked return from exception. Then jumps to handle_exception. 166 | la at,faked_epc 167 | mtc0 at,CP0_EPC 168 | sync.p 169 | mfc0 at,CP0_STATUS 170 | li v0,0xfffffffe 171 | and at,v0 172 | mtc0 at,CP0_STATUS 173 | sync.p 174 | eret 175 | nop 176 | nop 177 | 178 | faked_epc: 179 | nop 180 | nop 181 | jal handle_exception 182 | nop 183 | nop 184 | nop 185 | 186 | 187 | faked_ra: 188 | di 189 | 190 | li $3, 0x64 191 | move $4,$0 192 | syscall // FlushCache(0) - Writeback data cache 193 | nop 194 | 195 | li $3, 0x64 196 | li $4, 2 197 | syscall // FlushCache(2) - Flush inst cache 198 | nop 199 | 200 | nop 201 | nop 202 | la k0,gdbstub_ps2_regs 203 | mfc0 at,CP0_STATUS // Sony do this... I don't think I want to do this though. It's odd! 204 | li k1,0xffffffe4 // last byte is 0b11100100, which sets IEc, KUc, KUp, IEo to 0. Not what you'd expect. 205 | and at,at,k1 206 | mtc0 at,CP0_STATUS 207 | sync.p 208 | 209 | // Playstation 2 specific registers. 210 | lw v0,GDB_FR_CP1_ACC(k0) 211 | mtc1 $0,fp0 212 | mtc1 v0,fp1 213 | adda.s fp0,fp1 214 | lw v0,GDB_FR_SHFT_AMNT(k0) 215 | mtsa v0 216 | lw v0,GDB_FR_LO1(k0) 217 | mtlo1 v0 218 | lw v0,GDB_FR_HI1(k0) 219 | mthi1 v0 220 | lw v0,GDB_FR_CP0_ENTRYHI(k0) 221 | lw v1,GDB_FR_CP0_WIRED(k0) 222 | mtc0 v0,CP0_ENTRYHI 223 | mtc0 v1,CP0_WIRED 224 | lw v0,GDB_FR_CP0_PAGEMASK(k0) 225 | lw v1,GDB_FR_CP0_ENTRYLO1(k0) 226 | mtc0 v0,CP0_PAGEMASK 227 | mtc0 v1,CP0_ENTRYLO1 228 | lw v0,GDB_FR_CP0_ENTRYLO0(k0) 229 | lw v1,GDB_FR_CP0_INDEX(k0) 230 | mtc0 v0,CP0_ENTRYLO0 231 | mtc0 v1,CP0_INDEX 232 | lw v0,GDB_FR_CP0_CONTEXT(k0) 233 | mtc0 v0,CP0_CONTEXT 234 | 235 | // Floating point registers 236 | mfc0 v0,CP0_STATUS /* check if the FPU is enabled */ 237 | srl v0,v0,16 238 | andi v0,v0,(ST0_CU1 >> 16) 239 | 240 | beqz v0,3f /* disabled, skip */ 241 | nop 242 | 243 | lwc1 $31,GDB_FR_FPR31(k0) 244 | lwc1 $30,GDB_FR_FPR30(k0) 245 | lwc1 $29,GDB_FR_FPR29(k0) 246 | lwc1 $28,GDB_FR_FPR28(k0) 247 | lwc1 $27,GDB_FR_FPR27(k0) 248 | lwc1 $26,GDB_FR_FPR26(k0) 249 | lwc1 $25,GDB_FR_FPR25(k0) 250 | lwc1 $24,GDB_FR_FPR24(k0) 251 | lwc1 $23,GDB_FR_FPR23(k0) 252 | lwc1 $22,GDB_FR_FPR22(k0) 253 | lwc1 $21,GDB_FR_FPR21(k0) 254 | lwc1 $20,GDB_FR_FPR20(k0) 255 | lwc1 $19,GDB_FR_FPR19(k0) 256 | lwc1 $18,GDB_FR_FPR18(k0) 257 | lwc1 $17,GDB_FR_FPR17(k0) 258 | lwc1 $16,GDB_FR_FPR16(k0) 259 | lwc1 $15,GDB_FR_FPR15(k0) 260 | lwc1 $14,GDB_FR_FPR14(k0) 261 | lwc1 $13,GDB_FR_FPR13(k0) 262 | lwc1 $12,GDB_FR_FPR12(k0) 263 | lwc1 $11,GDB_FR_FPR11(k0) 264 | lwc1 $10,GDB_FR_FPR10(k0) 265 | lwc1 $9,GDB_FR_FPR9(k0) 266 | lwc1 $8,GDB_FR_FPR8(k0) 267 | lwc1 $7,GDB_FR_FPR7(k0) 268 | lwc1 $6,GDB_FR_FPR6(k0) 269 | lwc1 $5,GDB_FR_FPR5(k0) 270 | lwc1 $4,GDB_FR_FPR4(k0) 271 | lwc1 $3,GDB_FR_FPR3(k0) 272 | lwc1 $2,GDB_FR_FPR2(k0) 273 | lwc1 $1,GDB_FR_FPR1(k0) 274 | lwc1 $0,GDB_FR_FPR0(k0) 275 | 276 | 277 | // CP0 and integer registers 278 | 3: 279 | mfc0 t0,CP0_STATUS 280 | ori t0,0x1f 281 | xori t0,0x1f 282 | mtc0 t0,CP0_STATUS 283 | 284 | lw v0,GDB_FR_STATUS(k0) 285 | lw v1,GDB_FR_EPC(k0) 286 | 287 | mtc0 v0,CP0_STATUS 288 | sync.p 289 | mtc0 v1,CP0_EPC 290 | sync.p 291 | lq v0,GDB_FR_HI(k0) 292 | lq v1,GDB_FR_LO(k0) 293 | pmthi v0 294 | pmtlo v1 295 | lq $31,GDB_FR_REG31(k0) 296 | lq $30,GDB_FR_REG30(k0) 297 | lq $29,GDB_FR_REG29(k0) 298 | lq $28,GDB_FR_REG28(k0) 299 | lq $25,GDB_FR_REG25(k0) 300 | lq $24,GDB_FR_REG24(k0) 301 | lq $23,GDB_FR_REG23(k0) 302 | lq $22,GDB_FR_REG22(k0) 303 | lq $21,GDB_FR_REG21(k0) 304 | lq $20,GDB_FR_REG20(k0) 305 | lq $19,GDB_FR_REG19(k0) 306 | lq $18,GDB_FR_REG18(k0) 307 | lq $17,GDB_FR_REG17(k0) 308 | lq $16,GDB_FR_REG16(k0) 309 | lq $15,GDB_FR_REG15(k0) 310 | lq $14,GDB_FR_REG14(k0) 311 | lq $13,GDB_FR_REG13(k0) 312 | lq $12,GDB_FR_REG12(k0) 313 | lq $11,GDB_FR_REG11(k0) 314 | lq $10,GDB_FR_REG10(k0) 315 | lq $9,GDB_FR_REG9(k0) 316 | lq $8,GDB_FR_REG8(k0) 317 | lq $7,GDB_FR_REG7(k0) 318 | lq $6,GDB_FR_REG6(k0) 319 | lq $5,GDB_FR_REG5(k0) 320 | lq $4,GDB_FR_REG4(k0) 321 | lq $3,GDB_FR_REG3(k0) 322 | lq $2,GDB_FR_REG2(k0) 323 | lq $1,GDB_FR_REG1(k0) 324 | 325 | mfc0 k0,CP0_CAUSE // I added these 326 | ori k0,k0,0x13 // I added these 327 | mtc0 k0,CP0_CAUSE // I added these 328 | 329 | sync.p 330 | eret 331 | nop 332 | nop 333 | .set pop 334 | .end trap_low 335 | -------------------------------------------------------------------------------- /ee/gdb-stub.h: -------------------------------------------------------------------------------- 1 | /* 2 | _____ ___ ____ 3 | ____| | ____| PSX2 OpenSource Project 4 | | ___| |____ (C)2003, Ray Donnelly ( rdonnelly@polygoons.com ) 5 | -------------------------------------------------------------------------- 6 | gdb-stub.h PS2 REMOTE GDB STUB USING TCP 7 | */ 8 | 9 | #ifndef __ASM_MIPS_GDB_STUB_H 10 | #define __ASM_MIPS_GDB_STUB_H 11 | 12 | 13 | /* 14 | * important register numbers - TODO :: MAKE SURE THESE ARE STILL CORRECT (IT WAS 8 YEARS AGO!) 15 | */ 16 | 17 | #define REG_EPC 37 18 | #define REG_FP 72 19 | #define REG_SP 29 20 | 21 | /* 22 | * Stack layout for the GDB exception handler 23 | * Derived from the stack layout described in asm-mips/stackframe.h 24 | * 25 | * The first PTRSIZE*5 bytes are argument save space for C subroutines. 26 | */ 27 | #define NUMREGS 96 28 | #define GPR_SIZE 16 // Saves 16 bytes per register regardless of actual size. 29 | #define PTRSIZE 4 30 | 31 | #define GDB_FR_REG0 (GPR_SIZE * 5) /* 0 */ 32 | #define GDB_FR_REG1 ((GDB_FR_REG0) + GPR_SIZE) /* 1 */ 33 | #define GDB_FR_REG2 ((GDB_FR_REG1) + GPR_SIZE) /* 2 */ 34 | #define GDB_FR_REG3 ((GDB_FR_REG2) + GPR_SIZE) /* 3 */ 35 | #define GDB_FR_REG4 ((GDB_FR_REG3) + GPR_SIZE) /* 4 */ 36 | #define GDB_FR_REG5 ((GDB_FR_REG4) + GPR_SIZE) /* 5 */ 37 | #define GDB_FR_REG6 ((GDB_FR_REG5) + GPR_SIZE) /* 6 */ 38 | #define GDB_FR_REG7 ((GDB_FR_REG6) + GPR_SIZE) /* 7 */ 39 | #define GDB_FR_REG8 ((GDB_FR_REG7) + GPR_SIZE) /* 8 */ 40 | #define GDB_FR_REG9 ((GDB_FR_REG8) + GPR_SIZE) /* 9 */ 41 | #define GDB_FR_REG10 ((GDB_FR_REG9) + GPR_SIZE) /* 10 */ 42 | #define GDB_FR_REG11 ((GDB_FR_REG10) + GPR_SIZE) /* 11 */ 43 | #define GDB_FR_REG12 ((GDB_FR_REG11) + GPR_SIZE) /* 12 */ 44 | #define GDB_FR_REG13 ((GDB_FR_REG12) + GPR_SIZE) /* 13 */ 45 | #define GDB_FR_REG14 ((GDB_FR_REG13) + GPR_SIZE) /* 14 */ 46 | #define GDB_FR_REG15 ((GDB_FR_REG14) + GPR_SIZE) /* 15 */ 47 | #define GDB_FR_REG16 ((GDB_FR_REG15) + GPR_SIZE) /* 16 */ 48 | #define GDB_FR_REG17 ((GDB_FR_REG16) + GPR_SIZE) /* 17 */ 49 | #define GDB_FR_REG18 ((GDB_FR_REG17) + GPR_SIZE) /* 18 */ 50 | #define GDB_FR_REG19 ((GDB_FR_REG18) + GPR_SIZE) /* 19 */ 51 | #define GDB_FR_REG20 ((GDB_FR_REG19) + GPR_SIZE) /* 20 */ 52 | #define GDB_FR_REG21 ((GDB_FR_REG20) + GPR_SIZE) /* 21 */ 53 | #define GDB_FR_REG22 ((GDB_FR_REG21) + GPR_SIZE) /* 22 */ 54 | #define GDB_FR_REG23 ((GDB_FR_REG22) + GPR_SIZE) /* 23 */ 55 | #define GDB_FR_REG24 ((GDB_FR_REG23) + GPR_SIZE) /* 24 */ 56 | #define GDB_FR_REG25 ((GDB_FR_REG24) + GPR_SIZE) /* 25 */ 57 | #define GDB_FR_REG26 ((GDB_FR_REG25) + GPR_SIZE) /* 26 */ 58 | #define GDB_FR_REG27 ((GDB_FR_REG26) + GPR_SIZE) /* 27 */ 59 | #define GDB_FR_REG28 ((GDB_FR_REG27) + GPR_SIZE) /* 28 */ 60 | #define GDB_FR_REG29 ((GDB_FR_REG28) + GPR_SIZE) /* 29 */ 61 | #define GDB_FR_REG30 ((GDB_FR_REG29) + GPR_SIZE) /* 30 */ 62 | #define GDB_FR_REG31 ((GDB_FR_REG30) + GPR_SIZE) /* 31 */ 63 | 64 | /* 65 | * Saved special registers... TODORMD :: Move all ps2 specific ones to the very end. 66 | */ 67 | #define GDB_FR_LO ((GDB_FR_REG31) + GPR_SIZE) /* 32 */ // I've moved this... 68 | #define GDB_FR_HI ((GDB_FR_LO) + GPR_SIZE) /* 33 */ // ...and this... 69 | #define GDB_FR_STATUS ((GDB_FR_HI) + GPR_SIZE) /* 34 */ 70 | #define GDB_FR_BADVADDR ((GDB_FR_STATUS) + 4) /* 35 */ 71 | #define GDB_FR_CAUSE ((GDB_FR_BADVADDR) + 4) /* 36 */ 72 | #define GDB_FR_EPC ((GDB_FR_CAUSE) + 4) /* 37 */ 73 | 74 | /* 75 | * Saved floating point registers 76 | */ 77 | #define GDB_FR_FPR0 ((GDB_FR_EPC) + 4) /* 38 */ 78 | #define GDB_FR_FPR1 ((GDB_FR_FPR0) + 4) /* 39 */ 79 | #define GDB_FR_FPR2 ((GDB_FR_FPR1) + 4) /* 40 */ 80 | #define GDB_FR_FPR3 ((GDB_FR_FPR2) + 4) /* 41 */ 81 | #define GDB_FR_FPR4 ((GDB_FR_FPR3) + 4) /* 42 */ 82 | #define GDB_FR_FPR5 ((GDB_FR_FPR4) + 4) /* 43 */ 83 | #define GDB_FR_FPR6 ((GDB_FR_FPR5) + 4) /* 44 */ 84 | #define GDB_FR_FPR7 ((GDB_FR_FPR6) + 4) /* 45 */ 85 | #define GDB_FR_FPR8 ((GDB_FR_FPR7) + 4) /* 46 */ 86 | #define GDB_FR_FPR9 ((GDB_FR_FPR8) + 4) /* 47 */ 87 | #define GDB_FR_FPR10 ((GDB_FR_FPR9) + 4) /* 48 */ 88 | #define GDB_FR_FPR11 ((GDB_FR_FPR10) + 4) /* 49 */ 89 | #define GDB_FR_FPR12 ((GDB_FR_FPR11) + 4) /* 50 */ 90 | #define GDB_FR_FPR13 ((GDB_FR_FPR12) + 4) /* 51 */ 91 | #define GDB_FR_FPR14 ((GDB_FR_FPR13) + 4) /* 52 */ 92 | #define GDB_FR_FPR15 ((GDB_FR_FPR14) + 4) /* 53 */ 93 | #define GDB_FR_FPR16 ((GDB_FR_FPR15) + 4) /* 54 */ 94 | #define GDB_FR_FPR17 ((GDB_FR_FPR16) + 4) /* 55 */ 95 | #define GDB_FR_FPR18 ((GDB_FR_FPR17) + 4) /* 56 */ 96 | #define GDB_FR_FPR19 ((GDB_FR_FPR18) + 4) /* 57 */ 97 | #define GDB_FR_FPR20 ((GDB_FR_FPR19) + 4) /* 58 */ 98 | #define GDB_FR_FPR21 ((GDB_FR_FPR20) + 4) /* 59 */ 99 | #define GDB_FR_FPR22 ((GDB_FR_FPR21) + 4) /* 60 */ 100 | #define GDB_FR_FPR23 ((GDB_FR_FPR22) + 4) /* 61 */ 101 | #define GDB_FR_FPR24 ((GDB_FR_FPR23) + 4) /* 62 */ 102 | #define GDB_FR_FPR25 ((GDB_FR_FPR24) + 4) /* 63 */ 103 | #define GDB_FR_FPR26 ((GDB_FR_FPR25) + 4) /* 64 */ 104 | #define GDB_FR_FPR27 ((GDB_FR_FPR26) + 4) /* 65 */ 105 | #define GDB_FR_FPR28 ((GDB_FR_FPR27) + 4) /* 66 */ 106 | #define GDB_FR_FPR29 ((GDB_FR_FPR28) + 4) /* 67 */ 107 | #define GDB_FR_FPR30 ((GDB_FR_FPR29) + 4) /* 68 */ 108 | #define GDB_FR_FPR31 ((GDB_FR_FPR30) + 4) /* 69 */ 109 | 110 | #define GDB_FR_FSR ((GDB_FR_FPR31) + 4) /* 70 */ 111 | #define GDB_FR_FIR ((GDB_FR_FSR) + 4) /* 71 */ 112 | 113 | #define GDB_FR_FRP ((GDB_FR_FIR) + 4) /* 72 */ 114 | #define GDB_FR_DUMMY ((GDB_FR_FRP) + 4) /* 73, unused ??? */ 115 | 116 | /* 117 | * Again, CP0 registers 118 | */ 119 | #define GDB_FR_CP0_INDEX ((GDB_FR_DUMMY) + 4) /* 74 */ 120 | #define GDB_FR_CP0_RANDOM ((GDB_FR_CP0_INDEX) + 4) /* 75 */ 121 | #define GDB_FR_CP0_ENTRYLO0 ((GDB_FR_CP0_RANDOM) + 4) /* 76 */ 122 | #define GDB_FR_CP0_ENTRYLO1 ((GDB_FR_CP0_ENTRYLO0) + 4) /* 77 */ 123 | #define GDB_FR_CP0_CONTEXT ((GDB_FR_CP0_ENTRYLO1) + 4) /* 78 */ 124 | #define GDB_FR_CP0_PAGEMASK ((GDB_FR_CP0_CONTEXT) + 4) /* 79 */ 125 | #define GDB_FR_CP0_WIRED ((GDB_FR_CP0_PAGEMASK) + 4) /* 80 */ 126 | #define GDB_FR_CP0_REG7 ((GDB_FR_CP0_WIRED) + 4) /* 81 */ 127 | #define GDB_FR_CP0_REG8 ((GDB_FR_CP0_REG7) + 4) /* 82 */ 128 | #define GDB_FR_CP0_REG9 ((GDB_FR_CP0_REG8) + 4) /* 83 */ 129 | #define GDB_FR_CP0_ENTRYHI ((GDB_FR_CP0_REG9) + 4) /* 84 */ 130 | #define GDB_FR_CP0_REG11 ((GDB_FR_CP0_ENTRYHI) + 4) /* 85 */ 131 | #define GDB_FR_CP0_REG12 ((GDB_FR_CP0_REG11) + 4) /* 86 */ 132 | #define GDB_FR_CP0_REG13 ((GDB_FR_CP0_REG12) + 4) /* 87 */ 133 | #define GDB_FR_CP0_REG14 ((GDB_FR_CP0_REG13) + 4) /* 88 */ 134 | #define GDB_FR_CP0_PRID ((GDB_FR_CP0_REG14) + 4) /* 89 */ 135 | 136 | /* 137 | * Ps2 registers. 138 | */ 139 | #define GDB_FR_CP1_ACC ((GDB_FR_CP0_PRID) + 4) /* 90 */ 140 | #define GDB_FR_SHFT_AMNT ((GDB_FR_CP1_ACC) + 4) /* 91 */ 141 | #define GDB_FR_LO1 ((GDB_FR_SHFT_AMNT) + 4) /* 92 */ 142 | #define GDB_FR_HI1 ((GDB_FR_LO1) + 4) /* 93 */ 143 | #define GDB_FR_CP0_DEPC ((GDB_FR_HI1) + 4) /* 94 */ 144 | #define GDB_FR_CP0_PERFCNT ((GDB_FR_CP0_DEPC) + 4) /* 95 */ 145 | 146 | // #define GDB_FR_SIZE ((((GDB_FR_CP0_PERFCNT) + 4) + (PTRSIZE - 1)) & ~(PTRSIZE - 1)) 147 | // With alignment. 148 | #define GDB_FR_SIZE ((((GDB_FR_CP0_PERFCNT) + 12) + (PTRSIZE - 1)) & ~(PTRSIZE - 1)) 149 | 150 | #ifndef __ASSEMBLY__ 151 | 152 | /* 153 | * This is the same as above, but for the high-level 154 | * part of the GDB stub. 155 | */ 156 | 157 | typedef struct _gdb_regs_ps2 158 | { 159 | /* 160 | * Pad bytes for argument save space on the stack 161 | * 20/40/80 Bytes for 32/64/128 bit code 162 | */ 163 | unsigned int pad0 __attribute__((mode(TI))); 164 | unsigned int pad1 __attribute__((mode(TI))); 165 | unsigned int pad2 __attribute__((mode(TI))); 166 | unsigned int pad3 __attribute__((mode(TI))); 167 | unsigned int pad4 __attribute__((mode(TI))); 168 | 169 | /* 170 | * saved main processor registers 171 | */ 172 | unsigned int reg0 __attribute__((mode(TI))); 173 | unsigned int reg1 __attribute__((mode(TI))); 174 | unsigned int reg2 __attribute__((mode(TI))); 175 | unsigned int reg3 __attribute__((mode(TI))); 176 | unsigned int reg4 __attribute__((mode(TI))); 177 | unsigned int reg5 __attribute__((mode(TI))); 178 | unsigned int reg6 __attribute__((mode(TI))); 179 | unsigned int reg7 __attribute__((mode(TI))); 180 | unsigned int reg8 __attribute__((mode(TI))); 181 | unsigned int reg9 __attribute__((mode(TI))); 182 | unsigned int reg10 __attribute__((mode(TI))); 183 | unsigned int reg11 __attribute__((mode(TI))); 184 | unsigned int reg12 __attribute__((mode(TI))); 185 | unsigned int reg13 __attribute__((mode(TI))); 186 | unsigned int reg14 __attribute__((mode(TI))); 187 | unsigned int reg15 __attribute__((mode(TI))); 188 | unsigned int reg16 __attribute__((mode(TI))); 189 | unsigned int reg17 __attribute__((mode(TI))); 190 | unsigned int reg18 __attribute__((mode(TI))); 191 | unsigned int reg19 __attribute__((mode(TI))); 192 | unsigned int reg20 __attribute__((mode(TI))); 193 | unsigned int reg21 __attribute__((mode(TI))); 194 | unsigned int reg22 __attribute__((mode(TI))); 195 | unsigned int reg23 __attribute__((mode(TI))); 196 | unsigned int reg24 __attribute__((mode(TI))); 197 | unsigned int reg25 __attribute__((mode(TI))); 198 | unsigned int reg26 __attribute__((mode(TI))); 199 | unsigned int reg27 __attribute__((mode(TI))); 200 | unsigned int reg28 __attribute__((mode(TI))); 201 | unsigned int reg29 __attribute__((mode(TI))); 202 | unsigned int reg30 __attribute__((mode(TI))); 203 | unsigned int reg31 __attribute__((mode(TI))); // 32 204 | 205 | /* 206 | * Saved special registers - note, the ordering is different for ps2 against vanilla, this is because lo and hi are 128 bit 207 | * and in order to keep alignment, I've re-ordered them to be before cp0_status, whilst the pc side expects them to be below. 208 | * Note that in struct gdb_regs, the order is as expected. 209 | */ 210 | unsigned int lo __attribute__((mode(TI))); 211 | unsigned int hi __attribute__((mode(TI))); 212 | int cp0_status; 213 | int cp0_badvaddr; 214 | int cp0_cause; 215 | int cp0_epc; // 6 216 | 217 | /* 218 | * Saved floating point registers 219 | */ 220 | int fpr0, fpr1, fpr2, fpr3, fpr4, fpr5, fpr6, fpr7; 221 | int fpr8, fpr9, fpr10, fpr11, fpr12, fpr13, fpr14, fpr15; 222 | int fpr16, fpr17, fpr18, fpr19, fpr20, fpr21, fpr22, fpr23; 223 | int fpr24, fpr25, fpr26, fpr27, fpr28, fpr29, fpr30, fpr31; // 32 224 | 225 | int cp1_fsr; 226 | int cp1_fir; // 2 227 | 228 | /* 229 | * Frame pointer 230 | */ 231 | int frame_ptr; // Eh? Isn't the frame pointer just reg30? (also called s8) 232 | int dummy; /* unused */ // 2 233 | 234 | /* 235 | * saved cp0 registers -> but not all are saved? 236 | */ 237 | int cp0_index; 238 | int cp0_random; 239 | int cp0_entrylo0; 240 | int cp0_entrylo1; 241 | int cp0_context; 242 | int cp0_pagemask; 243 | int cp0_wired; 244 | int cp0_reg7; // NOT ACTUALLY SAVED... info 245 | int cp0_reg8; // NOT ACTUALLY SAVED... badvaddr 246 | int cp0_reg9; // NOT ACTUALLY SAVED... count 247 | int cp0_entryhi; 248 | int cp0_reg11; // NOT ACTUALLY SAVED... compare 249 | int cp0_reg12; // NOT ACTUALLY SAVED... status 250 | int cp0_reg13; // NOT ACTUALLY SAVED... cause 251 | int cp0_reg14; // NOT ACTUALLY SAVED... epc 252 | int cp0_prid; // 16 253 | 254 | /* 255 | * Ps2 specific registers - I've put these all at the end so the above is as similar as possible to vanilla mips. 256 | */ 257 | int cp1_acc; 258 | int shft_amnt; 259 | int lo1; 260 | int hi1; 261 | int cp0_depc; 262 | int cp0_perfcnt; // 6 263 | } gdb_regs_ps2; 264 | 265 | // All this because the compiler won't allow any 128 bit arithmetic. 266 | struct gdb_regs 267 | { 268 | /* 269 | * Pad bytes for argument save space on the stack 270 | * 20/40/80 Bytes for 32/64/128 bit code 271 | */ 272 | unsigned int pad0; 273 | unsigned int pad1; 274 | unsigned int pad2; 275 | unsigned int pad3; 276 | unsigned int pad4; 277 | 278 | /* 279 | * saved main processor registers 280 | */ 281 | unsigned int reg0; 282 | unsigned int reg1; 283 | unsigned int reg2; 284 | unsigned int reg3; 285 | unsigned int reg4; 286 | unsigned int reg5; 287 | unsigned int reg6; 288 | unsigned int reg7; 289 | unsigned int reg8; 290 | unsigned int reg9; 291 | unsigned int reg10; 292 | unsigned int reg11; 293 | unsigned int reg12; 294 | unsigned int reg13; 295 | unsigned int reg14; 296 | unsigned int reg15; 297 | unsigned int reg16; 298 | unsigned int reg17; 299 | unsigned int reg18; 300 | unsigned int reg19; 301 | unsigned int reg20; 302 | unsigned int reg21; 303 | unsigned int reg22; 304 | unsigned int reg23; 305 | unsigned int reg24; 306 | unsigned int reg25; 307 | unsigned int reg26; 308 | unsigned int reg27; 309 | unsigned int reg28; // gp 310 | unsigned int reg29; // sp 311 | unsigned int reg30; // fp 312 | unsigned int reg31; // ra // 32 313 | 314 | /* 315 | * Saved special registers 316 | */ 317 | unsigned int cp0_status; 318 | unsigned int lo; 319 | unsigned int hi; 320 | unsigned int cp0_badvaddr; 321 | unsigned int cp0_cause; 322 | unsigned int cp0_epc; // 6 323 | 324 | /* 325 | * Saved floating point registers 326 | */ 327 | int fpr0, fpr1, fpr2, fpr3, fpr4, fpr5, fpr6, fpr7; 328 | int fpr8, fpr9, fpr10, fpr11, fpr12, fpr13, fpr14, fpr15; 329 | int fpr16, fpr17, fpr18, fpr19, fpr20, fpr21, fpr22, fpr23; 330 | int fpr24, fpr25, fpr26, fpr27, fpr28, fpr29, fpr30, fpr31; // 32 331 | 332 | int cp1_fsr; 333 | int cp1_fir; // 2 334 | 335 | /* 336 | * Frame pointer 337 | */ 338 | int frame_ptr; // Eh? Isn't the frame pointer just a general purpose register (i.e. one of reg0...reg31???) 339 | int dummy; /* unused */ // 2 340 | 341 | /* 342 | * saved cp0 registers -> but not all are saved? 343 | */ 344 | int cp0_index; 345 | int cp0_random; 346 | int cp0_entrylo0; 347 | int cp0_entrylo1; 348 | int cp0_context; 349 | int cp0_pagemask; 350 | int cp0_wired; 351 | int cp0_reg7; // NOT ACTUALLY SAVED... info 352 | int cp0_reg8; // NOT ACTUALLY SAVED... badvaddr 353 | int cp0_reg9; // NOT ACTUALLY SAVED... count 354 | int cp0_entryhi; 355 | int cp0_reg11; // NOT ACTUALLY SAVED... compare 356 | int cp0_reg12; // NOT ACTUALLY SAVED... status 357 | int cp0_reg13; // NOT ACTUALLY SAVED... cause 358 | int cp0_reg14; // NOT ACTUALLY SAVED... epc 359 | int cp0_prid; // 16 360 | 361 | /* 362 | * Ps2 specific registers - I've put these all at the end so the above is as similar as possible to vanilla mips. 363 | */ 364 | int cp1_acc; 365 | int shft_amnt; 366 | int lo1; 367 | int hi1; 368 | int cp0_depc; 369 | int cp0_perfcnt; // 6 370 | }; 371 | 372 | #define SIGHUP 1 // Hangup (POSIX). 373 | #define SIGINT 2 // Interrupt (ANSI). 374 | #define SIGQUIT 3 // Quit (POSIX). 375 | #define SIGILL 4 // Illegal instruction (ANSI). 376 | #define SIGTRAP 5 // Trace trap (POSIX). 377 | #define SIGIOT 6 // IOT trap (4.2 BSD). 378 | #define SIGABRT SIGIOT // Abort (ANSI). 379 | #define SIGEMT 7 380 | #define SIGFPE 8 // Floating-point exception (ANSI). 381 | #define SIGKILL 9 // Kill, unblockable (POSIX). 382 | #define SIGBUS 10 // BUS error (4.2 BSD). 383 | #define SIGSEGV 11 // Segmentation violation (ANSI). 384 | #define SIGSYS 12 385 | #define SIGPIPE 13 // Broken pipe (POSIX). 386 | #define SIGALRM 14 // Alarm clock (POSIX). 387 | #define SIGTERM 15 // Termination (ANSI). 388 | #define SIGUSR1 16 // User-defined signal 1 (POSIX). 389 | #define SIGUSR2 17 // User-defined signal 2 (POSIX). 390 | #define SIGCHLD 18 // Child status has changed (POSIX). 391 | #define SIGCLD SIGCHLD // Same as SIGCHLD (System V). 392 | #define SIGPWR 19 // Power failure restart (System V). 393 | #define SIGWINCH 20 // Window size change (4.3 BSD, Sun). 394 | #define SIGURG 21 // Urgent condition on socket (4.2 BSD). 395 | #define SIGIO 22 // I/O now possible (4.2 BSD). 396 | #define SIGPOLL SIGIO // Pollable event occurred (System V). 397 | #define SIGSTOP 23 // Stop, unblockable (POSIX). 398 | #define SIGTSTP 24 // Keyboard stop (POSIX). 399 | #define SIGCONT 25 // Continue (POSIX). 400 | #define SIGTTIN 26 // Background read from tty (POSIX). 401 | #define SIGTTOU 27 // Background write to tty (POSIX). 402 | #define SIGVTALRM 28 // Virtual alarm clock (4.2 BSD). 403 | #define SIGPROF 29 // Profiling alarm clock (4.2 BSD). 404 | #define SIGXCPU 30 // CPU limit exceeded (4.2 BSD). 405 | #define SIGXFSZ 31 // File size limit exceeded (4.2 BSD). 406 | 407 | // These should not be considered constants from userland. 408 | #define SIGRTMIN 32 409 | #define SIGRTMAX (_NSIG - 1) 410 | 411 | 412 | // Status register bits available in all MIPS CPUs. 413 | #define ST0_IM 0x0000ff00 414 | #define STATUSB_IP0 8 415 | #define STATUSF_IP0 (1 << 8) 416 | #define STATUSB_IP1 9 417 | #define STATUSF_IP1 (1 << 9) 418 | #define STATUSB_IP2 10 419 | #define STATUSF_IP2 (1 << 10) 420 | #define STATUSB_IP3 11 421 | #define STATUSF_IP3 (1 << 11) 422 | #define STATUSB_IP4 12 423 | #define STATUSF_IP4 (1 << 12) 424 | #define STATUSB_IP5 13 425 | #define STATUSF_IP5 (1 << 13) 426 | #define STATUSB_IP6 14 427 | #define STATUSF_IP6 (1 << 14) 428 | #define STATUSB_IP7 15 429 | #define STATUSF_IP7 (1 << 15) 430 | #define ST0_DE 0x00010000 431 | #define ST0_CE 0x00020000 432 | #define ST0_CH 0x00040000 433 | #define ST0_SR 0x00100000 434 | #define ST0_BEV 0x00400000 435 | #define ST0_RE 0x02000000 436 | #define ST0_FR 0x04000000 437 | #define ST0_CU 0xf0000000 438 | #define ST0_CU0 0x10000000 439 | #define ST0_CU1 0x20000000 440 | #define ST0_CU2 0x40000000 441 | #define ST0_CU3 0x80000000 442 | #define ST0_XX 0x80000000 /* MIPS IV naming */ 443 | 444 | 445 | // Bitfields and bit numbers in the coprocessor 0 cause register. 446 | // Refer to to your MIPS R4xx0 manual, chapter 5 for explanation. 447 | #define CAUSEB_EXCCODE 2 448 | #define CAUSEF_EXCCODE (31 << 2) 449 | #define CAUSEB_IP 8 450 | #define CAUSEF_IP (255 << 8) 451 | #define CAUSEB_IP0 8 452 | #define CAUSEF_IP0 (1 << 8) 453 | #define CAUSEB_IP1 9 454 | #define CAUSEF_IP1 (1 << 9) 455 | #define CAUSEB_IP2 10 456 | #define CAUSEF_IP2 (1 << 10) 457 | #define CAUSEB_IP3 11 458 | #define CAUSEF_IP3 (1 << 11) 459 | #define CAUSEB_IP4 12 460 | #define CAUSEF_IP4 (1 << 12) 461 | #define CAUSEB_IP5 13 462 | #define CAUSEF_IP5 (1 << 13) 463 | #define CAUSEB_IP6 14 464 | #define CAUSEF_IP6 (1 << 14) 465 | #define CAUSEB_IP7 15 466 | #define CAUSEF_IP7 (1 << 15) 467 | #define CAUSEB_IV 23 468 | #define CAUSEF_IV (1 << 23) 469 | #define CAUSEB_CE 28 470 | #define CAUSEF_CE (3 << 28) 471 | #define CAUSEB_BD 31 472 | #define CAUSEF_BD (1 << 31) 473 | 474 | #endif /* !__ASSEMBLY__ */ 475 | #endif /* __ASM_MIPS_GDB_STUB_H */ 476 | -------------------------------------------------------------------------------- /ee/inst.h: -------------------------------------------------------------------------------- 1 | /* 2 | _____ ___ ____ 3 | ____| | ____| PSX2 OpenSource Project 4 | | ___| |____ (C)2003, Ray Donnelly ( rdonnelly@polygoons.com ) 5 | -------------------------------------------------------------------------- 6 | gdb-stub.h PS2 REMOTE GDB STUB USING TCP 7 | */ 8 | 9 | #ifndef ASM_MIPS_INST_H 10 | #define ASM_MIPS_INST_H 11 | 12 | // Major opcodes. Before MIPS IV cop1x was called cop3. 13 | // clang-format off 14 | enum major_op { 15 | spec_op, bcond_op, j_op, jal_op, 16 | beq_op, bne_op, blez_op, bgtz_op, 17 | addi_op, addiu_op, slti_op, sltiu_op, 18 | andi_op, ori_op, xori_op, lui_op, 19 | cop0_op, cop1_op, cop2_op, cop1x_op, 20 | beql_op, bnel_op, blezl_op, bgtzl_op, 21 | daddi_op, daddiu_op, ldl_op, ldr_op, 22 | major_1c_op, major_1d_op, major_1e_op, major_1f_op, 23 | lb_op, lh_op, lwl_op, lw_op, 24 | lbu_op, lhu_op, lwr_op, lwu_op, 25 | sb_op, sh_op, swl_op, sw_op, 26 | sdl_op, sdr_op, swr_op, cache_op, 27 | ll_op, lwc1_op, lwc2_op, pref_op, 28 | lld_op, ldc1_op, ldc2_op, ld_op, 29 | sc_op, swc1_op, swc2_op, major_3b_op, /* Opcode 0x3b is unused */ 30 | scd_op, sdc1_op, sdc2_op, sd_op 31 | }; 32 | 33 | 34 | // func field of spec opcode. 35 | enum spec_op { 36 | sll_op, movc_op, srl_op, sra_op, 37 | sllv_op, srlv_op, srav_op, spec1_unused_op, /* Opcode 0x07 is unused */ 38 | jr_op, jalr_op, movz_op, movn_op, 39 | syscall_op, break_op, spim_op, sync_op, 40 | mfhi_op, mthi_op, mflo_op, mtlo_op, 41 | dsllv_op, spec2_unused_op, dsrlv_op, dsrav_op, 42 | mult_op, multu_op, div_op, divu_op, 43 | dmult_op, dmultu_op, ddiv_op, ddivu_op, 44 | add_op, addu_op, sub_op, subu_op, 45 | and_op, or_op, xor_op, nor_op, 46 | spec3_unused_op, spec4_unused_op, slt_op, sltu_op, 47 | dadd_op, daddu_op, dsub_op, dsubu_op, 48 | tge_op, tgeu_op, tlt_op, tltu_op, 49 | teq_op, spec5_unused_op, tne_op, spec6_unused_op, 50 | dsll_op, spec7_unused_op, dsrl_op, dsra_op, 51 | dsll32_op, spec8_unused_op, dsrl32_op, dsra32_op 52 | }; 53 | 54 | 55 | // rt field of bcond opcodes. 56 | enum rt_op { 57 | bltz_op, bgez_op, bltzl_op, bgezl_op, 58 | spimi_op, unused_rt_op_0x05, unused_rt_op_0x06, unused_rt_op_0x07, 59 | tgei_op, tgeiu_op, tlti_op, tltiu_op, 60 | teqi_op, unused_0x0d_rt_op, tnei_op, unused_0x0f_rt_op, 61 | bltzal_op, bgezal_op, bltzall_op, bgezall_op 62 | /* 63 | * The others (0x14 - 0x1f) are unused. 64 | */ 65 | }; 66 | 67 | 68 | // rs field of cop opcodes. 69 | enum cop_op { 70 | mfc_op = 0x00, dmfc_op = 0x01, 71 | cfc_op = 0x02, mtc_op = 0x04, 72 | dmtc_op = 0x05, ctc_op = 0x06, 73 | bc_op = 0x08, cop_op = 0x10, 74 | copm_op = 0x18 75 | }; 76 | 77 | 78 | // func field of cop0 coi opcodes. 79 | enum cop0_coi_func { 80 | tlbr_op = 0x01, tlbwi_op = 0x02, 81 | tlbwr_op = 0x06, tlbp_op = 0x08, 82 | rfe_op = 0x10, eret_op = 0x18 83 | }; 84 | 85 | 86 | // func field of cop0 com opcodes. 87 | enum cop0_com_func { 88 | tlbr1_op = 0x01, tlbw_op = 0x02, 89 | tlbp1_op = 0x08, dctr_op = 0x09, 90 | dctw_op = 0x0a 91 | }; 92 | 93 | 94 | // fmt field of cop1 opcodes. 95 | enum cop1_fmt { 96 | s_fmt, d_fmt, e_fmt, q_fmt, 97 | w_fmt, l_fmt 98 | }; 99 | 100 | 101 | // func field of cop1 instructions using d, s or w format. 102 | enum cop1_sdw_func { 103 | fadd_op = 0x00, fsub_op = 0x01, 104 | fmul_op = 0x02, fdiv_op = 0x03, 105 | fsqrt_op = 0x04, fabs_op = 0x05, 106 | fmov_op = 0x06, fneg_op = 0x07, 107 | froundl_op = 0x08, ftruncl_op = 0x09, 108 | fceill_op = 0x0a, ffloorl_op = 0x0b, 109 | fround_op = 0x0c, ftrunc_op = 0x0d, 110 | fceil_op = 0x0e, ffloor_op = 0x0f, 111 | fmovc_op = 0x11, fmovz_op = 0x12, 112 | fmovn_op = 0x13, frecip_op = 0x15, 113 | frsqrt_op = 0x16, fcvts_op = 0x20, 114 | fcvtd_op = 0x21, fcvte_op = 0x22, 115 | fcvtw_op = 0x24, fcvtl_op = 0x25, 116 | fcmp_op = 0x30 117 | }; 118 | 119 | 120 | // func field of cop1x opcodes (MIPS IV). 121 | enum cop1x_func { 122 | lwxc1_op = 0x00, ldxc1_op = 0x01, 123 | pfetch_op = 0x07, swxc1_op = 0x08, 124 | sdxc1_op = 0x09, madd_s_op = 0x20, 125 | madd_d_op = 0x21, madd_e_op = 0x22, 126 | msub_s_op = 0x28, msub_d_op = 0x29, 127 | msub_e_op = 0x2a, nmadd_s_op = 0x30, 128 | nmadd_d_op = 0x31, nmadd_e_op = 0x32, 129 | nmsub_s_op = 0x38, nmsub_d_op = 0x39, 130 | nmsub_e_op = 0x3a 131 | }; 132 | 133 | 134 | // func field for mad opcodes (MIPS IV). 135 | enum mad_func { 136 | madd_op = 0x08, msub_op = 0x0a, 137 | nmadd_op = 0x0c, nmsub_op = 0x0e 138 | }; 139 | // clang-format on 140 | 141 | #ifdef __MIPSEB__ 142 | struct j_format 143 | { /* Jump format */ 144 | unsigned int opcode : 6; 145 | unsigned int target : 26; 146 | }; 147 | 148 | struct i_format 149 | { /* Immediate format (addi, lw, ...) */ 150 | unsigned int opcode : 6; 151 | unsigned int rs : 5; 152 | unsigned int rt : 5; 153 | signed int simmediate : 16; 154 | }; 155 | 156 | struct u_format 157 | { /* Unsigned immediate format (ori, xori, ...) */ 158 | unsigned int opcode : 6; 159 | unsigned int rs : 5; 160 | unsigned int rt : 5; 161 | unsigned int uimmediate : 16; 162 | }; 163 | 164 | struct c_format 165 | { /* Cache (>= R6000) format */ 166 | unsigned int opcode : 6; 167 | unsigned int rs : 5; 168 | unsigned int c_op : 3; 169 | unsigned int cache : 2; 170 | unsigned int simmediate : 16; 171 | }; 172 | 173 | struct r_format 174 | { /* Register format */ 175 | unsigned int opcode : 6; 176 | unsigned int rs : 5; 177 | unsigned int rt : 5; 178 | unsigned int rd : 5; 179 | unsigned int re : 5; 180 | unsigned int func : 6; 181 | }; 182 | 183 | struct p_format 184 | { /* Performance counter format (R10000) */ 185 | unsigned int opcode : 6; 186 | unsigned int rs : 5; 187 | unsigned int rt : 5; 188 | unsigned int rd : 5; 189 | unsigned int re : 5; 190 | unsigned int func : 6; 191 | }; 192 | 193 | struct f_format 194 | { /* FPU register format */ 195 | unsigned int opcode : 6; 196 | unsigned int : 1; 197 | unsigned int fmt : 4; 198 | unsigned int rt : 5; 199 | unsigned int rd : 5; 200 | unsigned int re : 5; 201 | unsigned int func : 6; 202 | }; 203 | 204 | struct ma_format 205 | { /* FPU multipy and add format (MIPS IV) */ 206 | unsigned int opcode : 6; 207 | unsigned int fr : 5; 208 | unsigned int ft : 5; 209 | unsigned int fs : 5; 210 | unsigned int fd : 5; 211 | unsigned int func : 4; 212 | unsigned int fmt : 2; 213 | }; 214 | 215 | #elif defined(__MIPSEL__) 216 | 217 | struct j_format 218 | { /* Jump format */ 219 | unsigned int target : 26; 220 | unsigned int opcode : 6; 221 | }; 222 | 223 | struct i_format 224 | { /* Immediate format */ 225 | signed int simmediate : 16; 226 | unsigned int rt : 5; 227 | unsigned int rs : 5; 228 | unsigned int opcode : 6; 229 | }; 230 | 231 | struct u_format 232 | { /* Unsigned immediate format */ 233 | unsigned int uimmediate : 16; 234 | unsigned int rt : 5; 235 | unsigned int rs : 5; 236 | unsigned int opcode : 6; 237 | }; 238 | 239 | struct c_format 240 | { /* Cache (>= R6000) format */ 241 | unsigned int simmediate : 16; 242 | unsigned int cache : 2; 243 | unsigned int c_op : 3; 244 | unsigned int rs : 5; 245 | unsigned int opcode : 6; 246 | }; 247 | 248 | struct r_format 249 | { /* Register format */ 250 | unsigned int func : 6; 251 | unsigned int re : 5; 252 | unsigned int rd : 5; 253 | unsigned int rt : 5; 254 | unsigned int rs : 5; 255 | unsigned int opcode : 6; 256 | }; 257 | 258 | struct p_format 259 | { /* Performance counter format (R10000) */ 260 | unsigned int func : 6; 261 | unsigned int re : 5; 262 | unsigned int rd : 5; 263 | unsigned int rt : 5; 264 | unsigned int rs : 5; 265 | unsigned int opcode : 6; 266 | }; 267 | 268 | struct f_format 269 | { /* FPU register format */ 270 | unsigned int func : 6; 271 | unsigned int re : 5; 272 | unsigned int rd : 5; 273 | unsigned int rt : 5; 274 | unsigned int fmt : 4; 275 | unsigned int : 1; 276 | unsigned int opcode : 6; 277 | }; 278 | 279 | struct ma_format 280 | { /* FPU multipy and add format (MIPS IV) */ 281 | unsigned int fmt : 2; 282 | unsigned int func : 4; 283 | unsigned int fd : 5; 284 | unsigned int fs : 5; 285 | unsigned int ft : 5; 286 | unsigned int fr : 5; 287 | unsigned int opcode : 6; 288 | }; 289 | 290 | #else /* !defined (__MIPSEB__) && !defined (__MIPSEL__) */ 291 | #error "MIPS but neither __MIPSEL__ nor __MIPSEB__?" 292 | #endif 293 | 294 | union mips_instruction 295 | { 296 | unsigned int word; 297 | unsigned short halfword[2]; 298 | unsigned char byte[4]; 299 | struct j_format j_format; 300 | struct i_format i_format; 301 | struct u_format u_format; 302 | struct c_format c_format; 303 | struct r_format r_format; 304 | struct f_format f_format; 305 | struct ma_format ma_format; 306 | }; 307 | 308 | #endif // ASM_MIPS_INST_H 309 | -------------------------------------------------------------------------------- /ee/ps2gdbStub.c: -------------------------------------------------------------------------------- 1 | /* 2 | _____ ___ ____ 3 | ____| | ____| PSX2 OpenSource Project 4 | | ___| |____ (C)2003, Ray Donnelly ( rdonnelly@polygoons.com ) 5 | -------------------------------------------------------------------------- 6 | ps2gdbStub.c PS2 REMOTE GDB STUB USING TCP 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "gdb-stub.h" 18 | #include "inst.h" 19 | 20 | // This project no longer contains a main function. Instead, link it into your own project and call gdb_stub_main from your own 21 | // main function. 22 | 23 | // Unless you edit your gcc specs file, and change it from:- 24 | // *subtarget_cc1_spec: 25 | // ...to... 26 | // *subtarget_cc1_spec: 27 | // -fno-omit-frame-pointer 28 | // ...then you'll need to comment this out. Also, you won't get stack back tracing working correctly either! 29 | #define COMPILER_USES_30_AS_FP 30 | 31 | // A few options until I've figured out which works best. 32 | // At present, I use jal to get to handle_exception, so a normal c-style return is used to get back. 33 | #define return_return() return 34 | 35 | #define return_handle_exception return_return 36 | 37 | // #define DEBUG 38 | 39 | #define DEBUG_NONE 0 40 | #define DEBUG_READS (1 << 0) 41 | #define DEBUG_WRITES (1 << 1) 42 | #define DEBUG_SINGLESTEP (1 << 2) 43 | #define DEBUG_PRINTREGS (1 << 3) 44 | #define DEBUG_COMMS (1 << 4) 45 | #define DEBUG_COMMSINIT (1 << 5) 46 | #define DEBUG_OTHERS (1 << 6) 47 | #define DEBUG_EVERYTHING DEBUG_READS | DEBUG_WRITES | DEBUG_SINGLESTEP | DEBUG_PRINTREGS | DEBUG_COMMS | DEBUG_COMMSINIT | DEBUG_OTHERS 48 | #define DEBUG_DODGYSTUFF DEBUG_READS | DEBUG_WRITES | DEBUG_SINGLESTEP | DEBUG_PRINTREGS | DEBUG_COMMS | DEBUG_OTHERS 49 | #define DEBUG_NOTHING 0 50 | #define DEBUG_MINIMAL DEBUG_PRINTREGS | DEBUG_SINGLESTEP | DEBUG_WRITES | DEBUG_READS 51 | 52 | #define DEBUG_PRINTREGS_SCREEN 0 53 | #define DEBUG_PRINTREGS_PRINTF 1 54 | 55 | #ifdef DEBUG 56 | int debug_level_g = DEBUG_EVERYTHING; 57 | #else 58 | int debug_level_g = DEBUG_NONE; 59 | #endif 60 | 61 | // Comment this in if you want address errors etc (the usual ps2sdk suspects) to run through my handler. Some code I refered to 62 | // was setting our exception handler for most types of trap. I don't know why! 63 | // #define TRAP_ALL_EXCEPTIONS 64 | #define GDB_PORT 12 65 | #define BP_OPC 0x0000000d 66 | 67 | // Low level support functions. 68 | extern void trap_low(void); // In "gdb-low.S". 69 | extern int putDebugChar(char c); // Write a single character. 70 | extern char getDebugChar(void); // Read a single character. 71 | static char *hex2mem(char *buf, char *mem, int count, int may_fault); 72 | 73 | // Breakpoint function and actual address of break instruction. 74 | extern void breakpoint(void); 75 | extern void breakinst(void); 76 | 77 | static int computeSignal(int tt); 78 | static int hex(unsigned char ch); 79 | static int hexToInt(char **ptr, int *intValue); 80 | static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault); 81 | void handle_exception(gdb_regs_ps2 *regs); 82 | static int gdbstub_net_accept(); 83 | 84 | // These are the gdb buffers. For the tcpip comms, there are seperate buffers, which fill input_buffer and output_buffer when 85 | // needed. 86 | // BUFMAX defines the maximum number of characters in inbound/outbound buffers at least NUMREGBYTES*2 are needed for register 87 | // packets. 88 | #define BUFMAX 2048 89 | static char input_buffer[BUFMAX]; 90 | static char output_buffer[BUFMAX]; 91 | static int gdbstub_initialised_g = 0; 92 | static int gdbstub_num_exceptions_g = 0; 93 | static const char hexchars[] = "0123456789abcdef"; 94 | 95 | 96 | #define SIZE_GDBSTUB_TCP_BUFFER 2048 97 | char gdbstub_recv_buffer_g[SIZE_GDBSTUB_TCP_BUFFER]; 98 | char gdbstub_send_buffer_g[SIZE_GDBSTUB_TCP_BUFFER]; 99 | 100 | #define HOSTPATHIRX "host:" 101 | 102 | // Comms structure for ps2sdk and this to share information. May phase this out if the two get integrated. 103 | typedef struct _gdbstub_comms_data 104 | { 105 | volatile int shutdown_should; 106 | volatile int shutdown_have; 107 | volatile int cmd_thread_id; 108 | volatile int gdb_thread_id; 109 | volatile int user_thread_id; 110 | } gdbstub_comms_data; 111 | 112 | char gdbstub_exception_stack[8 * 1024] __attribute__((aligned(16))); // This may be needed, I don't use it at present... 113 | 114 | gdb_regs_ps2 gdbstub_ps2_regs __attribute__((aligned(16))); 115 | struct gdb_regs gdbstub_regs; 116 | int thread_id_g; 117 | 118 | 119 | static const unsigned char *regName[NUMREGS] = 120 | { 121 | // GPRs (0-31) 122 | "zero", 123 | "at", 124 | "v0", 125 | "v1", 126 | "a0", 127 | "a1", 128 | "a2", 129 | "a3", 130 | "t0", 131 | "t1", 132 | "t2", 133 | "t3", 134 | "t4", 135 | "t5", 136 | "t6", 137 | "t7", 138 | "s0", 139 | "s1", 140 | "s2", 141 | "s3", 142 | "s4", 143 | "s5", 144 | "s6", 145 | "s7", 146 | "t8", 147 | "t9", 148 | "k0", 149 | "k1", 150 | "gp", 151 | "sp", 152 | "fp", 153 | "ra", 154 | 155 | // lo, hi, status, badvaddr, cause, epc. (32-37) 156 | "lo", 157 | "hi", // These are the last two 128 bit registers. 158 | "Stat", 159 | "BVAd", 160 | "Caus", 161 | "EPC", 162 | 163 | // FPRs (38-69) 164 | "fp0", 165 | "fp1", 166 | "fp2", 167 | "fp3", 168 | "fp4", 169 | "fp5", 170 | "fp6", 171 | "fp7", 172 | "fp8", 173 | "fp9", 174 | "fp10", 175 | "fp11", 176 | "fp12", 177 | "fp13", 178 | "fp14", 179 | "fp15", 180 | "fp16", 181 | "fp17", 182 | "fp18", 183 | "fp19", 184 | "fp20", 185 | "fp21", 186 | "fp22", 187 | "fp23", 188 | "fp24", 189 | "fp25", 190 | "fp26", 191 | "fp27", 192 | "fp28", 193 | "fp29", 194 | "fp30", 195 | "fp31", 196 | 197 | // FCR31 and FCR0. (70-71) 198 | "fsr", 199 | "fir", // fsr == fcr31, fir == fcr0 200 | 201 | "frp", 202 | "dummy", // "frp" is frame pointer, don't know what "dummy" is, seems dumb. 203 | 204 | // There's redundancy in these cp0 registers, reg12==status, 13==cause, 14==epc, 8==badvaddr. don't know why the stub does this? 205 | "cp0index", 206 | "cp0random", 207 | "entrylo0", 208 | "entrylo1", 209 | "context", 210 | "pagemask", 211 | "wired", 212 | "cp0reg7", 213 | "cp0reg8", 214 | "cp0reg9", 215 | "entryhi", 216 | "cp0reg11", 217 | "cp0reg12", 218 | "cp0reg13", 219 | "cp0reg14", 220 | "cp0prid", 221 | 222 | // Ps2 Specific saved registers. ACC, sa, hi1, lo1, DEPC (cp0reg24), PrfC (cp0reg25). Not handled on the remote GDB side yet. 223 | "acc", 224 | "sa", 225 | "hi1", 226 | "lo1", 227 | "DEPC", 228 | "PrfC", 229 | }; 230 | 231 | static char *exception_names_g[13] = 232 | { 233 | "Interrupt", "TLB modification", "TLB load/inst fetch", "TLB store", 234 | "Address load/inst fetch", "Address store", "Bus error (instr)", 235 | "Bus error (data)", "Syscall", "Breakpoint", "Reserved instruction", 236 | "Coprocessor unusable", "Arithmetic overflow"}; 237 | 238 | // TODO :: Allow gdb to tell us when to kill the program; instead of this nonsense. It's in the protocol anyway. 239 | volatile gdbstub_comms_data *comms_p_g; 240 | 241 | // Gdb stub socket related global vars. 242 | struct sockaddr_in gdb_local_addr_g; 243 | struct sockaddr_in gdb_remote_addr_g; 244 | fd_set comms_fd_g, temp_comms_fd_g; 245 | int sh_g; 246 | int cs_g = -1; 247 | 248 | void flush_cache_all() 249 | { 250 | FlushCache(0); 251 | FlushCache(2); 252 | } 253 | 254 | 255 | // libc type functions. 256 | // TODO :: Update to ps2sdk and remove these. 257 | int my_atoi(char *txt) 258 | { 259 | int is_neg = 0, val = 0; 260 | 261 | while (*txt == ' ') 262 | txt++; 263 | 264 | if (*txt == '-') 265 | is_neg = 1, txt++; 266 | 267 | while (*txt == ' ' || *txt == '\t') 268 | txt++; 269 | 270 | if (!*txt) 271 | return 0; 272 | 273 | while (*txt && *txt >= '0' && *txt <= '9') { 274 | val = 10 * val + (*txt - '0'); 275 | txt++; 276 | } 277 | 278 | if (is_neg) 279 | val = -val; 280 | 281 | return val; 282 | } 283 | 284 | 285 | void wait_a_while(int time) 286 | { 287 | int i, j; 288 | 289 | for (i = 0; i < 10000000; i++) { 290 | for (j = 0; j < time; j++) { 291 | } 292 | } 293 | } 294 | 295 | 296 | #ifdef DEBUG 297 | int gdbstub_printf(int debug_mask, char *format, ...) 298 | { 299 | va_list args; 300 | int ret; 301 | 302 | if ((debug_mask & debug_level_g) == 0) 303 | return 0; 304 | 305 | vprintf("GDBSTUB :: ", 0); 306 | va_start(args, format); 307 | ret = vprintf(format, args); 308 | va_end(args); 309 | 310 | return ret; 311 | } 312 | #else 313 | int gdbstub_printf(int debug_mask, char *format, ...) 314 | { 315 | return 0; 316 | } 317 | #endif 318 | 319 | int gdbstub_error(char *format, ...) 320 | { 321 | va_list args; 322 | int ret; 323 | 324 | while (1) { 325 | vprintf("GDBSTUBERROR :: ", 0); 326 | va_start(args, format); 327 | ret = vprintf(format, args); 328 | va_end(args); 329 | wait_a_while(1); 330 | } 331 | 332 | return ret; 333 | } 334 | 335 | // Convert ch from a hex digit to an int 336 | static int hex(unsigned char ch) 337 | { 338 | if (ch >= 'a' && ch <= 'f') 339 | return ch - 'a' + 10; 340 | if (ch >= '0' && ch <= '9') 341 | return ch - '0'; 342 | if (ch >= 'A' && ch <= 'F') 343 | return ch - 'A' + 10; 344 | return -1; 345 | } 346 | 347 | // getpacket depends on getDebugChar, but my communications happen in complete packets anyway, so this is a bit 348 | // round the houses, though not particularly slow. 349 | char getDebugChar() 350 | { 351 | static int recvd_chars_processed = 0; 352 | static int recvd_chars = 0; 353 | 354 | if (recvd_chars_processed < recvd_chars) { 355 | return (gdbstub_recv_buffer_g[recvd_chars_processed++]); 356 | } 357 | 358 | // Take it. 359 | recvd_chars = recv(cs_g, gdbstub_recv_buffer_g, SIZE_GDBSTUB_TCP_BUFFER, 0); 360 | recvd_chars_processed = 0; 361 | gdbstub_recv_buffer_g[recvd_chars] = 0; 362 | gdbstub_printf(DEBUG_COMMS, "Recieved %d bytes, of:-\n\t\t%s\n", recvd_chars, gdbstub_recv_buffer_g); 363 | 364 | if (recvd_chars_processed < recvd_chars) { 365 | return (gdbstub_recv_buffer_g[recvd_chars_processed++]); 366 | } 367 | 368 | 369 | gdbstub_printf(DEBUG_COMMS, " Waiting for remote GDB to connect\n\n\n"); 370 | while (gdbstub_net_accept() == -1) { 371 | gdbstub_error("GDB reconnect failed.\n"); 372 | } 373 | 374 | return 0xff; 375 | } 376 | 377 | 378 | // This puts a single char out at a time. But really putpacket batch sends any major stuff. This is only used outside of putpacket 379 | // is for single byte acks or fails (+/-) 380 | int putDebugChar(char c) 381 | { 382 | int sent_size; 383 | char ch[2]; 384 | 385 | ch[0] = c; 386 | ch[1] = 0x0; 387 | 388 | sent_size = send(cs_g, ch, 1, 0); 389 | if (sent_size != 1) { 390 | gdbstub_error("Couldn't send a char %c\n", c); 391 | return 0; 392 | } 393 | 394 | return 1; 395 | } 396 | 397 | // Scan for the sequence $# 398 | // Although this uses getDebugChar, I've wrapped that function up so that it communicates in large packets, so there shouldn't 399 | // be much of a speed issue with getpacket! 400 | static void getpacket(char *buffer) 401 | { 402 | unsigned char checksum; 403 | unsigned char xmitcsum; 404 | int i; 405 | int count; 406 | unsigned char ch; 407 | do { 408 | // Wait for the start character, ignore all other characters. 409 | while ((ch = (getDebugChar() & 0x7f)) != '$') { 410 | __asm__ __volatile__("nop"); 411 | } 412 | 413 | checksum = 0; 414 | xmitcsum = -1; 415 | count = 0; 416 | 417 | // Read until a # or end of buffer is found. 418 | while (count < BUFMAX) { 419 | ch = getDebugChar() & 0x7f; 420 | if (ch == '#') { 421 | break; 422 | } 423 | checksum = checksum + ch; 424 | buffer[count] = ch; 425 | count = count + 1; 426 | } 427 | 428 | if (count >= BUFMAX) 429 | continue; 430 | 431 | buffer[count] = 0; 432 | 433 | if (ch == '#') { 434 | xmitcsum = hex(getDebugChar() & 0x7f) << 4; 435 | xmitcsum |= hex(getDebugChar() & 0x7f); 436 | 437 | if (checksum != xmitcsum) { 438 | putDebugChar('-'); 439 | gdbstub_error("checksum failed\n"); 440 | } else { 441 | putDebugChar('+'); 442 | 443 | // If a sequence char is present, reply with the sequence ID. 444 | if (buffer[2] == ':') { 445 | putDebugChar(buffer[0]); 446 | putDebugChar(buffer[1]); 447 | 448 | // Remove sequence chars from buffer. 449 | count = strlen(buffer); 450 | for (i = 3; i <= count; i++) 451 | buffer[i - 3] = buffer[i]; 452 | } 453 | } 454 | } 455 | } while (checksum != xmitcsum); 456 | } 457 | 458 | // Fast version. Whole packet sent at a time. 459 | static void putpacket(char *buffer) 460 | { 461 | unsigned char checksum; 462 | unsigned char ch; 463 | int count, sent_size; 464 | int n; 465 | int len; 466 | 467 | gdbstub_send_buffer_g[0] = '$'; 468 | checksum = 0; 469 | count = 0; 470 | 471 | gdbstub_printf(DEBUG_COMMS, "putpacket of:-\n\t\t%s, size is %d\n", buffer, strlen(buffer)); 472 | while ((ch = buffer[count]) != 0) { 473 | gdbstub_send_buffer_g[count + 1] = ch; 474 | checksum += ch; 475 | count++; 476 | } 477 | gdbstub_send_buffer_g[count + 1] = '#'; 478 | gdbstub_send_buffer_g[count + 2] = hexchars[checksum >> 4]; 479 | gdbstub_send_buffer_g[count + 3] = hexchars[checksum & 0xf]; 480 | 481 | len = count + 4; 482 | sent_size = n = send(cs_g, gdbstub_send_buffer_g, len, 0); 483 | // Send buffer of ps2ips (1024 Bytes) could be to small when sending all registers: 484 | while (sent_size < len) { 485 | n = send(cs_g, &gdbstub_send_buffer_g[sent_size], len - sent_size, 0); 486 | if (n <= 0) 487 | break; 488 | sent_size += n; 489 | } 490 | while ((getDebugChar() & 0x7f) != '+') 491 | ; // Wait for ack. 492 | } 493 | 494 | // Indicate to caller of mem2hex or hex2mem that there 495 | // has been an error. WHAT'S THIS ABOUT THEN??? 496 | static volatile int mem_err = 0; 497 | 498 | // Convert the memory pointed to by mem into hex, placing result in buf. 499 | // Return a pointer to the last char put in buf (null), in case of mem fault, return 0. 500 | // If MAY_FAULT is non-zero, then we will handle memory faults by returning a 0, 501 | // else treat a fault like any other fault in the stub. 502 | static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault) 503 | { 504 | unsigned char ch; 505 | 506 | // set_mem_fault_trap(may_fault); 507 | 508 | flush_cache_all(); 509 | 510 | gdbstub_printf(DEBUG_READS, "Read mem of %8x\n", mem); 511 | 512 | if ((int)mem < 0xc0000 || (int)mem > 0x2000000) { 513 | gdbstub_printf(DEBUG_READS, " Read faked due to location\n"); 514 | // Prevent crash by pretending it's all zeroes. 515 | while (count-- > 0) { 516 | *buf++ = 0; 517 | } 518 | *buf = 0; 519 | 520 | return buf; 521 | } 522 | 523 | while (count-- > 0) { 524 | ch = *(mem++); 525 | if (mem_err) 526 | return 0; 527 | *buf++ = hexchars[ch >> 4]; 528 | *buf++ = hexchars[ch & 0xf]; 529 | } 530 | 531 | *buf = 0; 532 | 533 | // set_mem_fault_trap(0); 534 | 535 | return buf; 536 | } 537 | 538 | // Writes the binary of the hex array pointed to by into mem. 539 | // Returns a pointer to the byte AFTER the last written. 540 | static char *hex2mem(char *buf, char *mem, int count, int may_fault) 541 | { 542 | int i; 543 | unsigned int old_val; 544 | unsigned char ch; 545 | char *mem2 = mem; 546 | 547 | switch (count) { 548 | case 1: 549 | old_val = *(char *)mem2; 550 | break; 551 | case 2: 552 | old_val = *(short *)mem2; 553 | break; 554 | case 4: 555 | old_val = *(int *)mem2; 556 | break; 557 | default: 558 | old_val = -1; 559 | } 560 | 561 | flush_cache_all(); 562 | // set_mem_fault_trap(may_fault); 563 | 564 | for (i = 0; i < count; i++) { 565 | ch = hex(*buf++) << 4; 566 | ch |= hex(*buf++); 567 | *(mem++) = ch; 568 | if (mem_err) 569 | return 0; 570 | } 571 | 572 | switch (count) { 573 | case 1: 574 | gdbstub_printf(DEBUG_WRITES, "wrote byte:-\n\t\t%2x to [%8x], was %2x\n", *(unsigned char *)mem2, (int)mem2, old_val); 575 | break; 576 | case 2: 577 | gdbstub_printf(DEBUG_WRITES, "wrote short:-\n\t\t%4x to [%8x], was %4x\n", *(unsigned short *)mem2, (int)mem2, old_val); 578 | break; 579 | case 4: 580 | gdbstub_printf(DEBUG_WRITES, "wrote int:-\n\t\t%8x to [%8x], was %8x\n", *(unsigned int *)mem2, (int)mem2, old_val); 581 | break; 582 | default: 583 | gdbstub_printf(DEBUG_WRITES, "wrote to [%8x] bytes:-\n\t\t", (int)mem2); 584 | while (mem2 < mem) { 585 | gdbstub_printf(DEBUG_WRITES, "%2x ", *mem2++); 586 | } 587 | 588 | break; 589 | } 590 | 591 | // set_mem_fault_trap(0); 592 | flush_cache_all(); 593 | 594 | return mem; 595 | } 596 | 597 | 598 | // Single-step using breakpoints. When an exception is handled, we need to restore the instructions hoisted 599 | // when the breakpoints were set. This is where we save the original instructions. 600 | static struct gdb_bp_save 601 | { 602 | unsigned int addr; 603 | unsigned int val; 604 | } step_bp[2]; 605 | 606 | 607 | // Sets breakpoint instructions for single stepping. 608 | static void single_step(struct gdb_regs *regs) 609 | { 610 | union mips_instruction insn; 611 | unsigned int targ; 612 | int is_branch, is_cond, i; 613 | 614 | targ = regs->cp0_epc; 615 | insn.word = *(unsigned int *)targ; 616 | is_branch = is_cond = 0; 617 | 618 | switch (insn.i_format.opcode) { 619 | // jr and jalr are in r_format format. 620 | case spec_op: 621 | switch (insn.r_format.func) { 622 | case jalr_op: 623 | case jr_op: 624 | targ = *(®s->reg0 + insn.r_format.rs); 625 | is_branch = 1; 626 | break; 627 | } 628 | break; 629 | 630 | // Group contains:- 631 | // bltz_op, bgez_op, bltzl_op, bgezl_op, 632 | // bltzal_op, bgezal_op, bltzall_op, bgezall_op. 633 | case bcond_op: 634 | is_branch = is_cond = 1; 635 | targ += 4 + (insn.i_format.simmediate << 2); 636 | break; 637 | 638 | // Unconditional and in j_format. 639 | case jal_op: 640 | case j_op: 641 | is_branch = 1; 642 | targ += 4; 643 | targ >>= 28; 644 | targ <<= 28; 645 | targ |= (insn.j_format.target << 2); 646 | break; 647 | 648 | // Conditional. 649 | case beq_op: 650 | case beql_op: 651 | case bne_op: 652 | case bnel_op: 653 | case blez_op: 654 | case blezl_op: 655 | case bgtz_op: 656 | case bgtzl_op: 657 | case cop0_op: 658 | case cop1_op: 659 | case cop2_op: 660 | case cop1x_op: 661 | is_branch = is_cond = 1; 662 | targ += 4 + (insn.i_format.simmediate << 2); 663 | break; 664 | } 665 | 666 | gdbstub_printf(DEBUG_SINGLESTEP, "Single step, epc [%8x], is_branch %d, is_cond %d, targ is %8x\n", regs->cp0_epc, is_branch, is_cond, targ); 667 | if (is_branch) { 668 | i = 0; 669 | if (is_cond && targ != (regs->cp0_epc + 8)) { 670 | step_bp[i].addr = regs->cp0_epc + 8; 671 | step_bp[i++].val = *(unsigned *)(regs->cp0_epc + 8); 672 | *(unsigned *)(regs->cp0_epc + 8) = BP_OPC; 673 | gdbstub_printf(DEBUG_SINGLESTEP, "hoisted %8x (epc + 8) with BP_OPC\n", regs->cp0_epc + 8); 674 | } 675 | step_bp[i].addr = targ; 676 | step_bp[i].val = *(unsigned *)targ; 677 | *(unsigned *)targ = BP_OPC; 678 | gdbstub_printf(DEBUG_SINGLESTEP, "hoisted %8x (targ) with BP_OPC\n", targ); 679 | } else { 680 | step_bp[0].addr = regs->cp0_epc + 4; 681 | step_bp[0].val = *(unsigned *)(regs->cp0_epc + 4); 682 | *(unsigned *)(regs->cp0_epc + 4) = BP_OPC; 683 | gdbstub_printf(DEBUG_SINGLESTEP, "hoisted %8x (epc + 4) with BP_OPC\n", regs->cp0_epc + 4); 684 | } 685 | } 686 | 687 | 688 | void gdbstub_ps2regs_to_vanilla(gdb_regs_ps2 *ps2_regs, struct gdb_regs *regs) 689 | { 690 | regs->reg0 = *(int *)&ps2_regs->reg0; 691 | regs->reg1 = *(int *)&ps2_regs->reg1; 692 | regs->reg2 = *(int *)&ps2_regs->reg2; 693 | regs->reg3 = *(int *)&ps2_regs->reg3; 694 | regs->reg4 = *(int *)&ps2_regs->reg4; 695 | regs->reg5 = *(int *)&ps2_regs->reg5; 696 | regs->reg6 = *(int *)&ps2_regs->reg6; 697 | regs->reg7 = *(int *)&ps2_regs->reg7; 698 | regs->reg8 = *(int *)&ps2_regs->reg8; 699 | regs->reg9 = *(int *)&ps2_regs->reg9; 700 | regs->reg10 = *(int *)&ps2_regs->reg10; 701 | regs->reg11 = *(int *)&ps2_regs->reg11; 702 | regs->reg12 = *(int *)&ps2_regs->reg12; 703 | regs->reg13 = *(int *)&ps2_regs->reg13; 704 | regs->reg14 = *(int *)&ps2_regs->reg14; 705 | regs->reg15 = *(int *)&ps2_regs->reg15; 706 | regs->reg16 = *(int *)&ps2_regs->reg16; 707 | regs->reg17 = *(int *)&ps2_regs->reg17; 708 | regs->reg18 = *(int *)&ps2_regs->reg18; 709 | regs->reg19 = *(int *)&ps2_regs->reg19; 710 | regs->reg20 = *(int *)&ps2_regs->reg20; 711 | regs->reg21 = *(int *)&ps2_regs->reg21; 712 | regs->reg22 = *(int *)&ps2_regs->reg22; 713 | regs->reg23 = *(int *)&ps2_regs->reg23; 714 | regs->reg24 = *(int *)&ps2_regs->reg24; 715 | regs->reg25 = *(int *)&ps2_regs->reg25; 716 | regs->reg26 = *(int *)&ps2_regs->reg26; 717 | regs->reg27 = *(int *)&ps2_regs->reg27; 718 | regs->reg28 = *(int *)&ps2_regs->reg28; 719 | regs->reg29 = *(int *)&ps2_regs->reg29; 720 | regs->reg30 = *(int *)&ps2_regs->reg30; 721 | regs->reg31 = *(int *)&ps2_regs->reg31; 722 | regs->lo = *(int *)&ps2_regs->lo; 723 | regs->hi = *(int *)&ps2_regs->hi; 724 | regs->cp0_status = ps2_regs->cp0_status; 725 | regs->cp0_badvaddr = ps2_regs->cp0_badvaddr; 726 | regs->cp0_cause = ps2_regs->cp0_cause; 727 | regs->cp0_epc = ps2_regs->cp0_epc; 728 | regs->fpr0 = ps2_regs->fpr0; 729 | regs->fpr1 = ps2_regs->fpr1; 730 | regs->fpr2 = ps2_regs->fpr2; 731 | regs->fpr3 = ps2_regs->fpr3; 732 | regs->fpr4 = ps2_regs->fpr4; 733 | regs->fpr5 = ps2_regs->fpr5; 734 | regs->fpr6 = ps2_regs->fpr6; 735 | regs->fpr7 = ps2_regs->fpr7; 736 | regs->fpr8 = ps2_regs->fpr8; 737 | regs->fpr9 = ps2_regs->fpr9; 738 | regs->fpr10 = ps2_regs->fpr10; 739 | regs->fpr11 = ps2_regs->fpr11; 740 | regs->fpr12 = ps2_regs->fpr12; 741 | regs->fpr13 = ps2_regs->fpr13; 742 | regs->fpr14 = ps2_regs->fpr14; 743 | regs->fpr15 = ps2_regs->fpr15; 744 | regs->fpr16 = ps2_regs->fpr16; 745 | regs->fpr17 = ps2_regs->fpr17; 746 | regs->fpr18 = ps2_regs->fpr18; 747 | regs->fpr19 = ps2_regs->fpr19; 748 | regs->fpr20 = ps2_regs->fpr20; 749 | regs->fpr21 = ps2_regs->fpr21; 750 | regs->fpr22 = ps2_regs->fpr22; 751 | regs->fpr23 = ps2_regs->fpr23; 752 | regs->fpr24 = ps2_regs->fpr24; 753 | regs->fpr25 = ps2_regs->fpr25; 754 | regs->fpr26 = ps2_regs->fpr26; 755 | regs->fpr27 = ps2_regs->fpr27; 756 | regs->fpr28 = ps2_regs->fpr28; 757 | regs->fpr29 = ps2_regs->fpr29; 758 | regs->fpr30 = ps2_regs->fpr30; 759 | regs->fpr31 = ps2_regs->fpr31; 760 | regs->cp1_fsr = ps2_regs->cp1_fsr; 761 | regs->cp1_fir = ps2_regs->cp1_fir; 762 | regs->frame_ptr = ps2_regs->frame_ptr; 763 | regs->dummy = ps2_regs->dummy; 764 | regs->cp0_index = ps2_regs->cp0_index; 765 | regs->cp0_random = ps2_regs->cp0_random; 766 | regs->cp0_entrylo0 = ps2_regs->cp0_entrylo0; 767 | regs->cp0_entrylo1 = ps2_regs->cp0_entrylo1; 768 | regs->cp0_context = ps2_regs->cp0_context; 769 | regs->cp0_pagemask = ps2_regs->cp0_pagemask; 770 | regs->cp0_wired = ps2_regs->cp0_wired; 771 | regs->cp0_reg7 = ps2_regs->cp0_reg7; 772 | regs->cp0_reg8 = ps2_regs->cp0_reg8; 773 | regs->cp0_reg9 = ps2_regs->cp0_reg9; 774 | regs->cp0_entryhi = ps2_regs->cp0_entryhi; 775 | regs->cp0_reg11 = ps2_regs->cp0_reg11; 776 | regs->cp0_reg12 = ps2_regs->cp0_reg12; 777 | regs->cp0_reg13 = ps2_regs->cp0_reg13; 778 | regs->cp0_reg14 = ps2_regs->cp0_reg14; 779 | regs->cp0_prid = ps2_regs->cp0_prid; 780 | regs->cp1_acc = ps2_regs->cp1_acc; 781 | regs->shft_amnt = ps2_regs->shft_amnt; 782 | regs->lo1 = ps2_regs->lo1; 783 | regs->hi1 = ps2_regs->hi1; 784 | regs->cp0_depc = ps2_regs->cp0_depc; 785 | regs->cp0_perfcnt = ps2_regs->cp0_perfcnt; 786 | } 787 | 788 | 789 | void gdbstub_vanilla_to_ps2regs(gdb_regs_ps2 *ps2_regs, struct gdb_regs *regs) 790 | { 791 | *(int *)&ps2_regs->reg0 = (int)regs->reg0; 792 | *(int *)&ps2_regs->reg1 = (int)regs->reg1; 793 | *(int *)&ps2_regs->reg2 = (int)regs->reg2; 794 | *(int *)&ps2_regs->reg3 = (int)regs->reg3; 795 | *(int *)&ps2_regs->reg4 = (int)regs->reg4; 796 | *(int *)&ps2_regs->reg5 = (int)regs->reg5; 797 | *(int *)&ps2_regs->reg6 = (int)regs->reg6; 798 | *(int *)&ps2_regs->reg7 = (int)regs->reg7; 799 | *(int *)&ps2_regs->reg8 = (int)regs->reg8; 800 | *(int *)&ps2_regs->reg9 = (int)regs->reg9; 801 | *(int *)&ps2_regs->reg10 = (int)regs->reg10; 802 | *(int *)&ps2_regs->reg11 = (int)regs->reg11; 803 | *(int *)&ps2_regs->reg12 = (int)regs->reg12; 804 | *(int *)&ps2_regs->reg13 = (int)regs->reg13; 805 | *(int *)&ps2_regs->reg14 = (int)regs->reg14; 806 | *(int *)&ps2_regs->reg15 = (int)regs->reg15; 807 | *(int *)&ps2_regs->reg16 = (int)regs->reg16; 808 | *(int *)&ps2_regs->reg17 = (int)regs->reg17; 809 | *(int *)&ps2_regs->reg18 = (int)regs->reg18; 810 | *(int *)&ps2_regs->reg19 = (int)regs->reg19; 811 | *(int *)&ps2_regs->reg20 = (int)regs->reg20; 812 | *(int *)&ps2_regs->reg21 = (int)regs->reg21; 813 | *(int *)&ps2_regs->reg22 = (int)regs->reg22; 814 | *(int *)&ps2_regs->reg23 = (int)regs->reg23; 815 | *(int *)&ps2_regs->reg24 = (int)regs->reg24; 816 | *(int *)&ps2_regs->reg25 = (int)regs->reg25; 817 | *(int *)&ps2_regs->reg26 = (int)regs->reg26; 818 | *(int *)&ps2_regs->reg27 = (int)regs->reg27; 819 | *(int *)&ps2_regs->reg28 = (int)regs->reg28; 820 | *(int *)&ps2_regs->reg29 = (int)regs->reg29; 821 | *(int *)&ps2_regs->reg30 = (int)regs->reg30; 822 | *(int *)&ps2_regs->reg31 = (int)regs->reg31; 823 | *(int *)&ps2_regs->lo = (int)regs->lo; 824 | *(int *)&ps2_regs->hi = (int)regs->hi; 825 | ps2_regs->cp0_status = regs->cp0_status; 826 | ps2_regs->cp0_badvaddr = regs->cp0_badvaddr; 827 | ps2_regs->cp0_cause = regs->cp0_cause; 828 | ps2_regs->cp0_epc = regs->cp0_epc; 829 | ps2_regs->fpr0 = regs->fpr0; 830 | ps2_regs->fpr1 = regs->fpr1; 831 | ps2_regs->fpr2 = regs->fpr2; 832 | ps2_regs->fpr3 = regs->fpr3; 833 | ps2_regs->fpr4 = regs->fpr4; 834 | ps2_regs->fpr5 = regs->fpr5; 835 | ps2_regs->fpr6 = regs->fpr6; 836 | ps2_regs->fpr7 = regs->fpr7; 837 | ps2_regs->fpr8 = regs->fpr8; 838 | ps2_regs->fpr9 = regs->fpr9; 839 | ps2_regs->fpr10 = regs->fpr10; 840 | ps2_regs->fpr11 = regs->fpr11; 841 | ps2_regs->fpr12 = regs->fpr12; 842 | ps2_regs->fpr13 = regs->fpr13; 843 | ps2_regs->fpr14 = regs->fpr14; 844 | ps2_regs->fpr15 = regs->fpr15; 845 | ps2_regs->fpr16 = regs->fpr16; 846 | ps2_regs->fpr17 = regs->fpr17; 847 | ps2_regs->fpr18 = regs->fpr18; 848 | ps2_regs->fpr19 = regs->fpr19; 849 | ps2_regs->fpr20 = regs->fpr20; 850 | ps2_regs->fpr21 = regs->fpr21; 851 | ps2_regs->fpr22 = regs->fpr22; 852 | ps2_regs->fpr23 = regs->fpr23; 853 | ps2_regs->fpr24 = regs->fpr24; 854 | ps2_regs->fpr25 = regs->fpr25; 855 | ps2_regs->fpr26 = regs->fpr26; 856 | ps2_regs->fpr27 = regs->fpr27; 857 | ps2_regs->fpr28 = regs->fpr28; 858 | ps2_regs->fpr29 = regs->fpr29; 859 | ps2_regs->fpr30 = regs->fpr30; 860 | ps2_regs->fpr31 = regs->fpr31; 861 | ps2_regs->cp1_fsr = regs->cp1_fsr; 862 | ps2_regs->cp1_fir = regs->cp1_fir; 863 | ps2_regs->frame_ptr = regs->frame_ptr; 864 | ps2_regs->dummy = regs->dummy; 865 | ps2_regs->cp0_index = regs->cp0_index; 866 | ps2_regs->cp0_random = regs->cp0_random; 867 | ps2_regs->cp0_entrylo0 = regs->cp0_entrylo0; 868 | ps2_regs->cp0_entrylo1 = regs->cp0_entrylo1; 869 | ps2_regs->cp0_context = regs->cp0_context; 870 | ps2_regs->cp0_pagemask = regs->cp0_pagemask; 871 | ps2_regs->cp0_wired = regs->cp0_wired; 872 | ps2_regs->cp0_reg7 = regs->cp0_reg7; 873 | ps2_regs->cp0_reg8 = regs->cp0_reg8; 874 | ps2_regs->cp0_reg9 = regs->cp0_reg9; 875 | ps2_regs->cp0_entryhi = regs->cp0_entryhi; 876 | ps2_regs->cp0_reg11 = regs->cp0_reg11; 877 | ps2_regs->cp0_reg12 = regs->cp0_reg12; 878 | ps2_regs->cp0_reg13 = regs->cp0_reg13; 879 | ps2_regs->cp0_reg14 = regs->cp0_reg14; 880 | ps2_regs->cp0_prid = regs->cp0_prid; 881 | ps2_regs->cp1_acc = regs->cp1_acc; 882 | ps2_regs->shft_amnt = regs->shft_amnt; 883 | ps2_regs->lo1 = regs->lo1; 884 | ps2_regs->hi1 = regs->hi1; 885 | ps2_regs->cp0_depc = regs->cp0_depc; 886 | ps2_regs->cp0_perfcnt = regs->cp0_perfcnt; 887 | } 888 | 889 | 890 | void gdbstub_show_ps2_regs(gdb_regs_ps2 *regs, int except_num, int to_screen, int clear_screen) 891 | { 892 | static void (*printf_p)(const char *, ...); 893 | int i; 894 | int code, cause = regs->cp0_cause; 895 | 896 | code = cause & 0x7c; 897 | 898 | if (to_screen) { 899 | if (clear_screen) 900 | init_scr(); 901 | printf_p = scr_printf; 902 | } else { 903 | printf_p = (void *)printf; 904 | } 905 | 906 | printf_p("\t\t\tGBDStub: %s exception #%d\n", exception_names_g[code >> 2], except_num); 907 | printf_p("\tStatus %08x BadVAddr %08x Cause %08x EPC %08x\n\n", regs->cp0_status, regs->cp0_badvaddr, cause, regs->cp0_epc); 908 | 909 | // Print out the gprs. 910 | for (i = 0; i < 16; i++) { 911 | printf_p("%4s:%016lx%016lx %4s:%016lx%016lx\n", 912 | regName[i], ((long *)®s->reg0)[(i * 2) + 1], ((long *)®s->reg0)[i * 2], 913 | regName[i + 16], ((long *)®s->reg0)[(i + 16) * 2 + 1], ((long *)®s->reg0)[(i + 16) * 2]); 914 | } 915 | 916 | // Print out hi and lo. on ps2 these are 128 bit. 917 | printf_p("\n%4s:%016lx%016lx %4s:%016lx%016lx\n", 918 | regName[32], ((long *)®s->lo)[1], ((long *)®s->lo)[0], 919 | regName[33], ((long *)®s->hi)[1], ((long *)®s->hi)[0]); 920 | 921 | // Print out the floating point regs. There's cp1_acc as well, but I leave printing the ps2 registers at the end. 922 | if (!to_screen) { 923 | { 924 | int *pf = (int *)®s->fpr0; 925 | 926 | for (i = 0; i < 8; i++) { 927 | printf_p("%4s:%08lX %4s:%08lX %4s:%08lX %4s:%08lX\n", regName[38 + (i * 4)], pf[i * 4], 928 | regName[38 + ((i * 4) + 1)], pf[(i * 4) + 1], 929 | regName[38 + ((i * 4) + 2)], pf[(i * 4) + 2], 930 | regName[38 + ((i * 4) + 3)], pf[(i * 4) + 3]); 931 | } 932 | } 933 | } 934 | printf_p("\n%4s:%08lX %4s:%08lX\n", regName[70], regs->cp1_fsr, 935 | regName[71], regs->cp1_fir); 936 | } 937 | 938 | 939 | // If asynchronously interrupted by gdb, then we need to set a breakpoint 940 | // at the interrupted instruction so that we wind up stopped with a 941 | // reasonable stack frame. 942 | // It may be time to intergrate this code with ps2sdk. 943 | static struct gdb_bp_save async_bp; 944 | 945 | void set_async_breakpoint(unsigned int epc) 946 | { 947 | async_bp.addr = epc; 948 | async_bp.val = *(unsigned *)epc; 949 | *(unsigned *)epc = BP_OPC; 950 | flush_cache_all(); 951 | } 952 | 953 | // Normal gdb stubs execute in exception state. This one doesn't. This is because I need interrupts enabled in order to communicate 954 | // with remote GDB via tcpip. It's probably really slow doing it this way and I should probably figure out a way of keeping it in 955 | // exception state instead; serial communications?? 956 | void handle_exception(gdb_regs_ps2 *ps2_regs) 957 | { 958 | int trap; 959 | int sigval; 960 | int addr; 961 | int length; 962 | char *ptr, *ptr2; 963 | struct gdb_regs *regs = &gdbstub_regs; 964 | 965 | // I probably flush the caches unnessisarily, in the process of 'bodging it until it works'. 966 | flush_cache_all(); 967 | 968 | // Make the registers 'normal' - i.e. 32 bit. The remote GDB side never sees the 128 bit ps2_regs, only ever regs. 969 | // We put the changed values back just before exiting this function. 970 | gdbstub_ps2regs_to_vanilla(ps2_regs, regs); 971 | 972 | gdbstub_num_exceptions_g++; 973 | 974 | if (debug_level_g & DEBUG_PRINTREGS) { 975 | #if (DEBUG_PRINTREGS_SCREEN == 1) 976 | gdbstub_show_ps2_regs(ps2_regs, gdbstub_num_exceptions_g, 1, 1); 977 | #endif 978 | #if (DEBUG_PRINTREGS_PRINTF == 1) 979 | gdbstub_show_ps2_regs(ps2_regs, gdbstub_num_exceptions_g, 0, 0); 980 | #endif 981 | } 982 | 983 | // Turn cop1 on if it's not being used. Hmm. 984 | trap = (regs->cp0_cause & 0x7c) >> 2; 985 | if (trap == 11) { 986 | gdbstub_printf(DEBUG_OTHERS, "trap is 11 (cop unused)\n"); 987 | if (((regs->cp0_cause >> CAUSEB_CE) & 3) == 1) { 988 | regs->cp0_status |= ST0_CU1; 989 | return; 990 | } 991 | } 992 | 993 | // If we're in breakpoint() increment the EPC beyond the breakpoint. 994 | // This doesn't apply for other breaks not in the breakpoint() function, remote GDB handles all that, although stub handles 995 | // single stepping breakpoints... Can they conflict? i.e. single stepping breakpoint overwriting a remote GDB known breakpoint. 996 | // I've used debuggers where this appears to have happened, resulting in break insns left floating in the code. 997 | if (trap == 9 && regs->cp0_epc == (unsigned long)breakinst) { 998 | gdbstub_printf(DEBUG_SINGLESTEP, "skipping breakinst\n"); 999 | regs->cp0_epc += 4; 1000 | } 1001 | 1002 | // If we were single_stepping, restore the opcodes hoisted for the breakpoint(s). Conditional branch instructions place a 1003 | // breakpoint at both the branch target and epc+8. 1004 | if (step_bp[0].addr) { 1005 | gdbstub_printf(DEBUG_SINGLESTEP, "Restoring step_bp[0] %8x (was %8x) to %8x\n", step_bp[0].addr, *(unsigned *)step_bp[0].addr, step_bp[0].val); 1006 | *(unsigned *)step_bp[0].addr = step_bp[0].val; 1007 | step_bp[0].addr = 0; 1008 | 1009 | if (step_bp[1].addr) { 1010 | gdbstub_printf(DEBUG_SINGLESTEP, "Restoring step_bp[1] %8x (was %8x) to %8x\n", step_bp[1].addr, *(unsigned *)step_bp[1].addr, step_bp[1].val); 1011 | *(unsigned *)step_bp[1].addr = step_bp[1].val; 1012 | step_bp[1].addr = 0; 1013 | } 1014 | flush_cache_all(); 1015 | } 1016 | 1017 | // If we were interrupted asynchronously by gdb, then a breakpoint was set at the EPC of the interrupt so 1018 | // that we'd wind up here with an interesting stack frame. 1019 | if (async_bp.addr) { 1020 | *(unsigned *)async_bp.addr = async_bp.val; 1021 | async_bp.addr = 0; 1022 | } 1023 | 1024 | // Reply to remote GDB that an exception has occurred. 1025 | sigval = computeSignal(trap); 1026 | ptr = output_buffer; 1027 | 1028 | // Send trap type (converted to signal). 1029 | *ptr++ = 'T'; 1030 | *ptr++ = hexchars[sigval >> 4]; 1031 | *ptr++ = hexchars[sigval & 0xf]; 1032 | 1033 | // Send Error PC. 1034 | *ptr++ = hexchars[REG_EPC >> 4]; 1035 | *ptr++ = hexchars[REG_EPC & 0xf]; 1036 | *ptr++ = ':'; 1037 | ptr = mem2hex((char *)®s->cp0_epc, ptr, 4, 0); 1038 | *ptr++ = ';'; 1039 | 1040 | #ifdef COMPILER_USES_30_AS_FP 1041 | // Send frame pointer. 1042 | *ptr++ = hexchars[REG_FP >> 4]; 1043 | *ptr++ = hexchars[REG_FP & 0xf]; 1044 | *ptr++ = ':'; 1045 | ptr = mem2hex((char *)®s->reg30, ptr, 4, 0); 1046 | *ptr++ = ';'; 1047 | #else 1048 | // Send stack pointer as frame pointer instead, it's the best we can do? 1049 | *ptr++ = hexchars[REG_FP >> 4]; 1050 | *ptr++ = hexchars[REG_FP & 0xf]; 1051 | *ptr++ = ':'; 1052 | ptr = mem2hex((char *)®s->reg29, ptr, 4, 0); 1053 | *ptr++ = ';'; 1054 | #endif 1055 | 1056 | // Send stack pointer. 1057 | *ptr++ = hexchars[REG_SP >> 4]; 1058 | *ptr++ = hexchars[REG_SP & 0xf]; 1059 | *ptr++ = ':'; 1060 | ptr = mem2hex((char *)®s->reg29, ptr, 4, 0); 1061 | *ptr++ = ';'; 1062 | 1063 | // put the packet. 1064 | *ptr++ = 0; 1065 | gdbstub_initialised_g == 2 ? putpacket(output_buffer) : putDebugChar('-'), gdbstub_initialised_g = 2; 1066 | 1067 | // Wait for input from remote GDB. 1068 | while (1) { 1069 | output_buffer[0] = 0; 1070 | getpacket(input_buffer); 1071 | ptr = output_buffer; 1072 | 1073 | switch (input_buffer[0]) { 1074 | case '?': 1075 | // Return sigval. 1076 | *ptr++ = 'S'; 1077 | *ptr++ = hexchars[sigval >> 4]; 1078 | *ptr++ = hexchars[sigval & 0xf]; 1079 | *ptr++ = 0; 1080 | break; 1081 | 1082 | case 'd': 1083 | // Toggle debug flag - TODO :: Use this for setting my debug flag perhaps? 1084 | break; 1085 | 1086 | // Set thread for subsequent operations. 1087 | case 'H': 1088 | // Hct... c = 'c' for thread used in step and continue. 1089 | // t... can be -1 for all threads. 1090 | // c = 'g' for thread used in other operations. 1091 | // If zero, pick a thread, any thread. 1092 | strcpy(output_buffer, "OK"); 1093 | break; 1094 | 1095 | // Return the value of the CPU registers. 1096 | case 'g': 1097 | ptr = mem2hex((char *)®s->reg0, ptr, 32 * 4, 0); // r0...r31 1098 | ptr = mem2hex((char *)®s->cp0_status, ptr, 6 * 4, 0); // status, lo, hi, bad, cause, pc (epc!). 1099 | ptr = mem2hex((char *)®s->fpr0, ptr, 32 * 4, 0); // f0...31 1100 | ptr = mem2hex((char *)®s->cp1_fsr, ptr, 2 * 4, 0); // cp1 1101 | ptr = mem2hex((char *)®s->frame_ptr, ptr, 2 * 4, 0); // fp, dummy. What's dummy for? 1102 | ptr = mem2hex((char *)®s->cp0_index, ptr, 16 * 4, 0); // index, random, entrylo0, entrylo0 ... prid 1103 | break; 1104 | 1105 | // Set the value of the CPU registers - return OK. 1106 | case 'G': { 1107 | // TODO :: Test this, what about the SP stuff? 1108 | ptr2 = &input_buffer[1]; 1109 | hex2mem(ptr2, (char *)®s->reg0, 32 * 4, 0); 1110 | ptr2 = &ptr2[32 * 8]; 1111 | hex2mem(ptr2, (char *)®s->cp0_status, 6 * 4, 0); 1112 | ptr2 = &ptr2[6 * 8]; 1113 | hex2mem(ptr2, (char *)®s->fpr0, 32 * 4, 0); 1114 | ptr2 = &ptr2[32 * 8]; 1115 | hex2mem(ptr2, (char *)®s->cp1_fsr, 2 * 4, 0); 1116 | ptr2 = &ptr2[2 * 8]; 1117 | hex2mem(ptr2, (char *)®s->frame_ptr, 2 * 4, 0); 1118 | ptr2 = &ptr2[2 * 8]; 1119 | hex2mem(ptr2, (char *)®s->cp0_index, 16 * 4, 0); 1120 | strcpy(output_buffer, "OK"); 1121 | } break; 1122 | 1123 | // mAA..AA,LLLL: Read LLLL bytes at address AA..AA. 1124 | case 'm': 1125 | ptr2 = &input_buffer[1]; 1126 | 1127 | if (hexToInt(&ptr2, &addr) && *ptr2++ == ',' && hexToInt(&ptr2, &length)) { 1128 | if (mem2hex((char *)addr, output_buffer, length, 1)) 1129 | break; 1130 | strcpy(output_buffer, "E03"); 1131 | } else 1132 | strcpy(output_buffer, "E01"); 1133 | break; 1134 | 1135 | // MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK. 1136 | case 'M': 1137 | ptr2 = &input_buffer[1]; 1138 | 1139 | if (hexToInt(&ptr2, &addr) && *ptr2++ == ',' && hexToInt(&ptr2, &length) && *ptr2++ == ':') { 1140 | if (hex2mem(ptr2, (char *)addr, length, 1)) 1141 | strcpy(output_buffer, "OK"); 1142 | else 1143 | strcpy(output_buffer, "E03"); 1144 | } else 1145 | strcpy(output_buffer, "E02"); 1146 | break; 1147 | 1148 | // cAA..AA: Continue at address AA..AA(optional). 1149 | case 'c': 1150 | // Try to read optional parameter, pc unchanged if no parm. 1151 | ptr2 = &input_buffer[1]; 1152 | if (hexToInt(&ptr2, &addr)) 1153 | regs->cp0_epc = addr; 1154 | goto ret; 1155 | break; 1156 | 1157 | // Kill the program. 1158 | case 'k': 1159 | break; 1160 | 1161 | // Reset the whole machine. 1162 | case 'r': 1163 | break; 1164 | 1165 | // Single step. 1166 | case 's': 1167 | // There is no single step insn in the MIPS ISA, so uses break instead. 1168 | single_step(regs); 1169 | goto ret; 1170 | 1171 | // Set baud rate (bBB) - I've kept this here in case anyone wants to have a go at communicating some other way. 1172 | case 'b': 1173 | gdbstub_error("change baud rate not implemented\n"); 1174 | break; 1175 | 1176 | } // switch 1177 | // reply to the request 1178 | putpacket(output_buffer); 1179 | } // while 1180 | 1181 | ret: 1182 | gdbstub_vanilla_to_ps2regs(ps2_regs, regs); 1183 | flush_cache_all(); 1184 | return_handle_exception(); 1185 | } 1186 | 1187 | 1188 | // Mappings between MIPS hardware trap types, and unix signals, which are what GDB understands. It also indicates which hardware 1189 | // traps we need to commandeer when initializing the stub. 1190 | #ifdef TRAP_ALL_EXCEPTIONS 1191 | static struct hard_trap_info 1192 | { 1193 | unsigned char tt; // Trap type code for MIPS R3xxx and R4xxx 1194 | unsigned char signo; // Signal that we map this trap into 1195 | } hard_trap_info[] = { 1196 | {4, SIGBUS}, // address error (load). 1197 | {5, SIGBUS}, // address error (store). 1198 | {6, SIGBUS}, // instruction bus error. 1199 | {7, SIGBUS}, // data bus error. 1200 | {9, SIGTRAP}, // break. 1201 | {10, SIGILL}, // reserved instruction. 1202 | // {11, SIGILL}, // CPU unusable. 1203 | {12, SIGFPE}, // overflow. 1204 | {13, SIGTRAP}, // trap. 1205 | {14, SIGSEGV}, // virtual instruction cache coherency. 1206 | {15, SIGFPE}, // floating point exception. 1207 | {23, SIGSEGV}, // watch. 1208 | {31, SIGSEGV}, // virtual data cache coherency. 1209 | {0, 0} // Must be last. 1210 | }; 1211 | #else 1212 | // Cut down to just the break instruction. 1213 | static struct hard_trap_info 1214 | { 1215 | unsigned char tt; // Trap type code for MIPS R3xxx and R4xxx. 1216 | unsigned char signo; // Signal that we map this trap into. 1217 | } hard_trap_info[] = { 1218 | {9, SIGTRAP}, // break. 1219 | {0, 0} // Must be last. 1220 | }; 1221 | #endif 1222 | 1223 | 1224 | // Convert the MIPS hardware trap type code to a Unix signal number. 1225 | static int computeSignal(int tt) 1226 | { 1227 | struct hard_trap_info *ht; 1228 | 1229 | for (ht = hard_trap_info; ht->tt && ht->signo; ht++) 1230 | if (ht->tt == tt) 1231 | return ht->signo; 1232 | 1233 | return SIGHUP; // Default for things we don't know about. 1234 | } 1235 | 1236 | 1237 | // While we find nice hex chars, build an int. Return number of chars processed. 1238 | static int hexToInt(char **ptr, int *intValue) 1239 | { 1240 | int numChars = 0; 1241 | int hexValue; 1242 | 1243 | *intValue = 0; 1244 | 1245 | while (**ptr) { 1246 | hexValue = hex(**ptr); 1247 | if (hexValue < 0) 1248 | break; 1249 | 1250 | *intValue = (*intValue << 4) | hexValue; 1251 | numChars++; 1252 | 1253 | (*ptr)++; 1254 | } 1255 | 1256 | return (numChars); 1257 | } 1258 | 1259 | 1260 | void __attribute__((noinline)) breakpoint(void) 1261 | { 1262 | if (!gdbstub_initialised_g) { 1263 | gdbstub_error("breakpoint() called, but not initialised stub yet!\n"); 1264 | return; 1265 | } 1266 | __asm__ __volatile__(" \n" 1267 | " .globl breakinst \n" 1268 | " .set noreorder \n" 1269 | " nop \n" 1270 | "breakinst: break \n" 1271 | " nop \n" 1272 | " .set reorder \n"); 1273 | } 1274 | 1275 | // -1 == failure 1276 | int gdbstub_net_open() 1277 | { 1278 | int rc_bind, rc_listen; 1279 | 1280 | if (SifLoadModule(HOSTPATHIRX "ps2ips.irx", 0, NULL) < 0) { 1281 | gdbstub_error("Load ps2ips.irx failed.\n"); 1282 | return -1; 1283 | } 1284 | 1285 | if (ps2ip_init() < 0) { 1286 | gdbstub_error("ps2ip_init failed.\n"); 1287 | return -1; 1288 | } 1289 | 1290 | sh_g = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 1291 | if (sh_g < 0) { 1292 | gdbstub_error("Socket create failed.\n"); 1293 | return -1; 1294 | } 1295 | gdbstub_printf(DEBUG_COMMSINIT, "Socket returned %i.\n", sh_g); 1296 | 1297 | memset(&gdb_local_addr_g, 0, sizeof(gdb_local_addr_g)); 1298 | gdb_local_addr_g.sin_family = AF_INET; 1299 | gdb_local_addr_g.sin_addr.s_addr = htonl(INADDR_ANY); // any local address (a.k.a 0.0.0.0). 1300 | gdb_local_addr_g.sin_port = htons(GDB_PORT); 1301 | 1302 | // bind. 1303 | rc_bind = bind(sh_g, (struct sockaddr *)&gdb_local_addr_g, sizeof(gdb_local_addr_g)); 1304 | if (rc_bind < 0) { 1305 | gdbstub_error("Bind failed.\n"); 1306 | disconnect(sh_g); // Clean-up on failures. 1307 | return -1; 1308 | } 1309 | gdbstub_printf(DEBUG_COMMSINIT, "Bind returned %i.\n", rc_bind); 1310 | 1311 | rc_listen = listen(sh_g, 2); 1312 | if (rc_listen < 0) { 1313 | gdbstub_error("Listen failed.\n"); 1314 | disconnect(sh_g); // Clean-up on failures. 1315 | return -1; 1316 | } 1317 | gdbstub_printf(DEBUG_COMMSINIT, "Listen returned %i.\n", rc_listen); 1318 | return 0; 1319 | } 1320 | 1321 | static int gdbstub_net_accept() 1322 | { 1323 | int remote_len; 1324 | 1325 | remote_len = sizeof(gdb_remote_addr_g); 1326 | // Disconnect last connection if there was any. 1327 | if (cs_g >= 0) 1328 | disconnect(cs_g); 1329 | cs_g = accept(sh_g, (struct sockaddr *)&gdb_remote_addr_g, &remote_len); 1330 | 1331 | if (cs_g < 0) { 1332 | gdbstub_error("Accept failed.\n"); 1333 | disconnect(sh_g); // Clean-up on failures. 1334 | return -1; 1335 | } 1336 | 1337 | FD_ZERO(&comms_fd_g); 1338 | FD_SET(cs_g, &comms_fd_g); 1339 | 1340 | gdbstub_printf(DEBUG_COMMSINIT, "accept is %d\n", cs_g); 1341 | 1342 | gdbstub_printf(DEBUG_COMMSINIT, "netopen ok.\n"); 1343 | 1344 | return 0; 1345 | } 1346 | 1347 | void gdbstub_net_close() 1348 | { 1349 | disconnect(cs_g); 1350 | disconnect(sh_g); 1351 | gdbstub_printf(DEBUG_COMMSINIT, "disconnected\n"); 1352 | 1353 | return; 1354 | } 1355 | 1356 | 1357 | // -1 == failure 1358 | int gdbstub_init(int argc, char *argv[]) 1359 | { 1360 | struct hard_trap_info *ht; 1361 | 1362 | gdbstub_initialised_g = 0; 1363 | gdbstub_num_exceptions_g = 0; 1364 | thread_id_g = GetThreadId(); 1365 | 1366 | if (gdbstub_net_open() == -1 || gdbstub_net_accept() == -1) { 1367 | gdbstub_error("failed to open net connection.\n"); 1368 | return -1; 1369 | } 1370 | 1371 | for (ht = hard_trap_info; ht->tt && ht->signo; ht++) { 1372 | if (ht->tt < 4) 1373 | SetVTLBRefillHandler(ht->tt, trap_low); 1374 | else 1375 | SetVCommonHandler(ht->tt, trap_low); 1376 | } 1377 | flush_cache_all(); 1378 | gdbstub_initialised_g = 1; 1379 | gdbstub_printf(DEBUG_COMMS, "Waiting for remote GDB to connect\n\n\n"); 1380 | 1381 | breakpoint(); 1382 | 1383 | return 0; 1384 | } 1385 | 1386 | 1387 | void gdbstub_close() 1388 | { 1389 | gdbstub_net_close(); 1390 | gdbstub_initialised_g = 0; 1391 | 1392 | return; 1393 | } 1394 | 1395 | 1396 | int gdb_stub_main(int argc, char *argv[]) 1397 | { 1398 | int i; 1399 | 1400 | #if (DEBUG_PRINTREGS_SCREEN == 1) 1401 | init_scr(); 1402 | scr_printf("GDB Stub Loaded\n\n"); 1403 | #endif 1404 | gdbstub_printf(DEBUG_COMMSINIT, "GDB Stub Loaded\n\n"); 1405 | 1406 | for (i = 0; i < argc; i++) { 1407 | gdbstub_printf(DEBUG_COMMSINIT, "arg %d is %s\n", i, argv[i]); 1408 | } 1409 | 1410 | if (argc >= 2) 1411 | comms_p_g = (gdbstub_comms_data *)my_atoi(argv[1]); 1412 | else 1413 | comms_p_g = NULL; 1414 | 1415 | if (gdbstub_init(argc, argv) == -1) { 1416 | gdbstub_error("INIT FAILED\n"); 1417 | ExitDeleteThread(); 1418 | return -1; 1419 | } 1420 | 1421 | return 0; 1422 | } 1423 | -------------------------------------------------------------------------------- /ee/r5900_regs.h: -------------------------------------------------------------------------------- 1 | /* 2 | _____ ___ ____ 3 | ____| | ____| PSX2 OpenSource Project 4 | | ___| |____ (C)2003, Ray Donnelly ( rdonnelly@polygoons.com ) 5 | Also, Tony Saveski ( t_saveski@yahoo.com ) 6 | -------------------------------------------------------------------------- 7 | gdb-low.S PS2 REMOTE GDB STUB USING TCP 8 | */ 9 | 10 | #ifndef R5900_REGS_H 11 | #define R5900_REGS_H 12 | 13 | // MIPS CPU Registsers 14 | #define zero $0 // Always 0 15 | #define at $1 // Assembler temporary 16 | #define v0 $2 // Function return 17 | #define v1 $3 // 18 | #define a0 $4 // Function arguments 19 | #define a1 $5 20 | #define a2 $6 21 | #define a3 $7 22 | #define t0 $8 // Temporaries. No need 23 | #define t1 $9 // to preserve in your 24 | #define t2 $10 // functions. 25 | #define t3 $11 26 | #define t4 $12 27 | #define t5 $13 28 | #define t6 $14 29 | #define t7 $15 30 | #define s0 $16 // Saved Temporaries. 31 | #define s1 $17 // Make sure to restore 32 | #define s2 $18 // to original value 33 | #define s3 $19 // if your function 34 | #define s4 $20 // changes their value. 35 | #define s5 $21 36 | #define s6 $22 37 | #define s7 $23 38 | #define t8 $24 // More Temporaries. 39 | #define t9 $25 40 | #define k0 $26 // Reserved for Kernel 41 | #define k1 $27 42 | #define gp $28 // Global Pointer 43 | #define sp $29 // Stack Pointer 44 | #define fp $30 // Frame Pointer 45 | #define ra $31 // Function Return Address 46 | 47 | // COP0 48 | #define Index $0 // Index into the TLB array 49 | #define Random $1 // Randomly generated index into the TLB array 50 | #define EntryLo0 $2 // Low-order portion of the TLB entry for.. 51 | #define EntryLo1 $3 // Low-order portion of the TLB entry for 52 | #define Context $4 // Pointer to page table entry in memory 53 | #define PageMask $5 // Control for variable page size in TLB entries 54 | #define Wired $6 // Controls the number of fixed ("wired") TLB entries 55 | #define BadVAddr $8 // Address for the most recent address-related exception 56 | #define Count $9 // Processor cycle count 57 | #define EntryHi $10 // High-order portion of the TLB entry 58 | #define Compare $11 // Timer interrupt control 59 | #define Status $12 // Processor status and control 60 | #define Cause $13 // Cause of last general exception 61 | #define EPC $14 // Program counter at last exception 62 | #define PRId $15 // Processor identification and revision 63 | #define Config $16 // Configuration register 64 | #define LLAddr $17 // Load linked address 65 | #define WatchLo $18 // Watchpoint address Section 6.25 on 66 | #define WatchHi $19 // Watchpoint control 67 | #define Debug $23 // EJTAG Debug register 68 | #define DEPC $24 // Program counter at last EJTAG debug exception 69 | #define PerfCnt $25 // Performance counter interface 70 | #define ErrCtl $26 // Parity/ECC error control and status 71 | #define CacheErr $27 // Cache parity error control and status 72 | #define TagLo $28 // Low-order portion of cache tag interface 73 | #define TagHi $29 // High-order portion of cache tag interface 74 | #define ErrorPC $30 // Program counter at last error 75 | #define DEASVE $31 // EJTAG debug exception save register 76 | 77 | /* 78 | * Coprocessor 0 register names 79 | */ 80 | #define CP0_INDEX $0 81 | #define CP0_RANDOM $1 82 | #define CP0_ENTRYLO0 $2 83 | #define CP0_ENTRYLO1 $3 84 | #define CP0_CONF $3 85 | #define CP0_CONTEXT $4 86 | #define CP0_PAGEMASK $5 87 | #define CP0_WIRED $6 88 | #define CP0_INFO $7 89 | #define CP0_BADVADDR $8 90 | #define CP0_COUNT $9 91 | #define CP0_ENTRYHI $10 92 | #define CP0_COMPARE $11 93 | #define CP0_STATUS $12 94 | #define CP0_CAUSE $13 95 | #define CP0_EPC $14 96 | #define CP0_PRID $15 97 | #define CP0_CONFIG $16 98 | #define CP0_LLADDR $17 99 | #define CP0_WATCHLO $18 100 | #define CP0_WATCHHI $19 101 | #define CP0_XCONTEXT $20 102 | #define CP0_FRAMEMASK $21 103 | #define CP0_DIAGNOSTIC $22 104 | #define CP0_DEBUG $23 105 | #define CP0_DEPC $24 106 | #define CP0_PERFORMANCE $25 107 | #define CP0_ECC $26 108 | #define CP0_CACHEERR $27 109 | #define CP0_TAGLO $28 110 | #define CP0_TAGHI $29 111 | #define CP0_ERROREPC $30 112 | #define CP0_DESAVE $31 113 | 114 | /* 115 | * Coprocessor 1 (FPU) register names 116 | */ 117 | #define CP1_REVISION $0 118 | #define CP1_STATUS $31 119 | 120 | #define ST0_CH 0x00040000 121 | #define ST0_SR 0x00100000 122 | #define ST0_TS 0x00200000 123 | #define ST0_BEV 0x00400000 124 | #define ST0_RE 0x02000000 125 | #define ST0_FR 0x04000000 126 | #define ST0_CU 0xf0000000 127 | #define ST0_CU0 0x10000000 128 | #define ST0_CU1 0x20000000 129 | #define ST0_CU2 0x40000000 130 | #define ST0_CU3 0x80000000 131 | #define ST0_XX 0x80000000 /* MIPS IV naming */ 132 | 133 | // Floating point (cop1) floating point general purpose registers. 134 | #define fp0 $f0 135 | #define fp1 $f1 136 | #define fp2 $f2 137 | #define fp3 $f3 138 | #define fp4 $f4 139 | #define fp5 $f5 140 | #define fp6 $f6 141 | #define fp7 $f7 142 | #define fp8 $f8 143 | #define fp9 $f9 144 | #define fp10 $f10 145 | #define fp11 $f11 146 | #define fp12 $f12 147 | #define fp13 $f13 148 | #define fp14 $f14 149 | #define fp15 $f15 150 | #define fp16 $f16 151 | #define fp17 $f17 152 | #define fp18 $f18 153 | #define fp19 $f19 154 | #define fp20 $f20 155 | #define fp21 $f21 156 | #define fp22 $f22 157 | #define fp23 $f23 158 | #define fp24 $f24 159 | #define fp25 $f25 160 | #define fp26 $f26 161 | #define fp27 $f27 162 | #define fp28 $f28 163 | #define fp29 $f29 164 | #define fp30 $f30 165 | #define fp31 $f31 166 | 167 | #define fcr0 $0 // Floating point Implementation / Revision register. 168 | #define fcr31 $31 // Floating point Control / Status register. 169 | // Floating point Accumulator (ACC) can't be peeked at except via madd.s. 170 | 171 | #endif // R5900_REGS_H 172 | -------------------------------------------------------------------------------- /ps2.sh: -------------------------------------------------------------------------------- 1 | target remote 192.168.1.13:12 2 | symbol-file sample/testgdb.elf 3 | layout src 4 | layout asm 5 | layout split 6 | list main 7 | b testgdb.c:12 8 | c 9 | -------------------------------------------------------------------------------- /sample/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile template 3 | # 4 | 5 | EE_BIN = testgdb.elf 6 | EE_OBJS = testgdb.o 7 | 8 | EE_CFLAGS += -g -w 9 | EE_LIBS = -ldebug -lps2gdbStub -lps2ips 10 | EE_LDFLAGS += -L../lib 11 | 12 | all: 13 | cp -f $(PS2SDK)/iop/irx/ps2ips.irx ./ 14 | $(MAKE) $(EE_BIN) 15 | 16 | clean: 17 | rm -f $(EE_BIN) $(EE_OBJS) ps2ips.irx 18 | 19 | include $(PS2SDK)/samples/Makefile.pref 20 | include $(PS2SDK)/samples/Makefile.eeglobal 21 | -------------------------------------------------------------------------------- /sample/testgdb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int gdb_stub_main(int argc, char *argv[]); 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | volatile int i = 0; 9 | 10 | init_scr(); 11 | gdb_stub_main(0, NULL); 12 | scr_printf("i = %d\n", i += 2); 13 | scr_printf("i = %d\n", i += 10); 14 | 15 | asm("l: b l;"); 16 | 17 | return 0; 18 | } 19 | --------------------------------------------------------------------------------