Difference between revisions of "Setting Ada String Parameters"
(Created page with " It is often useful to be able to change the value of an Ada string parameter to a subprogram. Here is a description of that process, which varies for PowerAda and GNAT. ==E...") |
m |
||
Line 135: | Line 135: | ||
</nowiki> | </nowiki> | ||
+ | ===Larger Test=== | ||
+ | |||
+ | Here is a larger test that replaces an Ada string in parameter, out parameter, and function return value: | ||
+ | |||
+ | <source lang=ada> | ||
+ | package Pkg is | ||
+ | |||
+ | subtype Fixed_String is String(1..10); | ||
+ | |||
+ | procedure P1(S : in String); | ||
+ | |||
+ | procedure P2(S : in Fixed_String); | ||
+ | |||
+ | procedure P3(S : out String); | ||
+ | |||
+ | procedure P4(S : out Fixed_String); | ||
+ | |||
+ | function F1(I : in Integer) return String; | ||
+ | |||
+ | function F2(I : in Integer) return Fixed_String; | ||
+ | |||
+ | end Pkg; | ||
+ | |||
+ | |||
+ | with Text_Io; | ||
+ | |||
+ | package body Pkg is | ||
+ | |||
+ | procedure P1(S : in String) is | ||
+ | begin | ||
+ | Text_Io.Put_Line("p1 = " & S); | ||
+ | end P1; | ||
+ | |||
+ | procedure P2(S : in Fixed_String) is | ||
+ | begin | ||
+ | Text_Io.Put_Line("p2 = " & S); | ||
+ | end P2; | ||
+ | |||
+ | procedure P3(S : out String) is | ||
+ | begin | ||
+ | S := (others => 'v'); | ||
+ | end P3; | ||
+ | |||
+ | procedure P4(S : out Fixed_String) is | ||
+ | begin | ||
+ | S := (others => '.'); | ||
+ | end P4; | ||
+ | |||
+ | function F1(I : in Integer) return String is | ||
+ | begin | ||
+ | return Integer'Image(I); | ||
+ | end F1; | ||
+ | |||
+ | function F2(I : in Integer) return Fixed_String is | ||
+ | Temp: String := Integer'Image(I); | ||
+ | Result : Fixed_String := (others => ' '); | ||
+ | begin | ||
+ | if Temp'Length > Result'Length then | ||
+ | Result := Temp(Temp'First .. Temp'First + Result'Length -1); | ||
+ | else | ||
+ | Result(Result'First .. Result'First + Temp'Length - 1) := Temp; | ||
+ | end if; | ||
+ | return Result; | ||
+ | end F2; | ||
+ | |||
+ | end Pkg; | ||
+ | |||
+ | |||
+ | with Text_Io; | ||
+ | with Pkg; use Pkg; | ||
+ | |||
+ | procedure Main is | ||
+ | S1 : String(1..10) := (others => 'x'); | ||
+ | S2 : Fixed_String := "1234567890"; | ||
+ | S3 : String := "123456789"; | ||
+ | S4 : Fixed_String; | ||
+ | S6 : Fixed_String; | ||
+ | begin | ||
+ | Pkg.P1(S1); | ||
+ | Pkg.P2(S2); | ||
+ | Pkg.P3(S3); | ||
+ | Text_Io.Put_Line("S3 = " & S3); | ||
+ | Pkg.P4(S4); | ||
+ | Text_Io.Put_Line("S4 = " & S4); | ||
+ | declare | ||
+ | S5 : String := Pkg.F1(10); | ||
+ | begin | ||
+ | Text_Io.Put_Line("S5 = " & S5); | ||
+ | end; | ||
+ | S6 := Pkg.F2(77); | ||
+ | Text_Io.Put_Line("S6 = " & S6); | ||
+ | end Main; | ||
+ | |||
+ | </source> | ||
+ | |||
+ | Here is the probe to set the Ada string values: | ||
+ | |||
+ | <source lang=c> | ||
+ | |||
+ | probe thread | ||
+ | { | ||
+ | |||
+ | probe "pkg.p1" | ||
+ | { | ||
+ | on_entry | ||
+ | { | ||
+ | // set whole string | ||
+ | strncpy($s, "abcdefghijklmn", $string_ub_1_3 - $string_lb_1_2 + 1); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | probe "pkg.p2" | ||
+ | { | ||
+ | on_entry | ||
+ | { | ||
+ | // set whole string | ||
+ | strncpy($s, "9876543210", 10); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | probe "pkg.p3" | ||
+ | { | ||
+ | on_exit | ||
+ | { | ||
+ | // set whole string | ||
+ | // bounds target expressions found with apcgen | ||
+ | strncpy($s, "abcdefghijklmnop", $string_ub_1_3 - $string_lb_1_2 + 1); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | probe "pkg.p4" | ||
+ | { | ||
+ | on_exit | ||
+ | { | ||
+ | // set whole string | ||
+ | strncpy($s, "9876543210", 10); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | probe "pkg.f1" | ||
+ | { | ||
+ | on_exit | ||
+ | { | ||
+ | // set whole string | ||
+ | // bounds target expressions found with apcgen | ||
+ | strncpy($return, "987654321", $string_ub_1_4 - $string_lb_1_3 + 1); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | probe "pkg.f2" | ||
+ | { | ||
+ | on_exit | ||
+ | { | ||
+ | // set whole string | ||
+ | strncpy($return, "9876543210", 10); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | </source> | ||
+ | |||
+ | Here is the output with the probe in place: | ||
+ | |||
+ | <nowiki> | ||
+ | p1 = abcdefghij | ||
+ | p2 = 9876543210 | ||
+ | S3 = abcdefghi | ||
+ | S4 = 9876543210 | ||
+ | S5 = 987 | ||
+ | S6 = 9876543210 | ||
+ | </nowiki> | ||
==Gnat== | ==Gnat== | ||
Line 164: | Line 336: | ||
<nowiki> | <nowiki> | ||
p1 = newvalue | p1 = newvalue | ||
+ | </nowiki> | ||
+ | |||
+ | ===Larger Test=== | ||
+ | |||
+ | Here is the probe to set the Ada string values: | ||
+ | |||
+ | <source lang=c> | ||
+ | |||
+ | probe thread | ||
+ | { | ||
+ | |||
+ | probe "pkg.p1" | ||
+ | { | ||
+ | on_entry | ||
+ | { | ||
+ | // set whole string | ||
+ | strncpy($s, "abcdefghijklmn", $string_ub_1_3 - $string_lb_1_2 + 1); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | probe "pkg.p2" | ||
+ | { | ||
+ | on_entry | ||
+ | { | ||
+ | // set whole string | ||
+ | strncpy($s, "9876543210", 10); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | probe "pkg.p3" | ||
+ | { | ||
+ | on_exit | ||
+ | { | ||
+ | // set whole string | ||
+ | // bounds target expressions found with apcgen | ||
+ | strncpy($s, "abcdefghijklmnop", $string_ub_1_3 - $string_lb_1_2 + 1); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | probe "pkg.p4" | ||
+ | { | ||
+ | on_exit | ||
+ | { | ||
+ | // set whole string | ||
+ | strncpy($s, "9876543210", 10); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | probe "pkg.f1" | ||
+ | { | ||
+ | on_exit | ||
+ | { | ||
+ | // set whole string | ||
+ | // bounds target expressions found with apcgen | ||
+ | strncpy($return, "987654321", $string_ub_1_4 - $string_lb_1_3 + 1); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | probe "pkg.f2" | ||
+ | { | ||
+ | on_exit | ||
+ | { | ||
+ | // set whole string | ||
+ | strncpy($return, "9876543210", 10); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | </source> | ||
+ | |||
+ | Here is the output with the probe in place: | ||
+ | |||
+ | <nowiki> | ||
+ | p1 = abcdefghij | ||
+ | p2 = 9876543210 | ||
+ | S3 = abcdefghi | ||
+ | S4 = 9876543210 | ||
+ | S5 = 987 | ||
+ | S6 = 9876543210 | ||
</nowiki> | </nowiki> | ||
Revision as of 22:02, 23 August 2018
It is often useful to be able to change the value of an Ada string parameter to a subprogram. Here is a description of that process, which varies for PowerAda and GNAT.
Contents
Example Program
Here is an example program. The idea is to change the value of the parameter S
passed to Pkg.P1
.
package Pkg is
procedure P1(S : in String);
end Pkg;
with Text_Io;
package body Pkg is
procedure P1(S : in String) is
begin
Text_Io.Put_Line("p1 = " & S);
end P1;
end Pkg;
with Text_Io;
with Pkg; use Pkg;
procedure Main is
S1 : String(1..10) := (others => 'x');
begin
Pkg.P1(S1);
end Main;
PowerAda
PowerAda passes string parameters as three separate values: the character data pointer, the lower bound, and the upper bound. There are two ways to change the value to the string being passed in.
Simple (Destructive) Change
If the passed in string value doesn’t matter anymore, there is a simple (destructive) way to change the string. In this case you just copy the new string data (characters) over the old string data. The new string data must be the same size as the old one or you risk overwriting other data. Here is how you would do that:
probe thread
{
probe "pkg.p1"
{
on_entry
{
// sets passed string
strncpy($s, "abcdefghij", sizeof("abcdefghij"));
}
}
}
Will produce this output:
p1 = abcdefghij
You can get a little fancier if you access the lower and upper bound parameters to determine how much space you have to work with (see the next example below).
Replacing The String
The next example is how you can replace the incoming string value with a completely different one. The idea is to point to different string data and set different lower and upper bounds.
First, use apcgen
to find out the name to the string parameter lower and upper bound parameters:
# generate probe to discover string parameter names apcgen -qparams -p pkg.p1 -x main.exe > a.apc
In the generated apc in a.apc you will see the hidden parameters for the lower and upper bounds:
probe extern:"pkg.p1[1]" in MODULE_NAME
{ // "p1" declared in "/home/swn/aprobe/test/faq/setstrada3/pkg.adb" at line 8
on_entry
{
ap_LogSubprogramEntry;
log parameter("\"s\" (parameter) = ", $s);
log parameter("\"string_lb_1_2\" (parameter) = ", $string_lb_1_2);
log parameter("\"string_ub_1_3\" (parameter) = ", $string_ub_1_3);
}
on_exit
{
ap_LogSubprogramExit;
// Only continue if normal exit.
if (ap_ProbeActionReason != ap_ExitAction) return;
// Void return value.
}
}
So we can see the bounds passed in the parameters: string_lb_1_2
and string_ub_1_3
.
We can use the following probe to change the value of the string:
const char new_string[] = "abcdefghijklmnop";
probe thread
{
probe "pkg.p1"
{
on_entry
{
// Discovered the "hidden" string bounds using apcgen
// Set the string data to point to the new string data.
// We have to use the register name to change the address of the string data. On AIX $$r3 is first parameter.
$$r3 = &new_string;
// Set the lower bound to 1
$string_lb_1_2 = 1;
// set the upper bound to the string lentgh
$string_ub_1_3 = strlen(new_string);
}
}
}
Will produce this output:
p1 = abcdefghijklmnop
Larger Test
Here is a larger test that replaces an Ada string in parameter, out parameter, and function return value:
package Pkg is
subtype Fixed_String is String(1..10);
procedure P1(S : in String);
procedure P2(S : in Fixed_String);
procedure P3(S : out String);
procedure P4(S : out Fixed_String);
function F1(I : in Integer) return String;
function F2(I : in Integer) return Fixed_String;
end Pkg;
with Text_Io;
package body Pkg is
procedure P1(S : in String) is
begin
Text_Io.Put_Line("p1 = " & S);
end P1;
procedure P2(S : in Fixed_String) is
begin
Text_Io.Put_Line("p2 = " & S);
end P2;
procedure P3(S : out String) is
begin
S := (others => 'v');
end P3;
procedure P4(S : out Fixed_String) is
begin
S := (others => '.');
end P4;
function F1(I : in Integer) return String is
begin
return Integer'Image(I);
end F1;
function F2(I : in Integer) return Fixed_String is
Temp: String := Integer'Image(I);
Result : Fixed_String := (others => ' ');
begin
if Temp'Length > Result'Length then
Result := Temp(Temp'First .. Temp'First + Result'Length -1);
else
Result(Result'First .. Result'First + Temp'Length - 1) := Temp;
end if;
return Result;
end F2;
end Pkg;
with Text_Io;
with Pkg; use Pkg;
procedure Main is
S1 : String(1..10) := (others => 'x');
S2 : Fixed_String := "1234567890";
S3 : String := "123456789";
S4 : Fixed_String;
S6 : Fixed_String;
begin
Pkg.P1(S1);
Pkg.P2(S2);
Pkg.P3(S3);
Text_Io.Put_Line("S3 = " & S3);
Pkg.P4(S4);
Text_Io.Put_Line("S4 = " & S4);
declare
S5 : String := Pkg.F1(10);
begin
Text_Io.Put_Line("S5 = " & S5);
end;
S6 := Pkg.F2(77);
Text_Io.Put_Line("S6 = " & S6);
end Main;
Here is the probe to set the Ada string values:
probe thread
{
probe "pkg.p1"
{
on_entry
{
// set whole string
strncpy($s, "abcdefghijklmn", $string_ub_1_3 - $string_lb_1_2 + 1);
}
}
probe "pkg.p2"
{
on_entry
{
// set whole string
strncpy($s, "9876543210", 10);
}
}
probe "pkg.p3"
{
on_exit
{
// set whole string
// bounds target expressions found with apcgen
strncpy($s, "abcdefghijklmnop", $string_ub_1_3 - $string_lb_1_2 + 1);
}
}
probe "pkg.p4"
{
on_exit
{
// set whole string
strncpy($s, "9876543210", 10);
}
}
probe "pkg.f1"
{
on_exit
{
// set whole string
// bounds target expressions found with apcgen
strncpy($return, "987654321", $string_ub_1_4 - $string_lb_1_3 + 1);
}
}
probe "pkg.f2"
{
on_exit
{
// set whole string
strncpy($return, "9876543210", 10);
}
}
}
Here is the output with the probe in place:
p1 = abcdefghij p2 = 9876543210 S3 = abcdefghi S4 = 9876543210 S5 = 987 S6 = 9876543210
Gnat
Gnat passes Ada strings as a couple of records: the first contains the pointer to the string data (characters) and a pointer to the bounds record, the second record contains the lower and upper bounds. Aprobe includes some macros for manipulating GNAT string parameters so you don't ahve to worry about the underlying layout. Include $APROBE/include/gnatstrings.h
in you probe apc.
Replacing The String
Here is a probe to replace a Gnat Ada string parameter with a new one:
#include "gnatstrings.h"
probe thread
{
probe "pkg.p1"
{
on_entry
{
ap_SetGnatUCString($s, "new value");
}
}
}
Will produce this output:
p1 = newvalue
Larger Test
Here is the probe to set the Ada string values:
probe thread
{
probe "pkg.p1"
{
on_entry
{
// set whole string
strncpy($s, "abcdefghijklmn", $string_ub_1_3 - $string_lb_1_2 + 1);
}
}
probe "pkg.p2"
{
on_entry
{
// set whole string
strncpy($s, "9876543210", 10);
}
}
probe "pkg.p3"
{
on_exit
{
// set whole string
// bounds target expressions found with apcgen
strncpy($s, "abcdefghijklmnop", $string_ub_1_3 - $string_lb_1_2 + 1);
}
}
probe "pkg.p4"
{
on_exit
{
// set whole string
strncpy($s, "9876543210", 10);
}
}
probe "pkg.f1"
{
on_exit
{
// set whole string
// bounds target expressions found with apcgen
strncpy($return, "987654321", $string_ub_1_4 - $string_lb_1_3 + 1);
}
}
probe "pkg.f2"
{
on_exit
{
// set whole string
strncpy($return, "9876543210", 10);
}
}
}
Here is the output with the probe in place:
p1 = abcdefghij p2 = 9876543210 S3 = abcdefghi S4 = 9876543210 S5 = 987 S6 = 9876543210