Improved Efficiency of Object Code Verification Using Statically Abstracted Object Code

One of the major challenges in the formal verification of embedded system software is the complexity and substantially large size of the implementation. The problem becomes crucial when the embedded system is a complex medical device that is executing convoluted algorithms. In refinement-based verification, both specification and implementation are expressed as transition systems. Each behavior of the implementation transition system is matched to the specification transition system with the help of a refinement map. The refinement map can only project those values from the implementation which are responsible for labeling the current state of the system. When the refinement map is applied at the object code level, numerous instructions map to a single state in the specification transition system called stuttering instructions. We use the concept of Static Stuttering Abstraction (SSA) that filters the common multiple segments of stuttering instructions and replaces each segment with a merger. SSA algorithm reduces the implementation state space in embedded software, subsequently decreasing the efforts involved in manual verification with WEB refinement. The algorithm is formally proven for correctness. SSA is implemented on the pacemaker object code to evaluate the effectiveness of abstracted code in verification process. The results helped to establish the fact that, despite code size reduction, the bugs and errors can still be found. We implemented the SSA technique on two different platforms and it has been proven to be consistent in decreasing the code size significantly and hence the complexity of the implementation transition system. The results illustrate that there is considerable reduction in time and effort required for the verification of a complex software control, i.e., pacemaker when statically stuttering abstracted code is employed.


Introduction
Today, our lives are predominantly occupied by numerous real-time embedded systems. Such systems provide specific functionality and normally they are the element of a larger system [1]. e correctness of these systems depends on the logical functions as well as on the timely response. ey are used in automobiles, aircraft, implantable medical devices, cell phones, industrial robots, and many others.
At the core of embedded systems, there exist complex algorithms that define the specific working of the device. For instance, we can consider an implantable medical device like a pacemaker. Such an implanted device communicates with the patient's body and takes the real-time parameters to make decisions and execute the treatment accordingly [2]. Due to their safety-critical nature, small errors in such a system can lead to a big unrecoverable loss. erefore, it is essential to verify the functional correctness of such systems [3]. e verification process in the phase of medical device designing can prevent the patient from unrecoverable or irreversible consequences. Likewise, the formal verification practices applied in the aircraft designing can save an ample amount of money invested in the design and prevent any unseen failures that may occur in the future due to the presence of any error. From 2006 to 2011, the US Food and Drug Administration (FDA) has reported 5294 recalls and 1,154,451 adverse events due to the malfunctioning of medical devices. 22.8% of the recalls are due to the software bugs in the device [4]. FDA issued 55 Class 1 recalls due to software errors in the medical devices from 2006 to 2019 [5]. By looking into the statistics, it can be concluded that the formal verification of real-time embedded systems like safety-critical medical devices is indispensable.
Formal verification finds hard corner-case errors and ensures that the system is bug-free [6]. It is one of the most important and crucial phases of the software design cycle. Several efforts have been made to devise the techniques for enhancing efficiency and minimizing the complexity of the verification process. e software of an embedded system is comprised of intricate algorithms that are designed according to the required behavior of system [7]. Algorithms are written in a high-level language like C, Python, and Verilog. e compiler converts this source code into equivalent machine code, which is also known as object code. e conversion process of code from high-level language to low-level language can introduce errors in the system. Each instruction in a high-level language like C or C++ is converted into several numbers of lines in a low-level language like assembly. e object code of an embedded system is large, real-time, and interrupt-driven, and it contains the stuttering nature. e large size of the object code, which is to be executed on the embedded system, makes the application of the formal verification process more challenging. is leads to the requirement of an abstraction technique that reduces the length of the code while preserving the essence of functionality. e abstraction technique is designed to reduce the time and effort involved in the verification process by minimizing the size of the object code. In this paper, we propose a novel abstraction technique named Static Stuttering Abstraction (SSA), which is applied to the object code statically, which is before the actual run time. e technique is designed in the context of refinement-based verification, which is a formal verification technique. e specification and implementation of the systems are denoted in the form of a transition system (TS) in refinement-based verification. e required behavior of the system is defined in specification TS through states and transitions, while the software implementation at the object code level which is executed in the embedded system is represented by the implementation TS. e size of implementation TS is very huge as compared to the specification TS. e single progression at specification TS is represented by millions of transitions in the implementation TS. ese several transitions are known as stuttering transitions. Each state in the specification TS represents a unique state of the systems. e stuttering transitions arise from the execution of stuttering instructions. e states associated with the stuttering transitions in the implementation TS represent the same state of the specification TS.
We used the concept of stuttering instructions and stuttering transitions to formulate the concept of SSA. e finite number of stuttering instructions forming a pattern with a certain frequency is abstracted into one instruction.
e abstracted and merged instruction preserves the functionality of the implementation TS and consequently reduces the size. In this paper, we presented a process to apply SSA on the stuttering instructions of the implementation TS. e idea of SSA was presented in the ird International Conference on Cyber-Technologies and Cyber-Systems in Athens, Greece [8].
e specific contributions of this paper include the following: (i) e induction-based correctness proof for the SSA algorithm (ii) Improving the efficiency of manual verification of complex medical software control based on Well-Founded Equivalence Bisimulation (WEB) refinement (iii) Significant reduction in the state space of implementation object code for any platform (iv) e effectiveness of SSA algorithm for static verification of object code for nondeterministic systems where implementation can take different paths in real time (based on branches) e devised algorithm takes the instruction set architecture (ISA) and original object code as input for any platform and then automatically creates the abstracted code. We are not aware of any abstraction technique for the object code and its verification, to the best of our knowledge. With the help of the case study, we were able to achieve the proposed outcomes in terms of the verification effort improvement. us, SSA leads to reduced complexity in formal verification of object code in safety-critical applications. e rest of this paper is organized as follows. e background of the basic concepts used in the rest of the paper is presented in Section 2. Section 3 details related work. e proposed abstraction technique, designed algorithm, and its correctness are described in Section 4. Sec-tion5 describes the case study and results. e verification of the pacemaker control program with SSA and the details of efficiency achieved in verification due to SSA are explained in Section 6. Conclusion and future work are discussed in Section 7.

