From 3aa6936977078eaccc404373d2f9955f5588de51 Mon Sep 17 00:00:00 2001
From: Olivier Hainque <hainque@adacore.com>
Date: Fri, 6 Oct 2017 11:29:17 +0200
Subject: [PATCH 01/16] Update .gitreview for the 18.0 branch

Part of QA03-039

Change-Id: Idbbbb1907653e82a623e1a929c1ffc1982d73174
---
 .gitreview | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitreview b/.gitreview
index a5d94509a..f90352860 100644
--- a/.gitreview
+++ b/.gitreview
@@ -2,5 +2,5 @@
 host = git.adacore.com
 port = 29418
 project = gnatcoverage
-defaultbranch = master
+defaultbranch = 18.0
 defaultremote = origin

From 1a482347273011da5316fba75081b5905bf56334 Mon Sep 17 00:00:00 2001
From: Olivier Hainque <hainque@adacore.com>
Date: Sat, 21 Oct 2017 21:34:20 +0200
Subject: [PATCH 02/16] update ref branch in .gitreviw for 18.1

Part of QA19-079

Change-Id: I71343ab333c18cbb1162a1f41c6846d8ddd846f3
---
 .gitreview | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitreview b/.gitreview
index f90352860..5f8728433 100644
--- a/.gitreview
+++ b/.gitreview
@@ -2,5 +2,5 @@
 host = git.adacore.com
 port = 29418
 project = gnatcoverage
-defaultbranch = 18.0
+defaultbranch = 18.1
 defaultremote = origin

From 6977b56d9d43524b0ee445b50e5725858a1409f2 Mon Sep 17 00:00:00 2001
From: Olivier Hainque <hainque@adacore.com>
Date: Tue, 24 Oct 2017 11:03:32 +0200
Subject: [PATCH 03/16] Special processing for pragmas not generating code

Just not considering them as actual statements, as we were already doing
for pragma Annotate.

This prevents the production of meanlingless diagnostics
such as "statement never executed" on e.g. pragma Pure, which helps
readbility and reduces potential confusion.

Part of QA23-039

Change-Id: I08de62ecbf3bef083eb5556b28c4575f4808900b
(cherry picked from commit 6a07b7221b26151dc27e3b6aebc3a4d461bc262f)
---
 tools/gnatcov/coverage-source.adb |  16 +-
 tools/gnatcov/sc_obligations.adb  |  85 +++++----
 tools/gnatcov/sc_obligations.ads  | 294 +++++++++++++++++++++++++++++-
 3 files changed, 339 insertions(+), 56 deletions(-)

diff --git a/tools/gnatcov/coverage-source.adb b/tools/gnatcov/coverage-source.adb
index 685ad4650..16e1603f9 100644
--- a/tools/gnatcov/coverage-source.adb
+++ b/tools/gnatcov/coverage-source.adb
@@ -343,17 +343,11 @@ package body Coverage.Source is
                   --  Statement coverage: line is covered if any associated
                   --  statement is executed.
 
-                  if Is_Pragma_Annotate (SCO)
-                    or else Is_Disabled_Statement (SCO)
-                  then
-                     --  A disabled statement (i.e. a pragma Assert/Debug/PPC
-                     --  that is not enabled) or a pragma Annotate are known
-                     --  and intended to not generate any executable code. They
-                     --  are treated as documentation items in source, and are
-                     --  not subject to coverage discussion: they are neither
-                     --  covered nor not-covered, and need not be reported as
-                     --  bona fide statements excluded from coverage analysis
-                     --  either (see below case).
+                  if Ignore_SCO (SCO) then
+
+                     --  They are neither covered nor not-covered, and need
+                     --  not be reported as bona fide statements excluded from
+                     --  coverage analysis either (see below case).
 
                      null;
 
diff --git a/tools/gnatcov/sc_obligations.adb b/tools/gnatcov/sc_obligations.adb
index 7442c11d8..09470fc9b 100644
--- a/tools/gnatcov/sc_obligations.adb
+++ b/tools/gnatcov/sc_obligations.adb
@@ -35,7 +35,6 @@ with Interfaces;
 with Namet;         use Namet;
 with Outputs;       use Outputs;
 with SCOs;
-with Snames;        use Snames;
 with Strings;       use Strings;
 with Switches;      use Switches;
 with Traces_Elf;    use Traces_Elf;
@@ -2158,6 +2157,54 @@ package body SC_Obligations is
       return Has_SCO (Statement) or else Has_SCO (Condition);
    end Has_SCO;
 
