Function | Package: excl | ToC | DocOverview | CGDoc | RelNotes | FAQ | Index | PermutedIndex
| Allegro CL version 10.1 Unrevised from 10.0 to 10.1. 10.0 version

## validate-lisp-source

Arguments: function &optional reachable (ordering t)trace

Source-level debug info is propagated from the source all the way through the compilation of a function, and depending on the compexity of the function this information can become garbled along the way, due to reorderings, optimizations, implementation strategies, or simply high function complexity.

This function returns the number of problems seen after analyzing the source-level-debug info for function. If trace is given and true, progress will be printed verbosely whenever searching for a path from one program counter in the function to another. Program counters are always relative to the start of the function, beginning with 0. Function can be a function or closure object, or it can be any fboundp function spec.

The current validation styles available currently are reachable and ordering. Note that ordering defaults to true, and reachable defaults to `nil`. It is much more likely that a function will have problems with reachablity than with ordering, so a quick test for gross errors would be something like

     (validate-lisp-source 'foo)

If you want to validate only reachable problems, use

     (validate-lisp-source 'foo t nil)

and if you want all validations, use

     (validate-lisp-source 'foo t)

validate-lisp-source is highly compute-intensive. You can demonstrate this by calling with the trace argument non-`nil`.

### Source record validation concepts

A Lisp source record is identified by its index, and it contains a number of fields which are important to validation and which can be seen by using print-function-meta-info:

- The next and branch fields: labelled "nxt" and "br", respectively, in the print-function-meta-info output, these fields specify one or more indexes each indicating where execution might continue from here.
- The parent/child fields: Like the next and branch fields, the parent ("par") and child ("chld") fields are each an index, indicating a macroexpansion relationship. The child field indicates that this record is a macro form: the child field indexes the record which represents the form this form expanded to (each expansion is a single macroexpansion, as with macroexpand-1 or excl::compiler-macroexpand-1). The parent field indexes the parent, and each pair always reference each other. If the child record is also a macro form, it will also have a child record which indexes a third record, which will in turn point back to it via the parent field.
- The pc, next-pc, and branch-pc fields: Labelled "pc", "nxt", and "br" in the second half of each record in print-function-meta-info output, these values are actual relative program-counter values. A record has only one pc field, and may have 0 or more next-pc and branch-pc fields, depending on the branch-type.
- The entry-type field: this field describes in a keyword what kind of record this is. `nil` in this field means that there is no special consideration for this record. A non-exhaustive list of entry-types is:
  - `:ref` - A variable is being referenced.
  - `:call` - A call to a function is about to occur; arguments have already been placed.
  - `:early` - A call to a function is being considered, but arguments have not yet been placed.
  - `:clone` - assembler code has split off into two or more branches in implementing this form, and this record is a copy of a previous record.
  - `:init` - This record represents the storing of an initialization form into a variable being bound by a let form.
  - `:setq` - A variable is about to be setq'd.
- The branch-type field: this field describes what the branching characteristics are of this record. If the field is nil, then no branching occurs; the record only contains one next or branch field, and thus only one next-pc or branch-pc field. A non-exhaustive list of branch-types is:
  - `:bcc` - Branch on Condition Code: A decision will be made whether to branch or not. A next and branch field will always be present.
  - `:jmp` - branch unconditionally: Usually the branch/branch-pc fields will point to the target record/pc, and there will be no next/next-pc fields.
  - `:call` - A call to a function. The function is determined by what is in the function name register, and a decision about whether to break at the beginning of that function is determined by the step type. The next fields will be filled in with the next record after the call, unless it is a tail-call.
  - `:ret` - This record is a return record; there are no next or branch fields.
  - `:case` - This record represents a table-calculated jump, which may have next fields but always has multiple branch fields.
  - `:noreturn` - This record represents dead code, which will not be returned to (e.g. by a tail call).

The current validations are:

- ordering: This validation ensures that the pc, next-pc, and branch-pc fields are consistent with the record and its next and branch fields. Inconsistencies might result in the sudden loss of stopping while single-stepping, as the stepper sets only breakpoints where the code is likely to hit, moving forward from the currently-stopped record. For example, if Record 3 has pc=27, and it has a next record index of 4 but record 4 has a pc of 25, then record 3 will also have a next-pc of 25, and stepping from record 3 to record 4 will not stop when desired because the breakpoint has been set "behind" the current breakpoint. Some error messages that might be seen:
  - "pc is missing." This occurs when the compiler has not properly propagated the source record all the way to the in-core assembler, which should then assign a program counter to the record.
  - "bcc: one of next-pc (~d) or branch-pc (~d) is missing." This occurs sometimes in high optimization and complex code situations, where perhaps both branches to a decision point go to the same place
  - "no next or branch pc" Unless this is dead code, the record should always have at least one next-pc or branch-pc
  - "next-pc (~d) doesn't follow pc (~d)" The next-pc field of this record represents a point "earlier" in the program execution order. The next-pc might not be actually larger in value than the current pc, but as long as the next-pc can be reached by jumping and/or branching starting at this pc, this error will not be flagged.
- reachable: This validation ensures that a reverse mapping from pc to record number finds a record whose source actually correponds to the instruction at that pc. Failure for a pc to be reachable by the source record which caused it will sometimes result in a breakpoint being set in an unexpected location.

Condsider the following scenario with a function #'bas on some imaginary architecture:

    Record: 23 ... next: 24  ... pc: 120  next-pc: 95 form: (foo x)
    Record: 24 ... next: 25  ... pc: 95 ...           form: (bar (foo x))

Record 23 has been placed after record 24, so it has a higher pc value.

If we intersperse source and assembler records (a truncated version of what (print-function-meta-info 'bas :mixed t) would print), then we might have something like this:

    Record 24: pc: 95  ... form: (bar (foo x))
       95: call bar
       98: ...

    Record 10: pc: 112 ... form: (/ z 0)
       112: load r1, z-in-memory
       117: jmp 128
    Record 23: pc: 120  ...  form: (foo x)
       120: call foo
       125: jmp 95
       128: div 0
       133: ...
    Record 40...

If for some reason (such as a divide by 0) an error occurs at the instruction at 128, then the :zoom command would look at the pc at 128 and (incorrectly) associated it with record 23, instead of associating it with record 10 as it should. This is because the segment of code between 128 and 133 is not assocated with the source record it should be, and thus the instructions ar 128 and 133 are "not reachable" by record 23. Note the jump at 125 which is a good indicator of such a problem - a jump instruction without a source record immediately following will always result in a reachable failure.

The message in the example situation above will be

    Record 23 at pc: 120: (foo x)
      pc 133 doesn't follow record.

Copyright (c) 1998-2022, Franz Inc. Lafayette, CA., USA. All rights reserved.
This page was not revised from the 10.0 page.
Created 2019.8.20.

|  | ToC | DocOverview | CGDoc | RelNotes | FAQ | Index | PermutedIndex
| Allegro CL version 10.1 Unrevised from 10.0 to 10.1. 10.0 version