Background
e specification of the system and its implementation are modeled as TS in refinement-based FV. Definition of TS is as follows [9].
where S is the set of states, R is the transition relation which is the set of all state transitions, and L is a labeling function that defines what is visible at each state. A transition is of the form 〈w, v〉, where (w, v) ∈ S. e formal specification TS MM s represents the highlevel interpretation of the required behavior of the system design. e requirements are expressed by a small set of transitions and states in MM s . e implementation TS MM I is obtained after MM s is implemented on the embedded system and a high-level C code is obtained. e C code is translated into machine code, which is the object code that corresponds to MM I . A single execution of an instruction in the object code creates a transition in MM I . Here comes the role of SSA abstraction since MM s and MM I differ largely due to the state-space size and the number of transitions. One of the major challenges in refinement-based FV techniques is matching a small set of states, i.e., MM s , to an infinite large state space, i.e., MM I . e matching between the states of MM s with a transition of the form 〈s, u〉 and MM I with a transition of the form 〈w, v〉 is executed based on the concept of refinement map, which is defined below.
A refinement map r is applied to a state in MM I and its projects to the corresponding state in MM s . As stated by Definition 2, refinement map can either project to the same state in the specification r(w) � r(v) � s, i.e., both w and v match to the same specification state s, or project to a new state in the specification r(w) � s and r(v) � u, i.e., both w and v match to different specification states s and u, respectively. Refinement map only projects a certain set of values responsible for mapping the current state in MM I to the corresponding state in MM s . erefore, if an instruction does not modify the set of values projected by the refinement map, the instruction is called a stuttering instruction s i , as defined in Definition 3.
. . , i n be the set of instructions in MM I , where each i n � P n , w n , P n corresponds to the set of values that project to the matching state in MM s and w n reflects the current implementation state obtained after execution of i n ; when r(P n ) is applied, i n is a stuttering instruction s i if e high-level C code of a real-time system may contain common operations, which are translated into the same block of instructions in assembly code. A single block of instruction may occur multiple times, which makes a large portion of assembly code. e fundamental objective of SSA is to identify the location of common blocks of stuttering instructions s i , consider them as a pattern, and replace that pattern with a merger of a single line instruction. e updated single line instruction includes operations of all the instructions in the replaced pattern. If a pattern consists of 4 stuttering instructions and it occurs 50 times in the object code, the SSA will reduce 150 lines in the code, thus reducing the state space of MM I .

