通过 C 解释器 (VxWorks) 将字符串从 C 传递到 Ada

发布于 2025-01-17 20:59:06 字数 2210 浏览 2 评论 0原文

我正在尝试通过在telnet窗口中使用C解释器将字符串从C传递到ADA。

interface.h

#pragma once

#ifdef _cplusplus
extern "C"
{
#endif

extern void Ada_SetNewAddress(char*);

extern "C" void SetNewAddrBroker(char* ipAddress);

#ifdef __cplusplus
}
#endif

interface.cpp

#include "Interface.h"
#include <stdio>

extern "C" void SetNewAddrBroker(char* ipAddress)
{
    printf("We passed the value -> %s", ipAddress);
    Ada_SetNewAddress(ipAddress);
    printf("Ada was called!\n");
}

arterer.ads

with Interfaces.C;
with Interfaces.C.Strings;

package Streamer is
    procedure Initialize;
    procedure SetNewAddress(str : Interfaces.C.Strings.chars_ptr);
    pragma Export (C, SetNewAddress, "Ada_SetNewAddress");
end Streamer;

streamer.adb

package body Streamer is
    Socket : Socket_Type;
    DefaultAddr : String := "127.0.0.1";
    Address : Sock_Addr_Type := (Family_Inet, Inet_Addr(DefaultAddr), 1024);
    Buffer : Stream_Access;

    procedure Initialize is
    begin
        Create_Socket(Socket, Family_Inet, Socket_Datagram);
        Buffer := Stream(Socket, Address);
    end;

    procedure SetNewAddress(str : Interfaces.C.Strings.chars_ptr)
        cstar : String := Interfaces.C.Strings.Value(str);
    begin
        Address := (Family_Inet, Inet_Addr(cstar), 1024);
        Buffer := Stream(socket, Address);
    end;
end Streamer;

当我调用c函数setNewAddrBroker(“ 192.168.1.1”)时,我会收到'数据访问'错误,这是通过telnet到telnet to to to to to to to to t to vxworks计算机,此代码在此代码上存在, ADA程序是主要任务,因此我知道这不是丢失的“ Adainit()和adafinal()”的呼叫。我不知道为什么它会丢弃随机数据访问错误。我可以为Telnet客户端使用Putty或Teraterm,如果这很重要,则可以丢下相同的错误。

错误输出

    We passed -> 192.168.1.1
    data access
    Exception current instruction address: 0x002e3ab0
    ............
    trcStack aborted: error in top frame
    Shell task 'tShellRem1' restarted...

检查的指示,说明了

    0x2e3ab0 stw r30,8(r9)

我不知道的组件,但我想这是试图将字符串存储在一个太小的地方?

我需要在运行时为客户端设置经纪人的IP,ADA是客户端,经纪人就在我的LAN上。我希望能够将其远程链接到ADA客户端并更新IP地址,但是接触到我的唯一接口是VXWorks Box的C解释器,因此我坚持使用此功能。

VXWorks版本6.3

I'm trying to pass a string from C to Ada by using the C interpreter in a telnet window to a VxWorks box.

Interface.h

#pragma once

#ifdef _cplusplus
extern "C"
{
#endif

extern void Ada_SetNewAddress(char*);

extern "C" void SetNewAddrBroker(char* ipAddress);

#ifdef __cplusplus
}
#endif

Interface.cpp

#include "Interface.h"
#include <stdio>

extern "C" void SetNewAddrBroker(char* ipAddress)
{
    printf("We passed the value -> %s", ipAddress);
    Ada_SetNewAddress(ipAddress);
    printf("Ada was called!\n");
}

Streamer.ads

with Interfaces.C;
with Interfaces.C.Strings;

package Streamer is
    procedure Initialize;
    procedure SetNewAddress(str : Interfaces.C.Strings.chars_ptr);
    pragma Export (C, SetNewAddress, "Ada_SetNewAddress");
end Streamer;

Streamer.adb

package body Streamer is
    Socket : Socket_Type;
    DefaultAddr : String := "127.0.0.1";
    Address : Sock_Addr_Type := (Family_Inet, Inet_Addr(DefaultAddr), 1024);
    Buffer : Stream_Access;

    procedure Initialize is
    begin
        Create_Socket(Socket, Family_Inet, Socket_Datagram);
        Buffer := Stream(Socket, Address);
    end;

    procedure SetNewAddress(str : Interfaces.C.Strings.chars_ptr)
        cstar : String := Interfaces.C.Strings.Value(str);
    begin
        Address := (Family_Inet, Inet_Addr(cstar), 1024);
        Buffer := Stream(socket, Address);
    end;
