@@ -187,6 +187,117 @@ class Thumb2Architecture: public ArmCommonArchitecture
187187
188188 result.length = decomp.instrSize / 8 ;
189189
190+ if ((decomp.mnem == armv7::ARMV7_IT) && (decomp.fields [FIELD_mask] != 0 ))
191+ {
192+ // IT block: consume all instructions and handle contained branches
193+ uint32_t offset = decomp.instrSize / 8 ;
194+ uint32_t mask = decomp.fields [FIELD_mask];
195+ uint32_t cond = decomp.fields [FIELD_firstcond];
196+
197+ size_t instrCount;
198+ if (mask & 1 )
199+ instrCount = 4 ;
200+ else if (mask & 2 )
201+ instrCount = 3 ;
202+ else if (mask & 4 )
203+ instrCount = 2 ;
204+ else
205+ instrCount = 1 ;
206+
207+ // First branch/return in each condition path
208+ bool trueTerminated = false ;
209+ bool falseTerminated = false ;
210+ bool trueBranched = false ;
211+ bool falseBranched = false ;
212+ bool trueReturned = false ;
213+ bool falseReturned = false ;
214+
215+ uint64_t trueBranchTargetAddr = 0 ;
216+ uint64_t falseBranchTargetAddr = 0 ;
217+
218+ for (size_t i = 0 ; i < instrCount; i++)
219+ {
220+ bool isTrue = (i == 0 ) || (((mask >> (4 - i)) & 1 ) == (cond & 1 ));
221+
222+ InstructionInfo innerResult;
223+ if (!GetInstructionInfo (data + offset, addr + offset, maxLen - offset, innerResult))
224+ break ;
225+ if ((offset + innerResult.length ) > maxLen)
226+ break ;
227+
228+ bool & terminated = isTrue ? trueTerminated : falseTerminated;
229+ bool & branched = isTrue ? trueBranched : falseBranched;
230+ bool & returned = isTrue ? trueReturned : falseReturned;
231+ uint64_t & branchTarget = isTrue ? trueBranchTargetAddr : falseBranchTargetAddr;
232+
233+ // Only process if the conditional branch we're following isn't terminated
234+ // Otherwise, just track if the arch is switching and the offset
235+ if (!terminated)
236+ {
237+ for (size_t j = 0 ; j < innerResult.branchCount ; j++)
238+ {
239+ switch (innerResult.branchType [j])
240+ {
241+ case UnconditionalBranch:
242+ case TrueBranch:
243+ case FalseBranch:
244+ branched = true ;
245+ terminated = true ;
246+ branchTarget = innerResult.branchTarget [j];
247+ break ;
248+ case FunctionReturn:
249+ returned = true ;
250+ terminated = true ;
251+ break ;
252+ case CallDestination:
253+ result.AddBranch (CallDestination, innerResult.branchTarget [j],
254+ innerResult.branchArch [j] ? m_armArch : this );
255+ break ;
256+ case UnresolvedBranch:
257+ case IndirectBranch:
258+ case ExceptionBranch:
259+ // We don't know the branch target so just set terminated
260+ terminated = true ;
261+ break ;
262+ default :
263+ break ;
264+ }
265+ }
266+ }
267+
268+ if (innerResult.archTransitionByTargetAddr )
269+ result.archTransitionByTargetAddr = true ;
270+
271+ offset += innerResult.length ;
272+ }
273+
274+ result.length = offset;
275+
276+ uint64_t fallThroughAddr = (addr + offset) & 0xffffffffLL ;
277+ // The targets for true/false branches either go somewhere or fall through to the next instr
278+ uint64_t trueTargetAddr = trueBranched ? trueBranchTargetAddr : fallThroughAddr;
279+ uint64_t falseTargetAddr = falseBranched ? falseBranchTargetAddr : fallThroughAddr;
280+
281+ if (trueReturned && falseReturned)
282+ {
283+ // If both paths return
284+ result.AddBranch (FunctionReturn);
285+ }
286+ else if (trueTargetAddr != falseTargetAddr)
287+ {
288+ // True and false go to different locations (either branch or fallthrough)
289+ result.AddBranch (TrueBranch, trueTargetAddr, this );
290+ result.AddBranch (FalseBranch, falseTargetAddr, this );
291+ }
292+ else if (trueTargetAddr != fallThroughAddr)
293+ {
294+ // True and false branch to the same location that isn't the fallthrough address
295+ result.AddBranch (UnconditionalBranch, trueTargetAddr, this );
296+ }
297+
298+ return true ;
299+ }
300+
190301 switch (decomp.mnem )
191302 {
192303 case armv7::ARMV7_LDR:
0 commit comments