Related Work
Real-time applications like medical devices have become more efficient and flexible, which makes them more complex. is leads to an increasing demand for effective verification techniques. In 2010, the FDA launched a program "Infusion Pump Improvement Initiative" to address the problems linked with the infusion pumps malfunctioning [10]. As a result of this safety initiative, many formal verification methods for the correctness of infusion pump software were developed. ese methods are based on verification tools like Kronos [11] and UPPAAL [12], which work on the concept of timed automata [13]. ese methods have been successful for the verification of highlevel models that work in real time. Epsilon [14] is another real-time verification tool that intends to verify the communication protocols. ese tools deal with the high-level models, while we intend to do formal verification of lowlevel object code that is executed on the device. Our research work aims to reduce the effort required and the complexity involved in applying verification techniques by introducing an abstraction procedure. In recent research, there have been a lot of techniques based on the concept of stuttering aiming to improve the efficiency of the verification process.
Groote and Wijs in [15] provide an improved algorithm that determines the stuttering equivalence on a Kripke Structure.
e time complexity of the algorithm is O(m log n), where m represents the total number of transitions and n denotes the total number of states in the structure. e equivalence determines whether the two states have unique behavior while ignoring the transitions. e authors of [16] proposed a formal verification methodology for six kinds of stepper motor control by using the Well-Founded Simulation-(WFS) based refinement. Rob [17] presented the theorems and definitions that describe how to reduce requirements for applying fair stuttering refinements for the system. Jain and Manolis presented a method to test the functional correctness of software and hardware through refinement in [18]. is method overcomes the loopholes in the de facto testing method that is usually used in the industrial sector. Rabinovich [19] used the theory of automata to stimulate continuous and discrete timed systems. e concept of stuttering is used for w-string but not for abstraction.
Stuttering is introduced by Joachim [20] for constructing the deterministic w-automata. e redundant states that are stuttering are skipped to make the size of automaton smaller. e authors employ stuttering-based reduction but did not apply abstraction on object code statically. Jabeen et al. [21] presented Timed Well-Founded Simulation (TWFS) refinement for formal verification of real-time Field Programmable Gate Array (FPGA). e authors identify the reachable states of FPGA through manually produced invariants, without using stuttering abstraction. e proposed method is suitable only for FPGA and not for the object code of a real-time system. Peter and Jose [22] introduced abstraction in the field of discrete time to reduce the size of the state space and to make analysis and model checking more feasible. e concept of abstraction is used but stuttering abstraction is not employed. Mohana et al. [23] presented a technique that automates the Well-Founded Simulation-(WFS-) based refinement on an implementation TS. e presented algorithm takes the abstracted object code as input.
Scientific Programming 3 e abstraction is not applied statically on object code. Shuja et al. [24] presented refinement-based verification for DDD mode pacemaker control. e object code of the pacemaker is verified by proof obligations. e authors did not consider stuttering abstraction to make the object code smaller in size, which in results makes the verification process more tedious and time-consuming.
A new abstraction framework for a 3-valued model is proposed by Nejati et al. [25]. e method avoids the use of unnecessary additional refinement step and makes the model conclusive.
Our technique aims to abstract the recurring patterns of instructions in object code. e abstraction of patterns reduces the number of transitions and makes the refinementbased verification process easier. From the results, it is evident that SSA reduces the size of the object code (MM I ). SSA algorithm and its correctness are explained in the next section.

Automatic Static Stuttering Abstraction
Refinement-based verification of a real-time embedded system application is complex due to the large size of the object code. In this paper, we developed an algorithm for SSA and applied that to a real-time case study. We studied that the proposed abstraction technique reduces a considerable amount of effort required for the verification of object code and elaborated results with the help of case study discussed in Section 6. SSA inputs the implementation TS MM I (original object code) and outputs the updated MM I (abstracted object code). With the reduction in the size of object code, the number of transitions in the updated object code also decreases. e abstraction involves the notions of stuttering and nonstuttering transitions which are formally defined as follows.

Definition 4. A stuttering transition s t in MM
where specification TS is of the form MM S � 〈S ′ , R ′ , L ′ 〉, 〈s, u〉 is a transition in R ′ , and (s, u) ∈ S ′ .
Similarly, nonstuttering transition is defined as follows.
where specification TS is of the form MM S � 〈S ′ , R ′ , L ′ 〉, 〈s, u〉 is a transition in R ′ , and (s, u) ∈ S ′ . e theoretical relation between stuttering instruction s i and stuttering and nonstuttering transitions, s t and n t , respectively, can be recognized with the help of Definitions 3-5. Proof. If an instruction i n is a stuttering instruction s i , then there is no progress in MM I with respect to MM S ; we apply rank function on MM I and get rank(w n ) < rank(w n−1 ) representing that the states (w n−1 , w n ) in MM I both project to the same state s in MM S . erefore, it implies that transition 〈w n−1 , w n 〉 is always stuttering transition s t if an instruction i n is a stuttering instruction s i .