end Streamer;

When I call the C function SetNewAddrBroker("192.168.1.1") I get a 'data access' error, this is via telnet to the VxWorks machine that this code exists on, the Ada program is the main task, so I know it's not the missing "adainit() and adafinal()" calls. I can't figure out why it's throwing a random data access error. I can use putty or teraterm for the telnet client if that matters, both throw the same error.

THE ERROR OUTPUT

    We passed -> 192.168.1.1
    data access
    Exception current instruction address: 0x002e3ab0
    ............
    trcStack aborted: error in top frame
    Shell task 'tShellRem1' restarted...

Examining, the instruction that threw the error

    0x2e3ab0 stw r30,8(r9)

I do not know assembly but I imagine this is trying to store the string in a place that is too small?

I need to set the IP of the broker for the client at runtime, the Ada is the client, and the broker is just on my LAN. I want to be able to telnet to the Ada client and just update the ip address, but the only interface exposed to me is the C interpreter for the VxWorks box, so I'm stuck with interfacing with this.

VxWorks Version 6.3

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

‖放下 2025-01-24 20:59:06

以下是更改 https://codeshare.io/DZBnMO 中的代码的建议,以便它仍然调用 Ada来自 C(而不是发出 Ada 任务信号),但从 C 结构获取字符串而不使用辅助堆栈,因为所有字符串变量现在都具有静态已知长度:

在包 Streamer 中,将 GetNewAddress 的声明更改为:

subtype String_15 is String (1 .. 15);
type String_15_Ptr is access all String_15;

function GetNewAddress return String_15_Ptr;
pragma Import ( .. as before .. );

在包主体中Streamer,将 SetNewAddress 更改为如下:

procedure SetNewAddress
is -- (this "is" was missing from codeshare, btw)
   csize : constant Natural := Natural (GetNewAddressLen);
   cstrptr : constant String_15_Ptr := GetNewAddress;
   adaString : String_15;
begin
   for I in 1 .. csize loop
      adaString(I) := cstrptr(I);
   end loop;
   Address := (Family_Inet, Inet_Addr(adaString(1 .. csize)), 1024);
   Buffer := Stream (Socket, Address);
end;

请注意,我还没有编译此代码,但我希望它展示了避免二级堆栈的方法:每个全局和局部变量都必须具有静态大小,因此所有函数返回值类型都必须具有静态大小,但可以将动态大小的切片作为参数传递(因为 GNAT 使用引用传递)。

建议的 Ada 代码可能不完全可移植,因为它假设 C 类型(如“char *”)和 Ada 类型(如“String_15_Ptr”)之间存在某种对应关系,但在普通架构上,我希望它能够工作。

顺便说一句,您的 C 代码有一个潜在的缓冲区溢出错误:SetNewAddrBroker 应该使用 strncpy(),而不是 strcpy()。

Here is a suggestion on changing the code in https://codeshare.io/DZBnMO such that it still calls Ada from C (instead of signalling an Ada task), but gets the string from the C structure without using Secondary Stack, because all string variables now have a statically known length:

In package Streamer, change the declaration of GetNewAddress to be:

subtype String_15 is String (1 .. 15);
type String_15_Ptr is access all String_15;

function GetNewAddress return String_15_Ptr;
pragma Import ( .. as before .. );

In package body Streamer, change SetNewAddress as follows:

procedure SetNewAddress
is -- (this "is" was missing from codeshare, btw)
   csize : constant Natural := Natural (GetNewAddressLen);
   cstrptr : constant String_15_Ptr := GetNewAddress;
   adaString : String_15;
begin
   for I in 1 .. csize loop
      adaString(I) := cstrptr(I);
   end loop;
   Address := (Family_Inet, Inet_Addr(adaString(1 .. csize)), 1024);
   Buffer := Stream (Socket, Address);
end;

Note that I haven't compiled this code, but I hope it shows the method to avoid Secondary Stack: every global and local variable must have a static size, and so must all function return-value types, but it is possible to pass slices of dynamic size as parameters (because GNAT uses pass-by-reference there).

The suggested Ada code is maybe not fully portable, because it assumes a certain correspondence between C types like "char *" and Ada types like "String_15_Ptr", but on normal architectures I expect it to work.

By the way, your C code has a potential buffer-overflow bug: SetNewAddrBroker should use strncpy(), not strcpy().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文