+   ----------------
+   -- Ignore_SCO --
+   ----------------
+
+   function Ignore_SCO (SCO : SCO_Id) return Boolean is
+
+      Result : Boolean;
+
+      procedure Q (SCOD : SCO_Descriptor);
+      --  Set Result from the given SCO descriptor, accessed in-place
+      --  from SCO_Vector.
+
+      procedure Q (SCOD : SCO_Descriptor) is
+      begin
+         --  We ignore remnants of internal processing phases which leave
+         --  dummy SCO entries in SCO_Vector, as well as SCOs for pragmas
+         --  known not to generate code, as they are not really statements in
+         --  the Ada sense and need not be assessed for coverage.
+
+         Result :=
+           --  Not a real SCO any more ?
+
+           SCOD.Origin = No_CU_Id
+
+           or else
+
+           --  Pragma not generating code ?
+
+           (SCOD.S_Kind = Pragma_Statement
+              and then not Pragma_Might_Generate_Code (SCOD.Pragma_Name))
+
+           or else
+
+           --  Disabled pragma ?
+
+           SCOD.S_Kind = Disabled_Pragma_Statement;
+
+      end Q;
+
+   --  Start of processing for Ignore_SCO
+
+   begin
+      pragma Assert (Kind (SCO) = Statement);
+
+      SCO_Vector.Query_Element (SCO, Q'Access);
+      return Result;
+   end Ignore_SCO;
+
    -----------
    -- Image --
    -----------
@@ -2281,18 +2328,6 @@ package body SC_Obligations is
       end case;
    end Is_Assertion;
 
-   ---------------------------
-   -- Is_Disabled_Statement --
-   ---------------------------
-
-   function Is_Disabled_Statement (SCO : SCO_Id) return Boolean is
-      SCOD  : SCO_Descriptor renames SCO_Vector (SCO);
-   begin
-      pragma Assert (SCOD.Kind = Statement);
-      return SCOD.S_Kind = Disabled_Pragma_Statement
-               or else SCOD.Origin = No_CU_Id;
-   end Is_Disabled_Statement;
-
    -------------------
    -- Is_Expression --
    -------------------
@@ -2363,30 +2398,6 @@ package body SC_Obligations is
       end;
    end Is_Expression;
 
-   ------------------------
-   -- Is_Pragma_Annotate --
-   ------------------------
-
-   function Is_Pragma_Annotate (SCO : SCO_Id) return Boolean is
-      Result : Boolean;
-
-      procedure Q (SCOD : SCO_Descriptor);
-      --  Set Result
-
-      procedure Q (SCOD : SCO_Descriptor) is
-      begin
-         Result := SCOD.S_Kind = Pragma_Statement
-           and then SCOD.Pragma_Name = Pragma_Annotate;
-      end Q;
-
-   --  Start of processing for Is_Pragma_Annotate
-
-   begin
-      pragma Assert (Kind (SCO) = Statement);
-      SCO_Vector.Query_Element (SCO, Q'Access);
-      return Result;
-   end Is_Pragma_Annotate;
-
    ----------------------------------
    -- Is_Pragma_Pre_Post_Condition --
    ----------------------------------
diff --git a/tools/gnatcov/sc_obligations.ads b/tools/gnatcov/sc_obligations.ads
index cd270f3f7..124fb5a5b 100644
--- a/tools/gnatcov/sc_obligations.ads
+++ b/tools/gnatcov/sc_obligations.ads
@@ -27,6 +27,7 @@ limited with Checkpoints;
 with Slocs;       use Slocs;
 with Traces;      use Traces;
 with Types;       use Types;
+with Snames;      use Snames;
 
 package SC_Obligations is
 
@@ -193,12 +194,6 @@ package SC_Obligations is
    function S_Kind (SCO : SCO_Id) return Any_Statement_Kind;
    --  Return the statement kind for SCO, or No_Statement for No_SCO_Id.
 
-   function Is_Disabled_Statement (SCO : SCO_Id) return Boolean;
-   --  True for a disabled statement, i.e. a statement that is guaranteed to
-   --  never generate any code and is excluded from the scope of coverage
-   --  analysis. Also True for a dummy entry that results from cancelling an
-   --  irrelevant SCO.
-
    function Previous (SCO : SCO_Id) return SCO_Id;
    --  Previous statement in basic block
 
@@ -214,8 +209,12 @@ package SC_Obligations is
    --    * If Dom_SCO is a decision, it is guaranteed to have been evaluated
    --      with value Dom_Val.
 
-   function Is_Pragma_Annotate (SCO : SCO_Id) return Boolean;
-   --  True if SCO is for a pragma Annotate
+   function Ignore_SCO (SCO : SCO_Id) return Boolean;
+   --  True if we ignore the provided SCO for coverage purposes, typically for
+   --  pragmas (not real Ada statements in the first place) known not to
+   --  generate any executable code, which may be treated as a documentation
+   --  item in the source. The input SCO argument is expected to designate a
+   --  statement SCO.
 
    function Is_Pragma_Pre_Post_Condition (SCO : SCO_Id) return Boolean;
    --  True if SCO is for a pragma Pre/Postcondition
@@ -311,4 +310,283 @@ package SC_Obligations is
       CS : access Checkpoints.Checkpoint_State);
    --  Load checkpointed SCOs from S and merge them in current state
 
+private
+
+   --  For each pragma we know of, weather an occurrence of the pragma in the
+   --  source might generated code of its own, e.g. pragma Precondition.
+
+   --  This table is used to determine if a statement SCO attached to such a
+   --  pragma may be ignored for coverage analysis purposes. Note that
+   --  activation or deactivation (e.g. for assert-like pragmas controlled by
+   --  -gnata or configuration) is treated separately. Pragmas which do
+   --  generate code when activated should be listed as Might_Generate_Code
+   --  here, regardless of their actual activation status.  Conversely,
+   --  pragmas that only influence code generation performed otherwise (e.g.
+   --  pragma Inline) should be listed as not Might_Generate_Code.
+
+   Pragma_Might_Generate_Code : constant array (Pragma_Id) of Boolean
+     := ( --  Configuration pragmas
+
+          Pragma_Ada_83 => False,
+          Pragma_Ada_95 => False,
+          Pragma_Ada_05 => False,
+          Pragma_Ada_2005 => False,
+          Pragma_Ada_12 => False,
+          Pragma_Ada_2012 => False,
+          Pragma_Ada_2020 => False,
+
+          Pragma_Allow_Integer_Address => False,
+          Pragma_Annotate => False,
+          Pragma_Assertion_Policy => False,
+          Pragma_Assume_No_Invalid_Values => False,
+          Pragma_C_Pass_By_Copy => False,
+          Pragma_Check_Float_Overflow => False,
+          Pragma_Check_Name => False,
+          Pragma_Check_Policy => False,
+          Pragma_Compile_Time_Error => False,
+          Pragma_Compile_Time_Warning => False,
+          Pragma_Compiler_Unit => False,
+          Pragma_Compiler_Unit_Warning => False,
+          Pragma_Component_Alignment => False,
+          Pragma_Convention_Identifier => False,
+          Pragma_Debug_Policy => False,
+          Pragma_Detect_Blocking => False,
+          Pragma_Default_Storage_Pool => False,
+          Pragma_Disable_Atomic_Synchronization => False,
+          Pragma_Discard_Names => False,
+          Pragma_Elaboration_Checks => False,
+          Pragma_Eliminate => False,
+          Pragma_Enable_Atomic_Synchronization => False,
+          Pragma_Extend_System => False,
+          Pragma_Extensions_Allowed => False,
+          Pragma_External_Name_Casing => False,
+          Pragma_Favor_Top_Level => False,
+          Pragma_Ignore_Pragma => False,
+          Pragma_Implicit_Packing => False,
+          Pragma_Initialize_Scalars => False,
+          Pragma_Interrupt_State => False,
+          Pragma_License => False,
+          Pragma_Locking_Policy => False,
+          Pragma_No_Component_Reordering => False,
+          Pragma_No_Heap_Finalization => False,
+          Pragma_No_Run_Time => False,
+          Pragma_No_Strict_Aliasing => False,
+          Pragma_Normalize_Scalars => False,
+          Pragma_Optimize_Alignment => False,
+          Pragma_Overflow_Mode => False,
+          Pragma_Overriding_Renamings => False,
+          Pragma_Partition_Elaboration_Policy => False,
+          Pragma_Persistent_BSS => False,
+          Pragma_Polling => False,
+          Pragma_Prefix_Exception_Messages => False,
+          Pragma_Priority_Specific_Dispatching => False,
+          Pragma_Profile => False,
+          Pragma_Profile_Warnings => False,
+          Pragma_Propagate_Exceptions => False,
+          Pragma_Queuing_Policy => False,
+          Pragma_Rational => False,
+          Pragma_Ravenscar => False,
+          Pragma_Rename_Pragma => False,
+          Pragma_Restricted_Run_Time => False,
+          Pragma_Restrictions => False,
+          Pragma_Restriction_Warnings => False,
+          Pragma_Reviewable => False,
+          Pragma_Short_Circuit_And_Or => False,
+          Pragma_Short_Descriptors => False,
+          Pragma_Source_File_Name => False,
+          Pragma_Source_File_Name_Project => False,
+          Pragma_SPARK_Mode => False,
+          Pragma_Style_Checks => False,
+          Pragma_Suppress => False,
+          Pragma_Suppress_Exception_Locations => False,
+          Pragma_Task_Dispatching_Policy => False,
+          Pragma_Unevaluated_Use_Of_Old => False,
+          Pragma_Universal_Data => False,
+          Pragma_Unsuppress => False,
+          Pragma_Use_VADS_Size => False,
+          Pragma_Validity_Checks => False,
+          Pragma_Warning_As_Error => False,
+          Pragma_Warnings => False,
+          Pragma_Wide_Character_Encoding => False,
+
+          --  Remaining (non-configuration) pragmas, not generating code first
+
+          Pragma_Abort_Defer => False,
+          Pragma_Abstract_State => False,
+          Pragma_All_Calls_Remote => False,
+          Pragma_Async_Readers => False,
+          Pragma_Async_Writers => False,
+          Pragma_Asynchronous => False,
+          Pragma_Atomic => False,
+          Pragma_Atomic_Components => False,
+          Pragma_Attach_Handler => False,
+          Pragma_Attribute_Definition => False,
+          Pragma_Check => False,
+          Pragma_Comment => False,
+          Pragma_Common_Object => False,
+          Pragma_Complete_Representation => False,
+          Pragma_Complex_Representation => False,
+          Pragma_Constant_After_Elaboration => False,
+          Pragma_Controlled => False,
+          Pragma_Convention => False,
+          Pragma_CPP_Class => False,
+          Pragma_CPP_Constructor => False,
+          Pragma_CPP_Virtual => False,
+          Pragma_CPP_Vtable => False,
+          Pragma_Deadline_Floor => False,
+          Pragma_Default_Initial_Condition => False,
+          Pragma_Depends => False,
+          Pragma_Effective_Reads => False,
+          Pragma_Effective_Writes => False,
+          Pragma_Elaborate => False,
+          Pragma_Elaborate_All => False,
+          Pragma_Elaborate_Body => False,
+          Pragma_Export => False,
+          Pragma_Export_Function => False,
+          Pragma_Export_Object => False,
+          Pragma_Export_Procedure => False,
+          Pragma_Export_Value => False,
+          Pragma_Export_Valued_Procedure => False,
+          Pragma_Extensions_Visible => False,
+          Pragma_External => False,
+          Pragma_Finalize_Storage_Only => False,
+          Pragma_Ghost => False,
+          Pragma_Global => False,
+          Pragma_Ident => False,
+          Pragma_Implementation_Defined => False,
+          Pragma_Implemented => False,
+          Pragma_Import => False,
+          Pragma_Import_Function => False,
+          Pragma_Import_Object => False,
+          Pragma_Import_Procedure => False,
+          Pragma_Import_Valued_Procedure => False,
+          Pragma_Independent => False,
+          Pragma_Independent_Components => False,
+          Pragma_Initial_Condition => False,
+          Pragma_Initializes => False,
+          Pragma_Inline => False,
+          Pragma_Inline_Always => False,
+          Pragma_Inline_Generic => False,
+          Pragma_Inspection_Point => False,
+          Pragma_Interface_Name => False,
+          Pragma_Interrupt_Handler => False,
+          Pragma_Keep_Names => False,
+          Pragma_Link_With => False,
+          Pragma_Linker_Alias => False,
+          Pragma_Linker_Constructor => False,
+          Pragma_Linker_Destructor => False,
+          Pragma_Linker_Options => False,
+          Pragma_Linker_Section => False,
+          Pragma_List => False,
+          Pragma_Loop_Optimize => False,
+          Pragma_Loop_Variant => False,
+          Pragma_Machine_Attribute => False,
+          Pragma_Main => False,
+          Pragma_Main_Storage => False,
+          Pragma_Max_Queue_Length => False,
+          Pragma_Memory_Size => False,
+          Pragma_No_Body => False,
+          Pragma_No_Elaboration_Code_All => False,
+          Pragma_No_Inline => False,
+          Pragma_No_Return => False,
+          Pragma_No_Tagged_Streams => False,
+          Pragma_Obsolescent => False,
+          Pragma_Optimize => False,
+          Pragma_Ordered => False,
+          Pragma_Pack => False,
+          Pragma_Page => False,
+          Pragma_Part_Of => False,
+          Pragma_Passive => False,
+          Pragma_Predicate_Failure => False,
+          Pragma_Preelaborable_Initialization => False,
+          Pragma_Preelaborate => False,
+          Pragma_Provide_Shift_Operators => False,
+          Pragma_Psect_Object => False,
+          Pragma_Pure => False,
+          Pragma_Pure_Function => False,
+          Pragma_Refined_Depends => False,
+          Pragma_Refined_Global => False,
+          Pragma_Refined_State => False,
+          Pragma_Relative_Deadline => False,
+          Pragma_Remote_Access_Type => False,
+          Pragma_Remote_Call_Interface => False,
+          Pragma_Remote_Types => False,
+          Pragma_Share_Generic => False,
+          Pragma_Shared => False,
+          Pragma_Shared_Passive => False,
+          Pragma_Simple_Storage_Pool_Type => False,
+          Pragma_Source_Reference => False,
+          Pragma_Static_Elaboration_Desired => False,
+          Pragma_Stream_Convert => False,
+          Pragma_Subtitle => False,
+          Pragma_Suppress_All => False,
+          Pragma_Suppress_Debug_Info => False,
+          Pragma_Suppress_Initialization => False,
+          Pragma_System_Name => False,
+          Pragma_Test_Case => False,
+          Pragma_Task_Info => False,
+          Pragma_Task_Name => False,
+          Pragma_Task_Storage => False,
+          Pragma_Thread_Local_Storage => False,
+          Pragma_Time_Slice => False,
+          Pragma_Title => False,
+          Pragma_Unchecked_Union => False,
+          Pragma_Unimplemented_Unit => False,
+          Pragma_Universal_Aliasing => False,
+          Pragma_Unmodified => False,
+          Pragma_Unreferenced => False,
+          Pragma_Unreferenced_Objects => False,
+          Pragma_Unreserve_All_Interrupts => False,
+          Pragma_Unused => False,
+          Pragma_Volatile => False,
+          Pragma_Volatile_Components => False,
+          Pragma_Volatile_Full_Access => False,
+          Pragma_Volatile_Function => False,
+          Pragma_Weak_External => False,
+
+          Pragma_CPU => False,
+          Pragma_Default_Scalar_Storage_Order => False,
+          Pragma_Dispatching_Domain => False,
+          Pragma_Fast_Math => False,
+          Pragma_Interface => False,
+          Pragma_Interrupt_Priority => False,
+          Pragma_Lock_Free => False,
+          Pragma_Priority => False,
+          Pragma_Secondary_Stack_Size => False,
+          Pragma_Storage_Size => False,
+          Pragma_Storage_Unit => False,
+
+          --  Now pragmas which might generate code. This is an explicit list
+          --  instead of a mere "others" fallback to make sure we notice when
+          --  new pragmas get in the daily compiler from which we build, which
+          --  we expect to be reflected through Snames.
+
+          --  The Unknown case is there to handle situations at run time when
+          --  reading ali files produced by a version of the compiler more
+          --  recent than gnatcov. True is a conservative choice in this case,
+          --  as it will lead gnatcov to flag such pragma as real statements
+          --  even if they actually never generate code.
+
+          Pragma_Assume => True,
+          Pragma_Assert => True,
+          Pragma_Assert_And_Cut => True,
+
+          Pragma_Debug => True,
+          Pragma_Post => True,
+          Pragma_Postcondition => True,
+          Pragma_Post_Class => True,
+          Pragma_Refined_Post => True,
+          Pragma_Pre => True,
+          Pragma_Precondition => True,
+          Pragma_Pre_Class => True,
+          Pragma_Predicate => True,
+          Pragma_Contract_Cases => True,
+
+          Pragma_Loop_Invariant => True,
+          Pragma_Invariant => True,
+          Pragma_Type_Invariant => True,
+          Pragma_Type_Invariant_Class => True,
+
+          Unknown_Pragma => True);
+
 end SC_Obligations;

From eb51b65488b0c0e2b0434de7cbc15ccbaf2071d0 Mon Sep 17 00:00:00 2001
From: Olivier Hainque <hainque@adacore.com>
Date: Tue, 24 Oct 2017 15:18:42 +0200
Subject: [PATCH 04/16] Adjust stmt coverage test expectation on pragma
 No_Return

Now ignored for coverage reporting purposes, per QA23-039

Change-Id: I157021e030576d1e5ddf40a8323866496527fd8d
(cherry picked from commit c14663b4e934540dc0c68af063bd7422a47a7746)
---
 .../stmt/1_Core/06_Subprograms/No_Return/src/test_objects_0.adb  | 1 -
 1 file changed, 1 deletion(-)

diff --git a/testsuite/Qualif/Ada/stmt/1_Core/06_Subprograms/No_Return/src/test_objects_0.adb b/testsuite/Qualif/Ada/stmt/1_Core/06_Subprograms/No_Return/src/test_objects_0.adb
index c7b3be01d..33c9eafa8 100644
--- a/testsuite/Qualif/Ada/stmt/1_Core/06_Subprograms/No_Return/src/test_objects_0.adb
+++ b/testsuite/Qualif/Ada/stmt/1_Core/06_Subprograms/No_Return/src/test_objects_0.adb
@@ -9,7 +9,6 @@ end;
 --# objects.adb
 --  /test/ l- ## s-
 --  /pos/  l- ## s-
---  /pragma/ l- ## s-
 
 -- Old compilers are less precise in tracking
 -- dominance 

From 6908d613faeec1858965560f13c8d10e8a380adf Mon Sep 17 00:00:00 2001
From: Olivier Hainque <hainque@adacore.com>
Date: Wed, 25 Oct 2017 12:32:33 +0200
Subject: [PATCH 05/16] Fix minor glitches in comments

Follow-up adjustments on change just introduced for QA23-039

Change-Id: I5d46be3c8449b0b0f9f6f75b38918e2445676de8
(cherry picked from commit 6952c0a08b137526512b5ac987c59094d40481ea)
---
 tools/gnatcov/sc_obligations.ads | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/gnatcov/sc_obligations.ads b/tools/gnatcov/sc_obligations.ads
index 124fb5a5b..98e7a6eae 100644
--- a/tools/gnatcov/sc_obligations.ads
+++ b/tools/gnatcov/sc_obligations.ads
@@ -312,9 +312,9 @@ package SC_Obligations is
 
 private
 
-   --  For each pragma we know of, weather an occurrence of the pragma in the
-   --  source might generated code of its own, e.g. pragma Precondition.
-
+   --  For each pragma we know of, whether an occurrence of the pragma in the
+   --  source might generate code of its own, e.g. pragma Precondition.
+   --
    --  This table is used to determine if a statement SCO attached to such a
    --  pragma may be ignored for coverage analysis purposes. Note that
    --  activation or deactivation (e.g. for assert-like pragmas controlled by
@@ -560,7 +560,7 @@ private
           --  instead of a mere "others" fallback to make sure we notice when
           --  new pragmas get in the daily compiler from which we build, which
           --  we expect to be reflected through Snames.
-
+          --
           --  The Unknown case is there to handle situations at run time when
           --  reading ali files produced by a version of the compiler more
           --  recent than gnatcov. True is a conservative choice in this case,

From 1af1a9fea0100524ca7e38613d58b8cf31f7b1c6 Mon Sep 17 00:00:00 2001
From: Olivier Hainque <hainque@adacore.com>
Date: Tue, 12 Dec 2017 18:28:28 +0100
Subject: [PATCH 06/16] gnatcov manual: adjust the GPS section to the new GPS
 menu layouts

The Tools main menu morphed into Analyze. Adjust text and redo
screenshots.

Rephrase the paragraph referring to possible warnings in
GNATtest scenarii.

For Q927-033

Change-Id: I198a96f35879d79d85a165ff6978383a4ea5d4db
(cherry picked from commit e6aceba0e31e2737fbc9d16160548045fcb634c6)
---
 tools/gnatcov/doc/umanual/gps.rst             |  31 +++++++++---------
 .../gps_screenshots/0-pref-cov-toolchain.png  | Bin 23027 -> 46434 bytes
 .../umanual/gps_screenshots/1-build-mode.png  | Bin 29911 -> 67641 bytes
 .../umanual/gps_screenshots/2-build-mode.png  | Bin 15098 -> 22190 bytes
 .../umanual/gps_screenshots/3-cov-level.png   | Bin 40064 -> 84955 bytes
 .../doc/umanual/gps_screenshots/4-run.png     | Bin 30152 -> 60223 bytes
 .../umanual/gps_screenshots/5-coverage.png    | Bin 31306 -> 58635 bytes
 .../doc/umanual/gps_screenshots/6-report.png  | Bin 11682 -> 24207 bytes
 .../gps_screenshots/7-detailed-report.png     | Bin 36288 -> 47033 bytes
 9 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/tools/gnatcov/doc/umanual/gps.rst b/tools/gnatcov/doc/umanual/gps.rst
index 493ff1ceb..62ee83d1f 100644
--- a/tools/gnatcov/doc/umanual/gps.rst
+++ b/tools/gnatcov/doc/umanual/gps.rst
@@ -20,17 +20,18 @@ will apply to all the other projects you work with in GPS.
 
 The next step is to tell |gps| to build your project for |gcp|, with the
 appropriate compilation options. In order to do this, open the Scenario view
-(:menuselection:`Tools --> Views --> Scenario`).
+(:menuselection:`View --> Scenario`).
 
 .. image:: gps_screenshots/1-build-mode.png
 
-Then, change the Build mode from ``default`` to ``gnatcov``.
+Change the Build mode from ``default`` to ``gnatcov`` and validate by clicking
+the round *tick* icon on the upper left corner of the view window.
 
 .. image:: gps_screenshots/2-build-mode.png
 
 GNATcoverage supports multiple coverage criteria. In order to select which one
-to use, go to the project properties (:menuselection:`Project -->
-Properties...`).
+to use, go to the project properties (:menuselection:`Edit -->
+Project Properties...`).
 
 .. image:: gps_screenshots/3-cov-level.png
 
@@ -39,15 +40,15 @@ and |gcvcov| in the corresponding *Coverage level* combo boxes. Change both to
 ``stmt+decision``.
 
 This is all for the setup part. The |gcvrun| and |gcvcov| steps are available
-for each main unit in the :menuselection:`Tools --> GNATcov` menu. First build
-your program (:menuselection:`Build --> Project --> Build All`), then execute
-the ``GNATcov run`` and the ``GNATcov coverage`` commands.
+for each main unit in the :menuselection:`Analyze --> Coverage --> GNATcov`
+menu. First build your program (:menuselection:`Build --> Project --> Build
+All`), then execute the ``GNATcov run`` and the ``GNATcov coverage`` commands.
 
 .. image:: gps_screenshots/4-run.png
 
 .. image:: gps_screenshots/5-coverage.png
 
-Each entry in the :menuselection:`Tools --> GNATcov --> GNATcov coverage`
+Each entry in the :menuselection:`Analyze --> Coverage --> GNATcov --> GNATcov coverage`
 submenu opens a Coverage Report tab which displays the ratio of source lines
 that are covered.
 
@@ -71,16 +72,16 @@ GNATtest scenario
 
 Using |gcp| |gtest|-based testsuite in |gps| comes naturally as the combination
 of both. Open the project you want to test and then generate the unit test
-setup for it. Using the menu: :menuselection:`Tools --> GNATtest --> Generate
+setup for it. Using the menu: :menuselection:`Analyze --> GNATtest --> Generate
 Unit Test Setup`.
 
 Write your testcases, and when you are ready to run your testsuite, switch to
 the ``gnatcov`` build mode, select the desired coverage criteria in the project
 properties. Now, build your program (:menuselection:`Build --> Project` menu),
-run it and launch a coverage analysis for it (:menuselection:`Tools -->
-GNATcov`).
+run it and launch a coverage analysis for it (:menuselection:`Analyze -->
+Coverage --> GNATcov`).
 
-Logs from |gcp| (in the Messages view) will include warnings which mention the
-various helper projects generated and used by the |gtest| setup, for instance
-AUnit. While this is not a problem for the coverage analysis, we plan to fix
-this so that this report includes only the project you are working on.
+Depending on your version of |gcp|, logs in the Messages view might include
+warnings which mention the various helper projects generated and used by the
+|gtest| setup, for instance AUnit. These should not influence coverage
+analysis results for the units of your project.
diff --git a/tools/gnatcov/doc/umanual/gps_screenshots/0-pref-cov-toolchain.png b/tools/gnatcov/doc/umanual/gps_screenshots/0-pref-cov-toolchain.png
index 411127772da252c3a810602c2178fd124fd96496..ef17b25238ff44530848eb6d42629417b89dedcf 100644
GIT binary patch
diff --git a/tools/gnatcov/doc/umanual/gps_screenshots/1-build-mode.png b/tools/gnatcov/doc/umanual/gps_screenshots/1-build-mode.png
index 31fa4f2e67cc028dd8f4aae3efd15d4452aa4276..d0351f49c8d2529439965f2a66001598b548eb14 100644
GIT binary patch
diff --git a/tools/gnatcov/doc/umanual/gps_screenshots/2-build-mode.png b/tools/gnatcov/doc/umanual/gps_screenshots/2-build-mode.png
index 72b79ab5630cc83103962713174a2ce91561cf77..7694c001e5da2a91531efaa1e73fd6ba7f0783c9 100644
GIT binary patch
diff --git a/tools/gnatcov/doc/umanual/gps_screenshots/3-cov-level.png b/tools/gnatcov/doc/umanual/gps_screenshots/3-cov-level.png
index ba60b477eca1f65f3edc5cb57b2ee31e853b84f1..072ea86c36317ffa65fd9ac784de8c3e53684d58 100644
GIT binary patch
diff --git a/tools/gnatcov/doc/umanual/gps_screenshots/4-run.png b/tools/gnatcov/doc/umanual/gps_screenshots/4-run.png
index 8e7098f970a5f39ce2545781ce14ba819e01bdb3..77db6b37f14c319cc2c7c569a15316540f50fbbf 100644
GIT binary patch
diff --git a/tools/gnatcov/doc/umanual/gps_screenshots/5-coverage.png b/tools/gnatcov/doc/umanual/gps_screenshots/5-coverage.png
index 8d14803a8bb61d2e5f936016f825a3b404888e92..00b337459a65b7f59fea1209f9c6ce0a8939c8e5 100644
GIT binary patch
diff --git a/tools/gnatcov/doc/umanual/gps_screenshots/6-report.png b/tools/gnatcov/doc/umanual/gps_screenshots/6-report.png
index 8b26cb629c3e0b2715d5fa0b56bc342027f9bbe7..5fc3a2bdbb014377b5c0e50a75421ac3a491046a 100644
GIT binary patch
diff --git a/tools/gnatcov/doc/umanual/gps_screenshots/7-detailed-report.png b/tools/gnatcov/doc/umanual/gps_screenshots/7-detailed-report.png
index df4ca021279a1cab0dbdf56f08b9ee1327ecc4e5..5c1b434b73a55799aeed218937fe7098ffb92d87 100644
GIT binary patch

From 0484cac5692cb3fb67764380c3ff4dccb78f6b32 Mon Sep 17 00:00:00 2001
From: Olivier Hainque <hainque@adacore.com>
Date: Wed, 18 Oct 2017 22:14:34 +0200
Subject: [PATCH 07/16] gnatcov: reinstate the "prepare" run target

gnatcov run --target=prepare was meant to let users prepare
for an execution that will just append trace entries to a trace
file, typically by running qemu separately. The preparation
consists in creating the trace file and storing a trace header
there.

This was removed based on the belief that this facility wasn't
used any more. It actually still is relied upon by a few scripts
involved in runtime certification activities, some currently
ongoing.

In the course of QA16-036. Part of QA27-024 for 18.

Change-Id: I719372cf9268d6964ff91d7e6a427acaeede1e09
(cherry picked from commit 00bdac329cc78f268fe94cb774eb56ccd34fbddd)
---
 tools/gnatcov/rundrv-config.adb | 19 +++++++++++++++++++
 tools/gnatcov/rundrv.adb        |  8 ++++++++
 2 files changed, 27 insertions(+)

diff --git a/tools/gnatcov/rundrv-config.adb b/tools/gnatcov/rundrv-config.adb
index 2a4ee789b..57ea608e4 100644
--- a/tools/gnatcov/rundrv-config.adb
+++ b/tools/gnatcov/rundrv-config.adb
@@ -64,6 +64,8 @@ package body Rundrv.Config is
      (Context : Context_Type; Matches : Match_Array) return Command_Access;
    function ISystem
      (Context : Context_Type; Matches : Match_Array) return Command_Access;
+   function Prepare
+     (Context : Context_Type; Matches : Match_Array) return Command_Access;
    function Visium_ELF
      (Context : Context_Type; Matches : Match_Array) return Command_Access;
 
@@ -85,6 +87,7 @@ package body Rundrv.Config is
       (+"(x86|x86_64)-linux",   Native_Linux'Access),
       (+"(x86|x86_64)-windows", Native_Windows'Access),
       (+"iSystem-(5554|5634)",  ISystem'Access),
+      (+"prepare",              Prepare'Access),
       (+"visium-elf",           Visium_ELF'Access));
    --  For each target category, this table provides a target triples
    --  (without board name) pattern and a function to create the corresponding
@@ -254,6 +257,22 @@ package body Rundrv.Config is
       return Result;
    end ISystem;
 
+   -------------
+   -- Prepare --
+   -------------
+
+   function Prepare
+     (Context : Context_Type; Matches : Match_Array) return Command_Access
+   is
+      pragma Unreferenced (Matches);
+      pragma Unreferenced (Context);
+
+      Result : constant Command_Access := new Command_Type'
+        (Command => +"", others => <>);
+   begin
+      return Result;
+   end Prepare;
+
    ----------------
    -- Visium_ELF --
    ----------------
diff --git a/tools/gnatcov/rundrv.adb b/tools/gnatcov/rundrv.adb
index 2792c2489..25c32291b 100644
--- a/tools/gnatcov/rundrv.adb
+++ b/tools/gnatcov/rundrv.adb
@@ -183,6 +183,14 @@ package body Rundrv is
 
       Cmd : constant String := +Command.Command;
    begin
+
+      --  Honor a possible empty command text, meaning no actual
+      --  command to run.
+
+      if Cmd'Length = 0 then
+         return;
+      end if;
+
       --  Find executable
 
       Prg := GNAT.OS_Lib.Locate_Exec_On_Path (Cmd);

From dadbc2c4b15825113027c0d9a36970a8f4c41b8e Mon Sep 17 00:00:00 2001
From: Olivier Hainque <hainque@adacore.com>
Date: Tue, 12 Dec 2017 19:48:47 +0100
Subject: [PATCH 08/16] gnatcov testsuite: add SUITE/tracelib.py

extracted from tests/OA05-051-sharedobjs, so it can be reused
by other tests.

Part of work for adding a test for QA27-024

Change-Id: Ibbec782ca23b464a076c599fa4aabae9873b05f8
(cherry picked from commit 9b80d2cd6ea7b7e2eee66691a242d3d8728f3593)
---
 testsuite/SUITE/tracelib.py | 290 ++++++++++++++++++++++++++++++++++++
 1 file changed, 290 insertions(+)
 create mode 100644 testsuite/SUITE/tracelib.py

diff --git a/testsuite/SUITE/tracelib.py b/testsuite/SUITE/tracelib.py
new file mode 100644
index 000000000..cf026e4a8
--- /dev/null
+++ b/testsuite/SUITE/tracelib.py
@@ -0,0 +1,290 @@
+"""
+Qemu trace files loading and saving library.
+"""
+
+
+import binascii
+import datetime
+import os
+from struct import Struct
+
+
+class Enum(object):
+    RANGE = None
+
+    @classmethod
+    def in_range(cls, value):
+        low, high = cls.RANGE
+        return low <= value <= high
+
+    @classmethod
+    def check(cls, value):
+        assert cls.in_range(value), 'Invalid {}: {} not in {} .. {}'.format(
+            cls.__name__,
+            value,
+            cls.RANGE[0], cls.RANGE[1]
+        )
+
+
+class TraceKind(Enum):
+    Flat = 0
+    History = 1
+    Info = 2
+    DecisionMap = 3
+
+    RANGE = (0, 3)
+
+
+class InfoKind(Enum):
+    InfoEnd = 0
+    ExecFileName = 1
+    CoverageOptions = 2
+    UserData = 3
+    DateTime = 4
+    Kernel_File_Name = 5
+    ExecFileSize = 6
+    ExecTimeStamp = 7
+    ExecFileCRC32 = 8
+    CoverageContext = 9
+    ExecCodeSize = 10
+
+    RANGE = (0, 10)
+
+
+class TraceOp(Enum):
+    Block   = 0x10
+    Fault   = 0x20
+    Br0     = 0x01
+    Br1     = 0x02
+    Special = 0x80
+
+
+class TraceSpecial(Enum):
+    Loadaddr = 1
+    LoadSharedObject = 2
+    UnloadSharedObject = 3
+
+    RANGE = (1, 3)
+
+
+TRACE_MAGIC = '#QEMU-Traces'
+def create_trace_header(kind, pc_size, big_endian, machine):
+    return (
+        TRACE_MAGIC,
+        1,
+        kind,
+        pc_size,
+        big_endian,
+        machine >> 8,
+        machine & 0xff
+    )
+
+TraceHeaderStruct = Struct(
+    '12s'  # Magic string
+    'B'    # Version of file format
+    'B'    # Section kind
+
+    'B'    # Size of PC on target, in bytes
+    'B'    # Whether the host is big endian
+
+    'BB'   # Target ELF machine ID
+    'xx'   # Padding
+)
+
+
+TraceInfoHeaderStruct = Struct(
+    'I'  # Kind
+    'I'  # Length
+)
+
+
+TraceEntry32Struct = Struct(
+    'I'  # Pc
+    'H'  # Size
+    'B'  # Op
+    'x'  # Padding
+)
+TraceEntry64Struct = Struct(
+    'Q'      # Pc
+    'H'      # Size
+    'B'      # Op
+    'xxxxx'  # Padding
+)
+
+
+def unpack_from_file(fp, struct):
+    buf = fp.read(struct.size)
+    if not buf:
+        return None
+    assert len(buf) == struct.size
+    return struct.unpack(buf)
+
+
+class TraceFile(object):
+    def __init__(self, first_header, infos, second_header, entries):
+        self.bits = self.bits(second_header)
+
+        self.first_header = first_header
+        assert self.first_header
+
+        self.infos = infos
+
+        self.second_header = second_header
+        assert self.second_header
+
+        self.entries = entries
+        for entry in entries:
+            assert entry.bits == self.bits
+
+    @staticmethod
+    def bits(header):
+        assert header[3] in (4, 8)
+        return header[3] * 8
+
+    @classmethod
+    def read(cls, fp):
+        first_header = unpack_from_file(fp, TraceHeaderStruct)
+        infos = TraceInfoList.read(fp)
+
+        second_header = unpack_from_file(fp, TraceHeaderStruct)
+        bits = cls.bits(first_header)
+
+        entries = []
+        while True:
+            entry = TraceEntry.read(fp, bits)
+            if not entry:
+                break
+            entries.append(entry)
+
+        return cls(first_header, infos, second_header, entries)
+
+    def write(self, fp):
+        assert self.bits
+
+        fp.write(TraceHeaderStruct.pack(*self.first_header))
+        self.infos.write(fp)
+        fp.write(TraceHeaderStruct.pack(*self.second_header))
+        for entry in self.entries:
+            entry.write(fp)
+
+
+class TraceInfo(object):
+    def __init__(self, kind, data):
+        InfoKind.check(kind)
+        self.kind = kind
+        self.data = data
+
+    @staticmethod
+    def padding_size(data_size):
+        return 0 if data_size % 4 == 0 else (4 - (data_size % 4))
+
+    @property
+    def is_end(self):
+        return self.kind == InfoKind.InfoEnd
+
+    @classmethod
+    def read(cls, fp):
+        hdr = unpack_from_file(fp, TraceInfoHeaderStruct)
+        assert hdr
+        kind, length = hdr
+        InfoKind.check(kind)
+
+        data = fp.read(length)
+        assert len(data) == length
+
+        padding_size = cls.padding_size(len(data))
+        padding = fp.read(padding_size)
+        assert len(padding) == padding_size, (
+            'Expected {} padding bytes but got {}'.format(
+                padding_size, len(padding)
+            )
+        )
+        assert padding == ('\x00' * padding_size), (
+            'Some padding bytes are non-null: {}'.format(repr(padding))
+        )
+
+        return cls(kind, data)
+
+    def write(self, fp):
+        fp.write(TraceInfoHeaderStruct.pack(self.kind, len(self.data)))
+        fp.write(self.data)
+        fp.write('\x00' * self.padding_size(len(self.data)))
+
+
+class TraceInfoList(object):
+    def __init__(self, infos=None):
+        self.infos = infos or {}
+
+    @classmethod
+    def read(cls, fp):
+        result = cls()
+        while True:
+            info = TraceInfo.read(fp)
+            if info.is_end:
+                break
+            result.infos[info.kind] = info
+        return result
+
+    def write(self, fp):
+        for _, info in sorted(self.infos.items()):
+            info.write(fp)
+        fp.write(TraceInfoHeaderStruct.pack(InfoKind.InfoEnd, 0))
+
+
+class TraceEntry(object):
+    def __init__(self, bits, pc, size, op, infos=None):
+        self.bits = bits
+        self.pc = pc
+        self.size = size
+        self.op = op
+        self.infos = infos
+
+    @property
+    def is_special(self):
+        return bool(self.op & TraceOp.Special)
+
+    @staticmethod
+    def struct(bits):
+        return {
+            32: TraceEntry32Struct,
+            64: TraceEntry64Struct,
+        }[bits]
+
+    @classmethod
+    def read(cls, fp, bits):
+        fields = unpack_from_file(fp, cls.struct(bits))
+        if not fields:
+            return None
+
+        result = cls(bits, *fields)
+        if result.is_special and result.size == TraceSpecial.LoadSharedObject:
+            result.infos = TraceInfoList.read(fp)
+        return result
+
+    def write(self, fp):
+        fp.write(self.struct(self.bits).pack(
+            self.pc, self.size, self.op
+        ))
+        if self.infos:
+            self.infos.write(fp)
+
+
+def create_exec_infos(filename, code_size=None):
+    stat = os.stat(filename)
+    with open(filename, 'rb') as f:
+        f_contents = f.read()
+    crc32 = binascii.crc32(f_contents) & 0xffffffff
+    mtime = datetime.datetime.utcfromtimestamp(
+        int(stat.st_mtime)
+    )
+
+    infos = [
+        TraceInfo(InfoKind.ExecFileName, filename),
+        TraceInfo(InfoKind.ExecFileSize, ' ' + str(stat.st_size)),
+        TraceInfo(InfoKind.ExecTimeStamp, mtime.isoformat(' ')),
+        TraceInfo(InfoKind.ExecFileCRC32, ' ' + str(crc32)),
+    ]
+    if code_size:
+        infos.append(TraceInfo(InfoKind.ExecCodeSize, ' ' + str(code_size)))
+
+    return TraceInfoList({info.kind: info for info in infos})

From ceaac63bc80839ed44139e55f83d59cb157c503e Mon Sep 17 00:00:00 2001
From: Olivier Hainque <hainque@adacore.com>
Date: Tue, 12 Dec 2017 19:54:11 +0100
Subject: [PATCH 09/16] SUITE/tracelib.py: allow for a trace without the exec
 section

So we can inspect traces out of --target=prepare, part of test
for QA27-024.

Change-Id: Ib158c10970f0479cce58dc435b5525137be0efbd
(cherry picked from commit 284e279d019c6f481f2ec9c9b0a2f64378b76d72)
---
 testsuite/SUITE/tracelib.py | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/testsuite/SUITE/tracelib.py b/testsuite/SUITE/tracelib.py
index cf026e4a8..2c859b29d 100644
--- a/testsuite/SUITE/tracelib.py
+++ b/testsuite/SUITE/tracelib.py
@@ -122,15 +122,17 @@ def unpack_from_file(fp, struct):
 
 class TraceFile(object):
     def __init__(self, first_header, infos, second_header, entries):
-        self.bits = self.bits(second_header)
-
         self.first_header = first_header
         assert self.first_header
 
+        self.bits = TraceFile.bits(first_header)
         self.infos = infos
 
         self.second_header = second_header
-        assert self.second_header
+
+        if not second_header:
+            assert not entries
+            return
 
         self.entries = entries
         for entry in entries:

From fd9bb2b1c25e19837cc523843bdcc57c15bd81e3 Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <derodat@adacore.com>
Date: Thu, 14 Dec 2017 17:46:42 +0100
Subject: [PATCH 10/16] Add docstrings to entities in SUITE.tracelib

Change-Id: Ia424345da9cdd729cfdc73529af52e85b609090e
TN: QA27-024
(cherry picked from commit f616f5f7fbc14d2d5371e46f7535b1fe5401cd8c)
---
 testsuite/SUITE/tracelib.py | 151 ++++++++++++++++++++++++++++++++++++
 1 file changed, 151 insertions(+)

diff --git a/testsuite/SUITE/tracelib.py b/testsuite/SUITE/tracelib.py
index 2c859b29d..941f09735 100644
--- a/testsuite/SUITE/tracelib.py
+++ b/testsuite/SUITE/tracelib.py
@@ -10,15 +10,32 @@
 
 
 class Enum(object):
+    """
+    Base class to declare enumerations.
+    """
+
     RANGE = None
+    """
+    Tuple that contains the first and the last enumerated values. We consider
+    that all integers between these bounds (included) are valid enumerated
+    values.
+
+    :type: (int, int)
+    """
 
     @classmethod
     def in_range(cls, value):
+        """
+        Return whether `value` is in `cls`'s range.
+        """
         low, high = cls.RANGE
         return low <= value <= high
 
     @classmethod
     def check(cls, value):
+        """
+        Assert that `value` is in `cls`'s range.
+        """
         assert cls.in_range(value), 'Invalid {}: {} not in {} .. {}'.format(
             cls.__name__,
             value,
@@ -27,6 +44,9 @@ def check(cls, value):
 
 
 class TraceKind(Enum):
+    """
+    Kind of trace file. See Trace_Kind in qemu_traces.ads.
+    """
     Flat = 0
     History = 1
     Info = 2
@@ -36,6 +56,9 @@ class TraceKind(Enum):
 
 
 class InfoKind(Enum):
+    """
+    Kind of trace information record. See Info_Kind_Type in qemu_traces.ads.
+    """
     InfoEnd = 0
     ExecFileName = 1
     CoverageOptions = 2
@@ -52,6 +75,9 @@ class InfoKind(Enum):
 
 
 class TraceOp(Enum):
+    """
+    Trace operation bitmasks. See Trace_Op_* in qemu_traces.ads.
+    """
     Block   = 0x10
     Fault   = 0x20
     Br0     = 0x01
@@ -60,6 +86,9 @@ class TraceOp(Enum):
 
 
 class TraceSpecial(Enum):
+    """
+    Special trace operations. See Trace_Special_* in qemu_traces.ads.
+    """
     Loadaddr = 1
     LoadSharedObject = 2
     UnloadSharedObject = 3
@@ -68,7 +97,21 @@ class TraceSpecial(Enum):
 
 
 TRACE_MAGIC = '#QEMU-Traces'
+"""
+Exepected value of the Magic header field. See Qemu_Trace_Magic in
+qemu_traces.ads.
+"""
+
 def create_trace_header(kind, pc_size, big_endian, machine):
+    """
+    Return a tuple to represent a trace header. See Trace_Header in
+    qemu_traces.ads.
+
+    :param int kind: Trace file kind. See TraceKind.
+    :param int pc_size: Size of Program Counter on tagret, in bytes.
+    :param bool big_endian: Whether the target is big-endian.
+    :param int machine: Target ELF machine ID.
+    """
     return (
         TRACE_MAGIC,
         1,
@@ -113,6 +156,13 @@ def create_trace_header(kind, pc_size, big_endian, machine):
 
 
 def unpack_from_file(fp, struct):
+    """
+    Read all the bytes necessary to decode `struct` from the `fp` file and
+    return the decoded structure as a tuple.
+
+    :param file fp: File from which to read bytes.
+    :param Struct struct: Struct instance to decode data.
+    """
     buf = fp.read(struct.size)
     if not buf:
         return None
@@ -121,7 +171,22 @@ def unpack_from_file(fp, struct):
 
 
 class TraceFile(object):
+    """
+    In-memory representation of a trace file.
+    """
+
     def __init__(self, first_header, infos, second_header, entries):
+        """
+        Create a trace file.
+
+        If this instance must represent a partial trace file, `second_header`
+        must be None and `entries` must be empty.
+
+        :param first_header: Tuple for a TraceHeaderStruct structure.
+        :param TraceInfoList infos: Information for the traced program.
+        :param second_header: Tuple for a TraceHeaderStruct structure.
+        :param TraceInfoList entries: Trace entries.
+        """
         self.first_header = first_header
         assert self.first_header
 
@@ -130,6 +195,7 @@ def __init__(self, first_header, infos, second_header, entries):
 
         self.second_header = second_header
 
+        # If there is no second header, make sure we have no entry
         if not second_header:
             assert not entries
             return
@@ -140,11 +206,17 @@ def __init__(self, first_header, infos, second_header, entries):
 
     @staticmethod
     def bits(header):
+        """
+        Return size of PC on target, in bits.
+        """
         assert header[3] in (4, 8)
         return header[3] * 8
 
     @classmethod
     def read(cls, fp):
+        """
+        Read a trace file from the `fp` file. Return a TraceFile instance.
+        """
         first_header = unpack_from_file(fp, TraceHeaderStruct)
         infos = TraceInfoList.read(fp)
 
@@ -161,6 +233,9 @@ def read(cls, fp):
         return cls(first_header, infos, second_header, entries)
 
     def write(self, fp):
+        """
+        Write this trace file to the `fp` file.
+        """
         assert self.bits
 
         fp.write(TraceHeaderStruct.pack(*self.first_header))
@@ -171,21 +246,41 @@ def write(self, fp):
 
 
 class TraceInfo(object):
+    """
+    In-memory representation for a trace info entry.
+    """
+
     def __init__(self, kind, data):
+        """
+        Create a trace info entry.
+
+        :param int kind: Trace info entry kind. See InfoKind.
+        :param str data: Raw data (bytes) for this entry.
+        """
         InfoKind.check(kind)
         self.kind = kind
         self.data = data
 
     @staticmethod
     def padding_size(data_size):
+        """
+        Number of padding bytes at the end of the Trace_Info record.
+        """
         return 0 if data_size % 4 == 0 else (4 - (data_size % 4))
 
     @property
     def is_end(self):
+        """
+        Whether this trace info entry is the trace info list end marker.
+        """
         return self.kind == InfoKind.InfoEnd
 
     @classmethod
     def read(cls, fp):
+        """
+        Read a trace info entry from the `fp` file. Return a TraceInfo
+        instance.
+        """
         hdr = unpack_from_file(fp, TraceInfoHeaderStruct)
         assert hdr
         kind, length = hdr
@@ -208,17 +303,35 @@ def read(cls, fp):
         return cls(kind, data)
 
     def write(self, fp):
+        """
+        Write this trace info to the `fp` file.
+        """
         fp.write(TraceInfoHeaderStruct.pack(self.kind, len(self.data)))
         fp.write(self.data)
         fp.write('\x00' * self.padding_size(len(self.data)))
 
 
 class TraceInfoList(object):
+    """
+    In-memory representation of a list of list of trace info entries.
+    """
+
     def __init__(self, infos=None):
+        """
+        Create a list of trace info entries.
+
+        :param dict[int, TraceInfo]|None infos: None for an empty list.
+            Otherwise, mapping from trace info kind (see InfoKind) to TraceInfo
+            instance.
+        """
         self.infos = infos or {}
 
     @classmethod
     def read(cls, fp):
+        """
+        Read a trace info entry list from the `fp` file. Return a TraceInfoList
+        instance.
+        """
         result = cls()
         while True:
             info = TraceInfo.read(fp)
@@ -228,13 +341,28 @@ def read(cls, fp):
         return result
 
     def write(self, fp):
+        """
+        Write this trace info list to the `fp` file.
+        """
         for _, info in sorted(self.infos.items()):
             info.write(fp)
         fp.write(TraceInfoHeaderStruct.pack(InfoKind.InfoEnd, 0))
 
 
 class TraceEntry(object):
+    """
+    In-memory representation of a trace entry.
+    """
+
     def __init__(self, bits, pc, size, op, infos=None):
+        """
+        :param int bits: Number of bits in the target PC.
+        :param int pc: PC for the trace entry (i.e. first address to be
+            executed, or address of the event).
+        :param int size: Size in bytes for the trace entry.
+        :param None|TraceInfoList infos: Informations associated to this trace
+            entry.
+        """
         self.bits = bits
         self.pc = pc
         self.size = size
@@ -243,10 +371,18 @@ def __init__(self, bits, pc, size, op, infos=None):
 
     @property
     def is_special(self):
+        """
+        Whether this is a special trace entry. See Trace_Op_Special in
+        qemu_traces.ads.
+        """
         return bool(self.op & TraceOp.Special)
 
     @staticmethod
     def struct(bits):
+        """
+        Struct instance to decode a trace entry given the number of bits in PC
+        PC on a target.
+        """
         return {
             32: TraceEntry32Struct,
             64: TraceEntry64Struct,
@@ -254,6 +390,9 @@ def struct(bits):
 
     @classmethod
     def read(cls, fp, bits):
+        """
+        Read a trace entry from the `fp` file. Return a TraceEntry instance.
+        """
         fields = unpack_from_file(fp, cls.struct(bits))
         if not fields:
             return None
@@ -264,6 +403,9 @@ def read(cls, fp, bits):
         return result
 
     def write(self, fp):
+        """
+        Write this trace entry to the `fp` file.
+        """
         fp.write(self.struct(self.bits).pack(
             self.pc, self.size, self.op
         ))
@@ -272,6 +414,15 @@ def write(self, fp):
 
 
 def create_exec_infos(filename, code_size=None):
+    """
+    Create a TraceInfoList object to describe the given executable.
+
+    :param str filename: Path to the executable file.
+    :param int|None code_size: If provided, size of the executable code section
+        in `filename`. Used to create the Exec_Code_Size trace information
+        entry.
+    :rtype: TraceInfoList
+    """
     stat = os.stat(filename)
     with open(filename, 'rb') as f:
         f_contents = f.read()

From eaeb5b7f98c7677f7368e255bbcec6e1742daccd Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <derodat@adacore.com>
Date: Mon, 18 Dec 2017 10:30:41 +0100
Subject: [PATCH 11/16] SUITE.tracelib: fix a docstring typo

Change-Id: Ieb27d1e0a56633ca740b721d1fc0490e92df080b
TN: QA27-024
(cherry picked from commit af5073f7d31a3342f6010f1a6106b1dc9ac6da9c)
---
 testsuite/SUITE/tracelib.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/testsuite/SUITE/tracelib.py b/testsuite/SUITE/tracelib.py
index 941f09735..375eea9e5 100644
--- a/testsuite/SUITE/tracelib.py
+++ b/testsuite/SUITE/tracelib.py
@@ -108,7 +108,7 @@ def create_trace_header(kind, pc_size, big_endian, machine):
     qemu_traces.ads.
 
     :param int kind: Trace file kind. See TraceKind.
-    :param int pc_size: Size of Program Counter on tagret, in bytes.
+    :param int pc_size: Size of Program Counter on target, in bytes.
     :param bool big_endian: Whether the target is big-endian.
     :param int machine: Target ELF machine ID.
     """

From 410c69c9dc99c99c24506473764112c1f5bc1a19 Mon Sep 17 00:00:00 2001
From: Olivier Hainque <hainque@adacore.com>
Date: Wed, 7 Mar 2018 10:49:36 +0100
Subject: [PATCH 12/16] Update branchname in .gitreview for gnatcoverage 18.2

R305-053
---
 .gitreview | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitreview b/.gitreview
index 5f8728433..54044f3f3 100644
--- a/.gitreview
+++ b/.gitreview
@@ -2,5 +2,5 @@
 host = git.adacore.com
 port = 29418
 project = gnatcoverage
-defaultbranch = 18.1
+defaultbranch = 18.2
 defaultremote = origin

From 1be09f0009b06a4eb945bc60d3434b22969e3dd1 Mon Sep 17 00:00:00 2001
From: assamoi <assamoi@adacore.com>
Date: Thu, 11 Jan 2018 23:21:04 +0100
Subject: [PATCH 13/16] Add information on missing sources from SCOs for dhtml
 report

Change-Id: I324b9abf09acc9047de3f5e05ba7fe5280df92db
TN: PC20-040
(cherry picked from commit c825ab1b64b81ac702e05204d5b04544e2b346b3)
---
 tools/gnatcov/annotations-dynamic_html.adb | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/tools/gnatcov/annotations-dynamic_html.adb b/tools/gnatcov/annotations-dynamic_html.adb
index 425ebef8c..e29938825 100644
--- a/tools/gnatcov/annotations-dynamic_html.adb
+++ b/tools/gnatcov/annotations-dynamic_html.adb
@@ -358,6 +358,8 @@ package body Annotations.Dynamic_Html is
               ("coverage_level", String'(Source.Get ("coverage_level")));
             Simplified.Set_Field
               ("hunk_filename", String'(Source.Get ("hunk_filename")));
+            Simplified.Set_Field
+              ("missing_source", Boolean'(Source.Get ("missing_source")));
 
             if Source.Has_Field ("project") then
                --  Project name is optional. Add it only when relevant
@@ -397,15 +399,10 @@ package body Annotations.Dynamic_Html is
       Clear (Pp.Current_Decisions);
       Clear (Pp.Current_Conditions);
 
-      if not Info.Has_Source then
-         Skip := True;
-         return;
-      end if;
-
       Skip := False;
 
+      Source.Set_Field ("missing_source", not Info.Has_Source);
       --  Compute the coverage stats and store them into a JSON dictionary
-
       Stats.Set_Field ("no_code", Info.Stats (No_Code));
       Stats.Set_Field ("covered", Info.Stats (Covered));
       Stats.Set_Field ("partially_covered", Info.Stats (Partially_Covered));

From f4ac440df729d86ef93107c4458e3c7752c1e75c Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <derodat@adacore.com>
Date: Fri, 17 Nov 2017 17:25:22 +0100
Subject: [PATCH 14/16] Files_Table.Expand_Line_Table: avoid big aggregate
 stack allocation

Change-Id: Id09c41ad21c093c26dbbc991e293aa14363baaff
TN: QB14-023
(cherry picked from commit f2a1840e6d20cb0c79c79dc79dc021e83e528aba)
---
 tools/gnatcov/files_table.adb | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/tools/gnatcov/files_table.adb b/tools/gnatcov/files_table.adb
index d25d4a89c..6cc3e78bd 100644
--- a/tools/gnatcov/files_table.adb
+++ b/tools/gnatcov/files_table.adb
@@ -460,10 +460,14 @@ package body Files_Table is
          return;
       end if;
 
-      New_Lines :=
-        new Source_Line_Array'
-          (FI.Lines.Last_Index + 1 .. Line =>
-             (State => (others => No_Code), others => <>));
+      --  Allocate the array first and then initialize it. Don't do it in one
+      --  single statement as this would create a big aggregate on the stack,
+      --  triggering a stack overflow when the number of line is too high.
+
+      New_Lines := new Source_Line_Array (FI.Lines.Last_Index + 1 .. Line);
+      for Line of New_Lines.all loop
+         Line := (State => (others => No_Code), others => <>);
+      end loop;
 
       Bump (Line_Table_Alloc);
       Bump (Line_Table_Alloc_Size, How_Many => New_Lines'Length);

From f3637267d5371cc9e657b361fe36a71f0f990b42 Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Wed, 13 Nov 2019 07:41:47 -0800
Subject: [PATCH 15/16] .gitreview: set gerrit.defaultbranch to 18-sustained
 [SB13-044]

---
 .gitreview | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitreview b/.gitreview
index 54044f3f3..83ce68906 100644
--- a/.gitreview
+++ b/.gitreview
@@ -2,5 +2,5 @@
 host = git.adacore.com
 port = 29418
 project = gnatcoverage
-defaultbranch = 18.2
+defaultbranch = 18-sustained
 defaultremote = origin

From e99a87397e27cbb8f27b817b52338293ce4fc934 Mon Sep 17 00:00:00 2001
From: Liaiss Merzougue <merzougue@adacore.com>
Date: Wed, 2 Jul 2025 16:33:11 +0000
Subject: [PATCH 16/16] Fix GNATCoverage build on Windows

On 18-sustained, GNATCoverage was previously built with Visual Studio
12. With the Secure control plane transition we have only Visual
Studio 17, take the opportunity to use a newer version of
Visual Studio

Ref: it/org/software-supply-chain/production-pipeline/issues#129
---
 tools/gnatcov/trace_adapters/dynamorio/CMakeLists.txt | 6 ++++--
 tools/gnatcov/trace_adapters/dynamorio/Makefile       | 8 ++++----
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/tools/gnatcov/trace_adapters/dynamorio/CMakeLists.txt b/tools/gnatcov/trace_adapters/dynamorio/CMakeLists.txt
index 85a7ad1e5..3c404b138 100644
--- a/tools/gnatcov/trace_adapters/dynamorio/CMakeLists.txt
+++ b/tools/gnatcov/trace_adapters/dynamorio/CMakeLists.txt
@@ -3,10 +3,12 @@
 # cmake -DDynamoRIO_DIR=$PWD/../dynamorio/cmake ../dr-gnatcov
 # make
 # ../dynamorio/bin64/drrun -client libqtrace.so 0 -- /bin/ls
-
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 3.15)
+project(qtrace C)
 
 add_library(qtrace SHARED qtrace.c)
+target_link_libraries(qtrace vcruntime libucrt)
+
 find_package(DynamoRIO)
 if (NOT DynamoRIO_FOUND)
   message(FATAL_ERROR "DynamoRIO package required to build")
diff --git a/tools/gnatcov/trace_adapters/dynamorio/Makefile b/tools/gnatcov/trace_adapters/dynamorio/Makefile
index 4f2637050..33b133bfd 100644
--- a/tools/gnatcov/trace_adapters/dynamorio/Makefile
+++ b/tools/gnatcov/trace_adapters/dynamorio/Makefile
@@ -8,9 +8,9 @@ DYNRIO_CLIENT=INVALID
 ifeq ($(HOST_OS), windows)
 DYNRIO_CLIENT=build/$(DYNRIO_CONFIG)/qtrace.dll
 ifeq ($(BITS_ARCH), 32)
-G_OPTION=-G"Visual Studio 12"
+G_OPTION=-G"Visual Studio 17"
 else
-G_OPTION=-G"Visual Studio 12 Win64"
+G_OPTION=-G"Visual Studio 17 Win64"
 endif
 endif
 
@@ -29,8 +29,8 @@ all: $(DYNRIO_CLIENT)
 
 $(DYNRIO_CLIENT):
 	mkdir build || true
-	cd build && cmake -DDynamoRIO_DIR=$(DYNRIO_PREFIX)/cmake $(G_OPTION) ..
-	cd build && cmake --build . --config $(DYNRIO_CONFIG)
+	cd build && cmake -Wno-dev -DDynamoRIO_DIR=$(DYNRIO_PREFIX)/cmake $(G_OPTION) ..
+	cd build && cmake --build . --config $(DYNRIO_CONFIG) -v 
 
 ################
 # Installation #