□
Rank: rank is a function that can be described with a well-founded structure comprising a set of natural numbers and a less than operator on the natural numbers (〈N, < 〉). In implementation TS, it is defined as a function whose value decreases when the implementation stutters with respect to the specification, for each single stuttering transition. Definition 6. Static Stuttering Abstraction (SSA) is an algorithm that automatically applies stuttering abstraction (SA) during static symbolic simulation of object code. e main objective of SSA is to reduce the size of the object code while preserving the actual functionality of the object code. Let I � 〈i 1 , i 2 , i 3 , . . . , i n 〉 be the set of instructions in the implementation TS MM I . We can apply SA on a segment of (1) All the instructions in the segment are stuttering instructions s i . If any instruction in the segment is a nonstuttering instruction, then we cannot apply SA to abstract that segment. (2) Segments should not contain any branch/jump instruction in the middle or start of the segment.
After the application of SSA, the instructions in object code get updated with the abstracted segment in the following manner: By using the definitions, we proposed a tool that statically applies stuttering abstractions on the object code. Algorithm 1 exhibits a procedure that performs SSA at the object code. e inputs to the procedure Stuff Abs are as follows: (1) Original object code file (obj init ).
(2) Matrix (patt opc ) containing information regarding the opcode of instructions that are involved in a pattern. e matrix used in our case study is given in Figure 1. Each row in the matrix depicts information about a pattern. e first column shows the mnemonics of the instructions involved in each pattern, while the rest of the columns contain the opcode of each mnemonic involved in the pattern. e first row of the matrix lists the pattern LDR-STR, which based on observation has the highest frequency in obj init . e opcode of LDR is stored in the second column, while the opcode of STR is shown in the third column. is pattern contains only two instructions; the third and fourth columns have no opcode value (X). e patterns in patt opc are stored in the order from highest to lowest in terms of the number of  For locating a pattern in object code, Opc of I c must be equal to already defined opcode of an instruction in patt opc (N c , N opc ). Opc and patt opc (N c , N opc ) are compared through function Same. e variable will be 1 if both opcodes are equal (line 26). If (Match � 1) (line 27), then I c is stored in buff (line 28); else N opc will be set to 0 (line 41). N opc must be equal tos p , for the abstraction of instructions stored in buff (line 28). It indicates that required number of instructions in a pattern patt opc (N c , : ) is located by the procedure in object code and is stored in buff. Another condition for the abstraction of instructions stored in buff is that they all should be a stuttering instruction s i . e stuttering or nonstuttering nature of instructions is computed using a function ref − map (line 30). ref − map will return 1 in the case where all the instructions in buff are stuttering instructions; otherwise, output will be 0. If instructions in buff are stuttering instructions s i (line 32), the pattern in object code is abstracted through a function mrg. is function returns the updated object code obj up d (line 33). red l (N c ) is an array that stores the number of lines reduced after the abstraction of each pattern patt opc (Nc, : ) in an object code (line 35).
e initial value of red l (N c ) for each iteration N c is 0 (lines 6 and 10). In obj up d , the total number of lines obj l (N c ) and current line c ins line get reduced by red p (N c ) (lines 36 and 37). N c will be incremented by one when the search for a pattern ends in entire object code (line 9). It indicates that current inner loop (lines 13-37) will search for a pattern in patt opc (N c ).
Total re d updates the data of total number of lines reduced red l after each execution of inner loop, abstracting each pattern patt ope (N c ) (line 43). lines abs is the total number of lines in object code after the complete abstraction process (line 45).
obj up d is smaller in size but it contains the original functionality of theobj init . e prime functionality of the SSA algorithm is to reduce the size of the object code while preserving the essence of the original object code. Figure 2 gives a graphical overview of the SSA tool working with a segment of instructions on which a single merger is applied. e instructions in the merger are from the pacemaker object code (obj init ) implemented on an embedded system platform LPC1768 and intend to do following operations: (1) Load the value at a memory location [0 × 000007D0] to a register r1 (2) Store the value in register r0 at memory location addressed by Buffer includes a pattern (LDR-STR) that is defined in the matrix patt opc (1, : ) in Figure 1. For the abstraction, the instructions in a buffer must be stuttering instructions. e state of the system for pacemaker object code is associated with the memory address 0 × 00000820. e above pattern is not changing the state of the system and operation in both instructions cannot be executed by the microprocessor in a single execution cycle. We replace the instructions in Buffer with a Merger. e merger identifier is named LST. e merger is updating the content of memory location [0 × 000007D0 + #0 × 00] with the value of register r0. e opcode of the merger is updated by the ASCII conversion of the merger. e instructions in buffer occupy memory address from 0 × 00000642 to 0 × 00000644 but the merger is occupying a single memory location. e LDR-STR pattern occurs 35 times in obj init of a pacemaker as shown in Table 1. e abstracted object code reduces the length of object code and the number of stuttering transitions s t in MM I . e reduced length of the object code makes the verification process easier for the end user. e information regarding patterns, their mergers, and opcode is provided in Table 1.

Correctness of SSA.
In this section, we presented the correctness of the SSA algorithm to ensure its correct functionality. e correctness of an algorithm is stated when an algorithm is correct according to its specification. If an algorithm gives an expected output for input, then it refers to its functional correctness [26]. e total correctness of an algorithm requires its partial correctness and termination proof [27]. e partial correctness of an algorithm ensures that whenever algorithm runs it always outputs the correct value [28]. In Algorithm 1, after a few assignments, a large section (lines 8-44) is repeated to achieve the desired output; therefore, it is an iterative algorithm [29]. e correctness of Algorithm 1 is completely dependent on the correctness of the loop (lines . e partial correctness of the loop is asserted if and only if variables in algorithm satisfy the loop precondition and after the commands in the loop complete their execution, the variables of algorithm hold the postcondition [30].
Algorithm 1 inputs the object code of a medical device obj init , which is the initial state, and outputs the updated object code obj upd with all possible mergers of patterns, which is the final state. Initial and final states can be represented by the predicates. A precondition for an algorithm is the predicate that must be true before the algorithm starts its execution. Similarly, the predicate that states what must be true after the execution of an algorithm for a given precondition is the postcondition [31]. e partial correctness of a loop involves finding the loop invariant and then proves it through the induction method. A predicate that is true before the first iteration of a loop and is also true after the finite iterations of that loop is known as loop invariant [32]. e truth of loop invariant ensures the truth of the postcondition of the loop. We have considered that all the variables used in Algorithm 1 are natural numbers. In termination proof of an iterative algorithm, the iteration number is associated with the decreasing sequence of natural numbers. en the termination proof can be concluded from eorem 2 [33], given as follows.

Theorem 2. Every decreasing sequence of natural number is finite.
e total correctness proof can be expressed as All the variables used in Algorithm 1 are natural numbers. Algorithm contains nested loops (inner loop (lines 17-42) and outer loop (lines 8-44)). Partial correctness of nested loops first proves the loop invariant of the inner loop and afterward for the outer loop. Sections4-A1 and 4-A2 present the total correctness of the inner and outer loop of Algorithm 1, respectively, involving its partial correctness and termination proof. e naming convention of variables used in this section is the same as that used in Algorithm 1.

Correctness of Inner Loop.
is section describes the correctness of inner − loop (lines 17-42) of Algorithm 1. e inner loop scans entire object code and applies merger LST on all possible occurrences of each type of pattern (e.g., LDR-STR). e correctness proof is as follows: (1) e precondition for the inner loop is It consists of 4 conditions that must be true before the execution of inner loop: e number of lines in object code at iteration N c of the outer loop is stored in obj l (N c ) and its value cannot be negative before the inner loop (line 12).
e number of lines that can be reduced red p (N c ) due to each abstraction of a pattern patt opc (N c , : ) cannot be a negative value (line 13). For a two-line pattern like LDR-STR, only one line can be reduced in object code after applying merger LST. e total number of lines reduced red l (N c ) through abstraction of a pattern patt opc (N c , : ) in whole object code must be zero (line 10).
e number of times abstraction abs i (N c ) of a pattern patt opc (N c , : ) is applied on object code must be zero.
(2) e postcondition for inner loop is It must be true after the termination of inner loop, when the condition c ins line � obj(N c ) becomes true. e purpose of inner loop is to apply merger on all possible occurrences of a pattern patt opc (N c , : ) in object code. e inner loop calculates information regarding total number of lines reduced in object code red l (N c ) and total number of times merger is applied on object code $abs_i(N_c)$ for a pattern given in matrix patt opc (N c , : ).
Proof. e base case for loop is k � 0. Before the loop starts (line 17), I(0) is is indicates that loop invariant holds for the base case. abs i 0 (N c ) represents the initial value of abs i (N c ). It is always 0 for every N c before the inner loop is executed (line 16).

Scientific Programming
If the loop invariant I is true for k th iteration, then it should hold for (k + 1) iteration (induction step). From lines 34 and 35 of algorithm, From equation (2), From equation (4), From equation (5), it can be seen that loop invariant holds after the (k + 1) th iteration. By induction method, the truth of equations (2) and (5) shows that loop invariant (equation (1)) is also true. (4) e termination proof for inner loop is given as follows.
After the (k + 1) th iteration, equation (7) will become Equation (8) shows that d is a decreasing sequence of iteration k. From eorem 2, we know that loop terminates in finite steps. (5) e truth of postcondition of inner loop can also be validated through the results given in Table 1. Consider a 4-line pattern LDR(pc), LDR(Register), CMP, BNE given in Table 1. e postcondition is given as e computed value can be compared with the value of red l (N c ) given in Table 1

Correctness of Outer Loop.
is section proves the correctness of the outer loop (lines 8-44) of the SSA algorithm. e main purpose of the outer loop is to consider each pattern from the matrix patt opc during each iteration and calculate the total number of reductions Total re d (line 43): (1) e precondition for the outer loop is e precondition consists of 5 conditions, which must be true before the outer loop execution. count represents the total number of patterns (rows) in the matrix patt opc (line 2). Its value cannot be negative.
Total re d represents the total lines reduced due to the abstraction of patterns in object code (line 43). Its value must be zero as the precondition of outer − loop.

Scientific Programming
N c indicates the current pattern (row number) considered in the matrix patt opc . Before the outer loop, its value must be zero. red l (N c ) represents the total number of lines reduced in object code due to the abstraction of pattern patt opc (N c , : ). Its value must be zero before the process of abstraction (outer loop) starts when N c � 0. abs i (N c ) shows the total abstractions of a pattern patt opc (N c , : ) done by the inner loop. Before the outer loop (N c � 0), its value must be zero.
(2) e postcondition of outer loop is By putting value of red l (N c ) from equation (1),  Proof. Suppose that the base case for loop is k � 0 and n k � 0. Before the first iteration of loop starts (line 8), the loop invariant in equation (12) becomes abs i (0) is the precondition of the outer loop. e loop invariant is true for the base case (k).

(23)
Comparison of equations (12) and (14) shows that the loop invariant I(n) holds after the (k + 1) th iteration of the loop. (4) e termination proof for outer loop is given as follows.

□
Proof. e guard G of the loop (line 8) is From line 2, it is evident that count is always a constant value. e value of N c is zero before the outer loop (line 3), but after each iteration of outer loop, its value gets closer to count (line 9). Let Meanwhile, d k > 0 and d k ∈ Ν.
During (k + 1) th iteration of the outer loop, equation (15) will become e above equation (16) shows that the value of d k is a decreasing sequence of positive integers. From eorem 2, it can be concluded that the outer loop terminates after finite iterations. e outer loop gives information regarding Total red k upon its termination when N c ≮count. Total red k given in Table 2 is the sum of all values in column red l (N c ) given in Table 1.

Case Study and Results
We have checked the efficiency of SSA abstraction tool by implementing it on the object code of a pacemaker. e code of pacemaker is designed according to the clinical settings expressed as a TS presented in Figure 3. At the start, the implementation transition system MM I of pacemaker is obtained on an ARM Cortex-M3-based NXP LPC1768 microcontroller. A library is maintained according to the instruction set architecture (ISA) of the microcontroller. Table 1 summarizes the information about the number and type of patterns identified and merged by an automated SSA tool for the object code. SSA reduces 41.78% of the object code of the pacemaker.
To confirm the consistency of the proposed tool, the functionality of the pacemaker is also modeled on a different platform, ATMega328p microcontroller. A separate library is maintained which supports the ISA of the Atmega328p microcontroller. Table 2 shows that, after abstraction through the SSA tool, the object code of pacemaker implemented on Atmega328p microcontroller is reduced up to 23.47%. e reduction in both cases is for a single execution of code, while in the real-time application the object code is executed in an infinite execution loop. e SSA reduces the considerable number of s t which makes the refinement-based verification process more efficient. Figure 4 depicts the general methodology for verification with SSA. e implementation code is first reduced by using the proposed SSA algorithm and then the reduced code and specification are formally modeled as transition systems (TS). Using the theory of WEB, which incorporates the Scientific Programming stuttering and nonstuttering behaviors, formal models and theorems are generated and discharged into theorem prover Z3. If the theorem is incorrect, both the formal model and theorem are revised, and the process is repeated. Previously, Shuja et al. [24] similarly verified the object code but they did not apply the SSA technique. Our case study results conclude that SSA has reduced the verification time of object code.

Verification of Pacemaker with SSA
To validate the correctness of abstracted object code after the SSA application, we performed the formal verification of the pacemaker control program using a statically abstracted implementation transition system (TS). It is to be noted that now the statically abstracted object code contributes to the implementation transition system instead of the original source code. We have taken the specification of pacemaker from [24] in the form of a TS (STS PM ) as shown in Figure 3. e pacemaker control program was implemented on Cortex-M3-based NXP LPC1768 microcontroller. e object code obtained after implementation was abstracted using the proposed SSA tool. e resultant abstracted code was formally verified against the specification. e underlying theory used for verification is the WEB (Well-Founded Equivalence Bisimulation) refinement theory [9] which is a notion of equivalence between the two transition systems (TS). e abstracted object code which is the implementation can be modeled as a TS where both the nonstuttering instructions and abstracted stuttering instructions are modeled as functions. e object code implementation is at the lower level with greater details as compared to the specification which is only the higher-level representation of system behavior. To overcome the differences in the implementation states and specification states, WEB employs the concept of refinement maps. A refinement map is a function that projects the implementation states to specification states and its definition is given in Section 2. e number of transitions in implementation TS is far more than the number of transitions in specification TS. For our pacemaker case study, the object code or implementation has millions of transitions, while the specification has only 10 transitions. erefore, several implementation transitions match to a single transition in the specification. is phenomenon is known as stuttering and WEB refinement theory covers this concept. A more detailed description of WEB refinement can be found in [22]. To ensure that the implementation is making progress and stuttering phenomenon terminates eventually, we have used rank functions. Rank functions discriminate against the stutter from deadlock (infinite stutter). If there is an infinite stutter, then it signals to a deadlock bug in the implementation.
We developed different proof obligations for pacemaker control knowing the specification TS. e proof obligations are written as the decidable fragments of first-order logic and are checked using the decision procedure (SMT solver Z3). e specification and implementation are encoded in the language of SMT. e proof obligations cover all the possible transitions and behaviors in statically abstracted implementation TS and check that every possible transition in the implementation system matches to a transition in the specification. e proof obligations should encompass only the reachable states of the implementation to avoid spurious counterexamples. We derived an invariant property that    identifies only the reachable states of implementation. e invariant property is given as follows: In the abovementioned properties, w is the implementation state and r is the refinement map which projects each implementation state w to one of the specification states S c . e invariant captures all the reachable states in the implementation. e object control program requires two counters indicated by At l and Vt l which keep track of the time that has passed since the last atrial and ventricle pace, respectively. e two counters show the permissible range of time based on which the transitions take place between different implementation states. ese permitted ranges of time values correspond to timing cycles in the specification (STS PM ) and are given using constants AEI, AVI, PWV, and PWA. e invariant holds true at each and every state of the implementation system, thus ensuring that the implementation always corresponds to the specification. We derived proof obligations for stuttering and nonstuttering behaviors of implementation. e invariant property characterizes all the implementation states to ensure that every transition in the implementation matches to a transition of the specification. e developed WEB refinement proof obligations were verified by Z3. e verification experiments were performed on Intel (R) Xeon (R) Bronze 3104CPU @1.70 GHz with 64GB RAM. A verification check was performed on the updated object code using the Z3 solver.
6.1. Bugs Caught by WEB. WEB refinement-based proof obligations facilitated finding out the bugs that are otherwise unseen or neglected by testing-based approaches. We caught up to two such kinds of bugs while verifying the pacemaker's abstracted object code using proof obligations. e description of such bugs is given as follows: (1) Bug 1: Port1 of LPC1768 was used for AP and VP, as given in the specification STS PM . e I/O functionality of Port1 is controlled by FIO1SET and FIO1CLR registers, through which the pin values are set and cleared, respectively. e value of FIO1SET was being updated inaccurately by the object code, specifically resulting in the system to transition incorrectly from s 3 to s 0 to s 4 . e correct transition according to specification STS PM is from s 3 to s 4 directly. is bug was caught by WEB proof obligations as this transition (s 3 , s 0 ) did not match to the specification transition system.
(2) Bug 2: the inputs for AS and VS were implemented using external interrupts. e interrupt status register IO2IntStatR holds the current status of interrupts. A value of either 1 or 2 in IO2IntStatR indicates that an AS or VS has occurred, respectively. e bug was revealed by VS input following the AS input and hence changing the status register IO2IntStatR value from 1 to 3. is is an incorrect value of status register indicating that both an AS and a VS have occurred. Consequently, the source of the external interrupt was misread as AS instead of VS. e bug occurred because the interrupt status was not cleared in the IO2IntStatR after the occurrence of an AS. is bug was caught and fixed.

Induced Bugs.
In order to assure that SSA does not alter or hide the original behavior of the object code, we also induced some bugs in the original object code. We added two more bugs, one in nonstuttering instructions and another in stuttering instructions, to check how SSA behaves to erroneous code. We were able to catch these induced bugs also in the abstracted code. e description of the induced bugs is given as follows: (1) Bug 1: in the pacemaker object code, the state of the system is represented by the last 5 bits [34] of LPC GPIO1. First, the pins of LPC GPIO1 need to be configured as output by writing 1s to the respective pins of the FIO1DIR register. As shown in Figure 5(a), the merger MST preserves the original instructions data. With the help of proof obligation, the merger is verified to implement correct behavior. Next, we induced an error by sending the wrong data to one pin of the FIO1DIR register. is erroneous data was passed to the merger as well, and the SSA tool abstracted the code (shown in Figure 5(b)). When this merger with erroneous data was verified, the proof was not satisfied. Hence, SSA is shown to preserve the original code functionality. Hence the encoded WEB-refinement proof obligations can catch bugs in the abstracted code.
(2) Bug 2: we induced another bug in the nonstuttering transition. As shown in Figure 6(a), the instruction STR is writing to the register FIO1SET at the address computed by [r1, #0 × 38]. FIO1SET and FIO1CLR are the two registers that directly change the state of the system with respect to the specification. e instructions that write to these two registers are, therefore, the nonstuttering instructions. We moved incorrect data to FIO1SET, which changed the system state from s 0 to s 3 (as shown in Figure 6(b)).
is transition is not given in specification TS (STS PM in Figure 3); therefore, it was a bug in the implementation.
e SSA tool does not abstract these nonstuttering instructions preserving the original code behavior. e proof obligations for these two instructions caught the error and counterexamples were generated. With the help of counterexamples, we can fix the bugs in the implementation.

Verification Effort Improvement
In refinement-based verification, it is required to write the proof for each assembly instruction. When SSA is applied, the numbers of assembly instructions are reduced and, consequently, the verification effort is reduced. We describe the verification of a piece of assembly code for our case study. Let us consider a three-line code fragment from the original object program as shown in Figure 7.
e SSA tool abstracts this code fragment into a single merger and replaces every occurrence of this multiline code in the original program by a single merger. is merger actually preserves the original function of code and, in the context of verification effort, it reduces the redundancy in proving the correctness of stuttering instructions. So, in this case, instead of generating three proof files, only one file is needed to be generated. e MOVS instruction updates register r0 with a constant value; L DR instruction adds a constant to PC value and loads the value placed at that address to the r1 register. Finally, the STR instruction stores the content of register r0 into memory location computed by e SSA tool merges this operation into a single instruction OMS, which combines the functionality of original set of instructions, eventually producing the same outcome. e proof files are written for the abstracted object code including merged (stuttering) and nonmerged instructions. Due to the space constraints, we are presenting the proof obligation for only the above abstracted instructions as given below. e proof obligations for all generated mergers are written in a similar manner with their own specific conditions: where S C � V c�0 5 s c in the specification STS PM . w is the current implementation state and v is its successor. e precondition checks the current values of peripheral registers and postcondition checks that the implementation is stuttering. is proof obligation checks the correctness of merger instruction bypassing the redundant verification checks. For all other mergers in the SSA abstracted code, the same method is employed to write the proof obligations. We have developed proof obligations for all the reachable states of implementation using case analysis. e proof obligations for nonstuttering transitions are similar to those developed in [24].
Another noticeable fact is that the state of implementation system maps to the same specification state before and after the merger instruction. erefore, the proof obligations for mergers also back the concept that mergers only combine the stuttering instructions.  e implementation state before and after the merger in abstracted code maps to the same specification state: where M erger is the set containing mergers in SSA abstracted code and is shown in Table 1 for our case study.
is theorem can be proved for any SSA abstracted code using proof by cases. We have developed proof obligations by considering all possible cases in the implementation of the pacemaker, which are justified by the specification. In actual object code, several repetitive code fragments can be abstracted by SSA and replaced by respective mergers. Consequently, the large state space is reduced, which makes the verification of object code efficient. e implementation of the pacemaker control program has several numbers of assembly instructions. e specification TS STS PM is nondeterministic and it has different paths. e implementation of a pacemaker is a real-time system that can actually take different paths on run-time. We have considered all such possible paths that can occur during the run-time of object code for this case. Each path taken by the control program or object code has a different length, depending on branches and input behavior. e input-dependent behavior in specification STS PM is implemented with interrupts. We applied SSA on every path of the program to see the difference after abstraction. e reduction in the size of implementation TS is depicted in terms of the number of transitions along each path in Table 3. ere are 4 different paths that this specific implementation (object code) can go through with and without the input interrupt. In hardware, there are actually millions of transitions because, at every clock cycle of the controller, the object code is executed and the system state is defined. Along each path, SSA combines the stuttering instructions and reduces the length of object code between two successive states that map to two successive states of the specification. For example, let us consider path 1 in Table 3.
For this path, there are 3 state transitions, with different interrupt sources (s 0 , s 0 ), (s 0 , s 1 ), and (s 1 , s 5 ). We can see in the last row of Table 3 that, in all three state transitions, the numbers of implementation transitions are reduced by almost 50%. A similar effect can be seen in the state transitions of path 2, path 3, and path 4. e table depicts the effect of SSA on all the possible code paths that the pacemaker code can take in real time. e substantial reduction in implementation TS can be observed in Table 3, which ultimately decreases the efforts involved in formal verification of the object code. Figure 8 shows some statistics obtained while proving the correctness by the theorem prover. It is obvious through the plots that the SSA abstracted object code (mergers) takes  Our results also indicate an obvious improvement in terms of time taken by the proofs. e graph plot in Figure 9 shows the time taken in proving the original code fragments and the SSA merged code. It can be clearly observed that the mergers take lesser time in verifying proofs as compared to the original instructions proofs.

Conclusion and Future Work
Verification of object code involves significant overhead in terms of time and efforts, and it is at the same time demanding because of safety concerns. Even in aerospace engineering, only the important safety-critical modules (which are usually the subsets of a whole application) are nominated for object code verification because of the complexity involved. is practice may leave underlying loopholes that can lead to program failure in some cases and eventually lead to unwanted consequences. We propose an approach to abstract the object code statically known as Static Stuttering Abstraction (SSA). It reduces the large size of object code program. e repetitive segments or groups of commands are sorted throughout the program code and combined into an abstract instruction known as merger. e program function is not altered after SSA even during the occurrence of branches or jumps in the original program code. is has been illustrated with the help of Table 3, where SSA is applied on different paths depending on different branching behaviors on run-time. All of these different paths in implementation have been verified to be correct after SSA. e proposed technique (SSA) contributes to the acceleration of refinement-based verification. Our abstraction technique is targeted for a very large state space like object code. SSA in our case study reduced the code size by 41% in LPC1768 controller and by 23% in Atmega328p controller as shown in Table 2. e difference in the code size reduction is because of two different ISA of two different controllers. e authors in [24] have applied the WFS refinement-based verification without abstraction. Each proof obligation generated by [24] has several associated proof files, depending on the number of object code instructions, which are discharged into Z3. SSA reduces the number of instructions so the numbers of proof files to be generated are reduced significantly. Consequently, the reduced manual efforts help to integrate a detailed and complete coverage of object code verification. In medical domain specifically, object code verification has become inevitable and commercially justified. We verified pacemaker case study and compared our results to [24]. e graph in Figure 9 depicts the comparison of time taken by theorem prover to verify a set of instructions in a pattern in original object code and its merger in updated object code. It is evident that the verification time has been considerably reduced after SSA for each original code fragment. e type of instruction patterns and number of mergers generated for LPC1768-based pacemaker object code are shown in Table 1. e first column of Table 3 shows the repetitive instruction patterns identified by SSA in original code. e second and third columns show the number of lines in the pattern and the number of times the pattern occurs in original code, respectively. e fourth column shows the original instructions opcode. e merger label and merger ASCII opcode are given in the fifth and sixth columns, respectively. e last column shows the binary opcode for merger. We identified fifteen patterns and obtained fifteen mergers for this particular object code implementation. Previously, many abstraction-based techniques have been designed for model checking but none of them targeted object code of a realtime application.
In the future, we intend to combine static and dynamic stuttering abstraction techniques and evaluate the efficacy of the cascaded technique. Dynamic stuttering abstraction is the symbolic simulation of an object code to obtain a reduced state transition system implementation of dynamic stuttering abstraction after the implementation of SSA is expected to solve the problem of an extremely large state space. We also plan to work on automating the WEB refinement process for equivalence checking between specification and implementation, which will eventually aid the refinement process by reducing the time and effort involved in the verification of the object code.

Data Availability
e data used to support the findings of this study are included within the article. In addition, in order to better share the research results, the codes related to the designed SSA tool are available from the corresponding author upon request.
Disclosure e contents do not necessarily reflect the views of the United States Government.

Conflicts of Interest
e authors declare that there are no conflicts of interest.