Let’s get started…
We previously considered a bank that was managing only one account. Now suppose that this example has been extended to support several accounts and transactions between these accounts:
package Accounts is type Customer is (Alice, Bob); procedure Open_Account (C : Customer; Cash : Integer); procedure Pay (From, To : Customer; Cash : Integer); end Accounts;
To check that no accounts are opened twice and that transactions only happen on opened accounts, we need to keep a record of the accounts that have been opened already. When we only had one account, the state was a simple Boolean variable; now it is a list of accounts, which is more complicated to express with only convenience variables. The Python interface of GDB can be used to bypass this limitation.
As a first step, let’s describe the whole program. It contains a main procedure that opens two accounts and schedules a set of transactions between them:
with Accounts; use Accounts; procedure P is begin Open_Account (Alice, 50); Open_Account (Bob, 40); Pay (From => Bob, To => Alice, Cash => 45); Pay (From => Alice, To => Bob, Cash => 20); Pay (From => Bob, To => Alice, Cash => 45); Pay (From => Alice, To => Bob, Cash => 20); end P;
As for the body of Accounts, it offers no difficulty. Oddly enough, it hides a transaction in its elaboration:
package body Accounts is type Account is limited record Balance : Integer; end record; Bank : array (Customer) of Account; procedure Open_Account (C : Customer; Cash : Integer) is begin Bank (C).Balance := Cash; end Open_Account; procedure Pay (From, To : Customer; Cash : Integer) is begin Bank (To).Balance := Bank (To).Balance + Cash; Bank (From).Balance := Bank (From).Balance - Cash; end Pay; -- At elaboration time, a suspicious operation is scheduled; -- Alice secretly pays a bribe to Bob: begin Pay (From => Alice, To => Bob, Cash => 20); end Accounts;
We will now implement, in Python, two hooks that should be executed whenever an operation on an account is scheduled. Create a new file named hooks.py with the following code:
current_customers =  def open_account_hook(): global current_customers c = str(gdb.parse_and_eval('c')) if c in current_customers: print "error: account initialized twice" else: print "(info) %s opens an account" % c current_customers.append(c) gdb.execute("continue") def pay_hook(): global current_customers f = str(gdb.parse_and_eval('from')) t = str(gdb.parse_and_eval('to')) if not f in current_customers: print "error: %s tries to pay before opening an account" % f elif not t in current_customers: print "error: %s cannot be paid before opening an account" % t else: cash = str(gdb.parse_and_eval('cash')) print "(info) %s gives %s $%s" % (f, t, cash) gdb.execute("continue")
This defines three entities: a global list that records the accounts that have been opened already, and two hooks to be executed when Open_Account and Pay are called.
Both get the value of the parameters using the function gdb.parse_and_eval (defined in the Python API) to check that the operation is valid. The documentation of this function, as well as the documentation of any Python entities, can be accessed from GDB using Python’s command-line help:
(gdb) python help(gdb.parse_and_eval) Help on built-in function parse_and_eval in module gdb: parse_and_eval(...) parse_and_eval (String) -> Value. Parse String as an expression, evaluate it, and return the result as a Value.
Now, we just need to register these commands in GDB using the source command and attach them to their corresponding breakpoints.
(gdb) source hooks.py (gdb) break open_account Breakpoint 1 at 0x4015b4: file accounts.adb, line 11. (gdb) commands >python open_account_hook() >end (gdb) break pay Breakpoint 2 at 0x4015f6: file accounts.adb, line 16. (gdb) commands >python pay_hook() >end
This detects that the first transaction is indeed invalid, as it happens before the accounts are opened:
(gdb) run Starting program: C:\home\guitton\GIT\GDB\builds\gems\3\p.exe [New Thread 1872.0x638] Breakpoint 2, accounts.pay (from=alice, to=bob, cash=20) at accounts.adb:16 16 Bank (To).Balance := Bank (To).Balance + Cash; error: alice tries to pay before opening an account
The Python API provides an advanced programming interface for GDB, with facilities for browsing through backtraces, threads, symbols, etc. For more information, we invite you to consult the dedicated section on those features in the GDB user’s guide.
- breakpoint_commands_2.zip - (2 KB)