7 void mark_reachable (struct code
*c
, struct location
*loc
)
9 uint32 remaining
= 1 + ((c
->end
->address
- loc
->address
) >> 2);
10 for (; remaining
--; loc
++) {
11 if (loc
->reachable
== LOCATION_REACHABLE
) break;
12 loc
->reachable
= LOCATION_REACHABLE
;
14 if (!loc
->insn
) return;
16 if (loc
->insn
->flags
& INSN_JUMP
) {
18 if (loc
[1].reachable
!= LOCATION_REACHABLE
)
19 loc
[1].reachable
= LOCATION_DELAY_SLOT
;
23 mark_reachable (c
, loc
->target
);
26 if (loc
->cswitch
->checked
) {
27 element el
= list_head (loc
->cswitch
->references
);
29 struct location
*target
= element_getvalue (el
);
30 mark_reachable (c
, target
);
31 if (!target
->references
)
32 target
->references
= list_alloc (c
->lstpool
);
33 if (target
->cswitch
!= loc
->cswitch
)
34 list_inserttail (target
->references
, loc
);
35 target
->cswitch
= loc
->cswitch
;
36 el
= element_next (el
);
41 if ((remaining
== 0) || !(loc
->insn
->flags
& (INSN_LINK
| INSN_WRITE_GPR_D
)))
46 } else if (loc
->insn
->flags
& INSN_BRANCH
) {
48 if (loc
[1].reachable
!= LOCATION_REACHABLE
)
49 loc
[1].reachable
= LOCATION_DELAY_SLOT
;
53 mark_reachable (c
, loc
->target
);
56 if ((remaining
== 0) || (loc
->branchalways
&& !(loc
->insn
->flags
& INSN_LINK
)))
66 void new_subroutine (struct code
*c
, struct location
*loc
, struct prx_function
*imp
, struct prx_function
*exp
)
68 struct subroutine
*sub
= loc
->sub
;
71 sub
= fixedpool_alloc (c
->subspool
);
74 sub
->whereused
= list_alloc (c
->lstpool
);
75 sub
->callblocks
= list_alloc (c
->lstpool
);
78 if (imp
) sub
->import
= imp
;
79 if (exp
) sub
->export
= exp
;
81 if (sub
->import
&& sub
->export
) {
83 error (__FILE__
": location 0x%08X is both import and export", loc
->address
);
86 mark_reachable (c
, loc
);
90 void extract_from_relocs (struct code
*c
)
94 i
= prx_findreloc (c
->file
, c
->baddr
);
95 for (; i
< c
->file
->relocnum
; i
++) {
97 struct prx_reloc
*rel
= &c
->file
->relocs
[i
];
99 tgt
= (rel
->target
- c
->baddr
) >> 2;
100 if (tgt
>= c
->numopc
) continue;
102 if (rel
->target
& 0x03) {
103 error (__FILE__
": relocation not word aligned 0x%08X", rel
->target
);
109 if (rel
->type
== R_MIPSX_JAL26
) {
110 new_subroutine (c
, loc
, NULL
, NULL
);
111 } else if (rel
->type
== R_MIPS_26
) {
112 struct location
*calledfrom
;
115 if (rel
->vaddr
< c
->baddr
) continue;
116 if (rel
->vaddr
& 0x03) {
117 error (__FILE__
": relocation address not word aligned 0x%08X", rel
->vaddr
);
121 ctgt
= (rel
->vaddr
- c
->baddr
) >> 2;
122 if (ctgt
>= c
->numopc
) continue;
124 calledfrom
= &c
->base
[ctgt
];
125 if (calledfrom
->insn
->insn
== I_JAL
) {
126 new_subroutine (c
, loc
, NULL
, NULL
);
128 } else if (rel
->type
== R_MIPS_32
) {
130 new_subroutine (c
, loc
, NULL
, NULL
);
131 } else if (rel
->type
== R_MIPS_HI16
|| rel
->type
== R_MIPSX_HI16
) {
132 /* TODO: is this OK to do? */
134 new_subroutine (c
, loc
, NULL
, NULL
);
140 void extract_from_exports (struct code
*c
)
144 for (i
= 0; i
< c
->file
->modinfo
->numexports
; i
++) {
145 struct prx_export
*exp
;
147 exp
= &c
->file
->modinfo
->exports
[i
];
148 for (j
= 0; j
< exp
->nfuncs
; j
++) {
149 struct prx_function
*func
= &exp
->funcs
[j
];
150 struct location
*loc
;
152 tgt
= (func
->vaddr
- c
->baddr
) >> 2;
153 if (func
->vaddr
< c
->baddr
||
155 error (__FILE__
": invalid exported function");
160 new_subroutine (c
, loc
, NULL
, func
);
161 func
->pfunc
= loc
->sub
;
167 void extract_from_imports (struct code
*c
)
171 for (i
= 0; i
< c
->file
->modinfo
->numimports
; i
++) {
172 struct prx_import
*imp
;
174 imp
= &c
->file
->modinfo
->imports
[i
];
175 for (j
= 0; j
< imp
->nfuncs
; j
++) {
176 struct prx_function
*func
= &imp
->funcs
[j
];
177 struct location
*loc
;
179 tgt
= (func
->vaddr
- c
->baddr
) >> 2;
180 if (func
->vaddr
< c
->baddr
||
182 error (__FILE__
": invalid imported function");
187 new_subroutine (c
, loc
, func
, NULL
);
188 func
->pfunc
= loc
->sub
;
189 loc
->sub
->numregargs
= func
->numargs
;
195 struct subroutine
*find_sub (struct code
*c
, struct location
*loc
)
198 if (loc
->sub
) return loc
->sub
;
199 } while (loc
-- != c
->base
);
204 void extract_hidden_subroutines (struct code
*c
)
206 struct subroutine
*cursub
= NULL
;
210 /* TODO: improve the hidden subroutine detection algorithm */
213 for (i
= 0; i
< c
->numopc
; i
++) {
214 struct location
*loc
= &c
->base
[i
];
215 if (loc
->sub
) cursub
= loc
->sub
;
216 if (loc
->reachable
== LOCATION_UNREACHABLE
) continue;
219 struct location
*target
;
220 struct subroutine
*targetsub
;
222 target
= loc
->target
;
223 targetsub
= find_sub (c
, target
);
225 if (!target
->sub
&& (targetsub
!= cursub
)) {
226 report (__FILE__
": hidden subroutine at 0x%08X (called by 0x%08X)\n", target
->address
, loc
->address
);
227 new_subroutine (c
, target
, NULL
, NULL
);
238 void delimit_borders (struct code
*c
)
240 struct subroutine
*prevsub
= NULL
;
243 for (i
= 0; i
< c
->numopc
; i
++) {
244 if (c
->base
[i
].sub
) {
245 list_inserttail (c
->subroutines
, c
->base
[i
].sub
);
247 prevsub
->end
= &c
->base
[i
- 1];
249 prevsub
= c
->base
[i
].sub
;
251 c
->base
[i
].sub
= prevsub
;
255 prevsub
->end
= &c
->base
[i
- 1];
261 void check_switches (struct subroutine
*sub
)
263 struct location
*loc
;
266 if (!loc
->cswitch
) continue;
267 if (loc
->cswitch
->jumplocation
== loc
) {
269 int haserror
= FALSE
;
271 el
= list_head (loc
->cswitch
->references
);
273 struct location
*target
= element_getvalue (el
);
274 if (target
->sub
!= loc
->sub
) haserror
= TRUE
;
275 target
->cswitch
= NULL
;
276 el
= element_next (el
);
280 report (__FILE__
": invalid switch at 0x%08X\n", loc
->address
);
281 fixedpool_free (sub
->code
->switchpool
, loc
->cswitch
);
284 loc
->cswitch
->checked
= TRUE
;
285 if (loc
->reachable
== LOCATION_REACHABLE
) {
286 loc
->reachable
= LOCATION_UNREACHABLE
;
287 mark_reachable (sub
->code
, loc
);
291 } while (loc
++ != sub
->end
);
295 void check_subroutine (struct subroutine
*sub
)
297 struct location
*loc
;
300 if ((sub
->end
->address
- sub
->begin
->address
) < 4) {
301 error (__FILE__
": subroutine is too short: 0x%08X", sub
->begin
->address
);
302 sub
->haserror
= TRUE
;
307 if (loc
->reachable
== LOCATION_UNREACHABLE
) continue;
309 if (loc
->error
!= ERROR_NONE
) {
310 switch (loc
->error
) {
311 case ERROR_INVALID_OPCODE
:
312 error (__FILE__
": invalid opcode 0x%08X at 0x%08X (sub: 0x%08X)", loc
->opc
, loc
->address
, sub
->begin
->address
);
313 sub
->haserror
= TRUE
;
315 case ERROR_TARGET_OUTSIDE_FILE
:
316 error (__FILE__
": branch/jump outside file at 0x%08X (sub: 0x%08X)", loc
->address
, sub
->begin
->address
);
317 sub
->haserror
= TRUE
;
319 case ERROR_DELAY_SLOT
:
320 error (__FILE__
": delay slot error at 0x%08X (sub: 0x%08X)", loc
->address
, sub
->begin
->address
);
321 sub
->haserror
= TRUE
;
323 case ERROR_ILLEGAL_BRANCH
:
324 error (__FILE__
": illegal branch at 0x%08X (sub: 0x%08X)", loc
->address
, sub
->begin
->address
);
325 sub
->haserror
= TRUE
;
332 if (sub
->haserror
) continue;
336 if (!loc
->target
->references
)
337 loc
->target
->references
= list_alloc (sub
->code
->lstpool
);
338 list_inserttail (loc
->target
->references
, loc
);
340 } while (loc
++ != sub
->end
);
343 if (loc
->reachable
== LOCATION_UNREACHABLE
) return;
346 if ((loc
->insn
->flags
& (INSN_JUMP
| INSN_LINK
| INSN_WRITE_GPR_D
)) == INSN_JUMP
)
349 if ((loc
->insn
->flags
& (INSN_BRANCH
| INSN_LINK
)) == INSN_BRANCH
&& loc
->branchalways
)
352 error (__FILE__
": subroutine at 0x%08X (end 0x%08X) has no finish", sub
->begin
->address
, sub
->end
->address
);
353 sub
->haserror
= TRUE
;
356 void extract_subroutines (struct code
*c
)
360 c
->subroutines
= list_alloc (c
->lstpool
);
362 extract_from_exports (c
);
363 extract_from_imports (c
);
364 extract_from_relocs (c
);
367 error (__FILE__
": creating artificial subroutine at address 0x%08X", c
->baddr
);
368 new_subroutine (c
, c
->base
, NULL
, NULL
);
371 extract_hidden_subroutines (c
);
375 el
= list_head (c
->subroutines
);
377 struct subroutine
*sub
= element_getvalue (el
);
379 check_switches (sub
);
380 check_subroutine (sub
);
382 if (!sub
->haserror
) {
383 sub
->status
|= SUBROUTINE_EXTRACTED
;
387 if (!sub
->haserror
) {
388 sub
->status
|= SUBROUTINE_CFG_EXTRACTED
;
389 extract_operations (sub
);
392 if (!sub
->haserror
) {
393 sub
->status
|= SUBROUTINE_OPERATIONS_EXTRACTED
;
396 el
= element_next (el
);