How does snmpd process SNMP requests? - net-snmp

I am new to the SNMP protocol. I want to know how snmpd processes SNMP requests. For example:
snmpget -v1 -c public localhost sysName
My understanding is it is implementing MIBs, e.g. SNMPv2-MIB, but is executing the uname -n command?

For the net-snmp snmpd mapping for the sysname OID see system_mib.c where it is sometimes indeed based on uname, see code snippet below:
#ifdef HAVE_GETHOSTNAME
gethostname(sysName, sizeof(sysName));
#else
#ifdef HAVE_UNAME
strlcpy(sysName, utsName.nodename, sizeof(sysName));
#else
#if defined (HAVE_EXECV) && !defined (mingw32)
sprintf(extmp.command, "%s -n", UNAMEPROG);
/*
* setup defaults
*/
extmp.type = EXECPROC;
extmp.next = NULL;
exec_command(&extmp);
strlcpy(sysName, extmp.output, sizeof(sysName));
if (strlen(sysName) >= 1)
sysName[strlen(sysName) - 1] = 0; /* chomp new line */
#else
strcpy(sysName, "unknown");
#endif /* HAVE_EXECV */
#endif /* HAVE_UNAME */
#endif /* HAVE_GETHOSTNAME */
To understand how snmpd internally works look at agent architecture page on net-snmp site.
It is detailed and also explains how to extend net-snmp with new MIBs.

Related

Correct way of installing postgresql extension with custom library

TL;DR
One has to compile their custom library as shared library:
gcc -c -fPIC warp_client.c -o warp_client.o
gcc -shared warp_client.o libwarp-client.so
Include the shared library and additional dependencies of that shared library in the Postgresql Makefile with the flags SHLIB_LINK and PG_LDFLAGS(Here the bachelor_fdw.c is the extension to compile):
EXTENSION = bachelor_fdw
MODULE_big = bachelor_fdw
DATA = bachelor_fdw--0.1.sql
OBJS = bachelor_fdw.o
PG_LIBS = -lpq
SHLIB_LINK = -lwarp_client -lucp
PG_LDFLAGS += -L/usr/lib/warpdrive/ -L/usr/lib/ucx/
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
Include the directories of the shared libraries into the environment variable LD_LIBRARY_PATH of Postgresql. For that, one has to add a line to the file 'environment' in the main Postgresql directory and restart Postgresql. Here is mine:
$ cat /etc/postgresql/12/main/environment
# environment variables for postgres processes
# This file has the same syntax as postgresql.conf:
# VARIABLE = simple_value
# VARIABLE2 = 'any value!'
# I. e. you need to enclose any value which does not only consist of letters,
# numbers, and '-', '_', '.' in single quotes. Shell commands are not
# evaluated.
LD_LIBRARY_PATH='/usr/include/:/usr/include/ucx/:/usr/lib/:/usr/lib/ucx/'
I am trying to create a foreign data wrapper, which uses a custom library from me. The fdw compiles and installs fine, but when using it, symbols to my library are undefined. What is the proper way of using custom c code as library in a postgresql extension and what am i doing wrong? Here are the steps i took:
Compile my library (warp_client.c) with flag -fPIC into an object file.
gcc -c -fPIC warp_client.c -o static/warp_client.o
Create static library from the object file.
ar -rcs out/libwarp_client.a static/warp_client.o
Copy libwarp_client.a and warp_client.h into the postgresql extension project root.
Compile postgresql extension with the following makefile.
EXTENSION = bachelor_fdw
MODULE_big = bachelor_fdw
DATA = bachelor_fdw--0.1.sql libwarp_client.a
OBJS = bachelor_fdw.o
HEADERS = warp_client.h
ifdef DEBUG
$(info $(shell echo "debug ist an"))
endif
PG_LIBS = -lpq
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
make USE_PGXS=1 install
Try to create the extension. The extension makes a call to a library function in it's _PG_INI() function. Error comes up:
CREATE EXTENSION IF NOT EXISTS bachelor_fdw;
psql:only_create.sql:3: ERROR: could not load library "/usr/lib/postgresql/12/lib/bachelor_fdw.so": /usr/lib/postgresql/12/lib/bachelor_fdw.so: undefined symbol: warpclient_getData
The warp_client.h has the function headers and warp_client.c has the functions. warp_client.c includes "warp_client.h", bachelor_fdw.c (the extension) includes "warp_client.h".
warp_client.h:
#ifndef TEST_FIELD_UCP_WARP_CLIENT_H
#define TEST_FIELD_UCP_WARP_CLIENT_H
#include <ucp/api/ucp.h>
int warpclient_queryServer(char *server_addr_local, int port, int useINet6, char *query);
void *warpclient_getData();
int warpclient_cleanup();
#endif //TEST_FIELD_UCP_WARP_CLIENT_H
Any more desired info? I would be really glad for any help.
EDIT 1
I use the functions from warp_client.h inside of bachelor_fdw.c. Do i still need to export them? I thought only functions, which get called from the postgresql server needs to be exported.
Here is part of bachelor_fdw.c:
#include <warp_client.h>
#include "postgres.h"
#include "foreign/fdwapi.h"
#include "foreign/foreign.h"
#include "nodes/nodes.h"
#include "optimizer/pathnode.h"
#include "optimizer/planmain.h"
...
PG_MODULE_MAGIC;
/*
* SQL functions
*/
PG_FUNCTION_INFO_V1(bachelor_fdw_handler);
PG_FUNCTION_INFO_V1(bachelor_fdw_validator);
/*
* Extension initialization functions
*/
extern void _PG_init(void);
extern void _PG_fini(void);
/*
* FDW callback routines
*/
static void bachelorBeginForeignScan(ForeignScanState *node, int eflags);
static TupleTableSlot *bachelorIterateForeignScan(ForeignScanState *node);
static void bachelorReScanForeignScan(ForeignScanState *node);
static void bachelorEndForeignScan(ForeignScanState *node);
static void bachelorGetForeignRelSize(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid);
static void bachelorGetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid);
static ForeignScan* bachelorGetForeignPlan(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid, ForeignPath *best_path, List *tlist, List *scan_clauses, Plan *outer_plan);
void _PG_init(void){
int ret = 0;
void *data;
ret = warpclient_queryServer(NULL, -1, 0, "SELECT TEST FROM TEST;");
elog_debug("Testquery for server. Return code (%d)...\n", ret);
while(NULL != (data = warpclient_getData())){
elog_debug("Data received as fdw: %s\n", data);
}
elog_debug("Finished receiving data.\n");
/* Call cleanup */
ret = warpclient_cleanup();
elog_debug("Warpclient cleanup (%d)...\n", ret);
}
And here is part of warp_client.c:
#include "warp_client.h"
...
int warpclient_cleanup(){
int ret = 0;
//free buffers
free(recvbuffer->buffer);
free(recvbuffer);
/* Close the endpoint to the server */
debugmsg("Close endpoint.\n");
ep_close();
/* releasing UCX ressources */
ucp_worker_destroy(ucp_worker);
ucp_cleanup(ucp_context);
return ret;
}
int warpclient_queryServer(char *server_addr_local, int port, int useINet6, char *query){
/*
* Initialize important connection variables
*/
debugmsg("Initializing connection variables...\n");
if(NULL != server_addr_local) server_addr = server_addr_local;
if((port >= 0) && (port <= UINT16_MAX)) server_port = port;
if(useINet6) ai_family = AF_INET6;
int ret;
/* Initialize the UCX required objects worker and context*/
debugmsg("Initializing context and worker...\n");
ret = init_context_and_worker();
if (ret != 0) {
fprintf(stderr, "Initializing worker or context failed! Exiting..\n");
return -2;
}
/*
* UCP objects: client_ep as communication endpoint for the worker.
* status for function error code check.
*/
ucs_status_t status;
/* ep initialization and exchange with server over sockets */
debugmsg("Creating Client endpoint.\n");
status = create_client_endpoint();
if (status != UCS_OK) {
fprintf(stderr, "failed to start client (%s)\n", ucs_status_string(status));
return -1;
}
ret = send_query(query);
if(ret!=0){
debugmsg("Failed to connect to Server.\n");
}
return ret;
}
EDIT 2
I managed to get a good step forward thanks to Laurenz Albe. But i still have a problem with a shared library used in my shared library. Do I also need to link to shared libraries used in my own shared library, even though i linked that as i compiled my shared library before distribution?
what I did:
I added SHLIB_LINK = -lwarp_client to the Makefile and also needed the line PG_LDFLAGS += -L. for the linker to find libwarp_client.so.
I also managed to include the environment variable LD_LIBRARY_PATH for the postgres service, so that it can find my library in the standard places. And removed the library from the DATA flag in the Makefile.
New Makefile:
EXTENSION = bachelor_fdw
MODULE_big = bachelor_fdw
DATA = bachelor_fdw--0.1.sql
OBJS = bachelor_fdw.o
ifdef DEBUG
$(info $(shell echo "debug ist an"))
endif
PG_LIBS = -lpq
SHLIB_LINK = -lwarp_client
PG_LDFLAGS += -L.
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
Enrivonment variables:
/proc/1551/environ | xargs -0 -n 1 echo
LD_LIBRARY_PATH=/usr/include/:/usr/include/ucx/:/usr/lib/:/usr/lib/ucx/
...
When using CREATE on the extension, my library gets used but postgres complains about another shared library, which my library uses.
psql:only_create.sql:3: ERROR: could not load library "/usr/lib/postgresql/12/lib/bachelor_fdw.so": /usr/lib/warpdrive/libwarp_client.so: undefined symbol: ucp_ep_create
The error clearly says, it uses my shared library from a subdirectory "warpdrive" in the included standard directory. The shared library from UCP is also in that standard directory:
ls /usr/lib/ucx
cmake libjucx.so.0.0.0 libucp.a libucs.la libuct.so
jucx-1.12.1.jar libucm.a libucp.la libucs.so libuct.so.0
libjucx.a libucm.la libucp.so libucs.so.0 libuct.so.0.0.0
libjucx.la libucm.so libucp.so.0 libucs.so.0.0.0 pkgconfig
libjucx.so libucm.so.0 libucp.so.0.0.0 libuct.a ucx
libjucx.so.0 libucm.so.0.0.0 libucs.a libuct.la
That looks like warpclient_getData gets used in your code, but you didn't link your shared object with the library that provides the function. Add the library to the SHLIB_LINK variable:
SHLIB_LINK = -lwarp
(That example assumes a library called libwarp.so.)

compiling c language program with libcurl on windows

I am trying to compile a simple c program on windows 10 using gcc from the libcurl website I cloned vcpkg and then ran the .bat file , next I installed curl with the command vcpkg install curl and got this output
Computing installation plan...
The following packages are already installed:
curl[core,non-http,openssl,schannel,ssl,sspi]:x86-windows -> 7.80.0
Package curl:x86-windows is already installed
Restored 0 packages from C:\Users\<me>\AppData\Local\vcpkg\archives in 138.1 us. Use --debug to see more details.
Total elapsed time: 386.9 ms
The package curl provides CMake targets:
find_package(CURL CONFIG REQUIRED)
target_link_libraries(main PRIVATE CURL::libcurl)
#include <stdio.h>
#include <stdlib.h>
#include <curl/curl.h>
int report()
{
CURL* curl;
CURLcode res;
/* In windows, this will init the winsock stuff */
curl_global_init(CURL_GLOBAL_ALL);
/* get a curl handle */
curl = curl_easy_init();
if (curl) {
/* First set the URL that is about to receive our POST. This URL can
just as well be a https:// URL if that is what should receive the
data. */
curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.1.12:8000");
const char* c = const_cast<char*>(output.c_str());
printf ("%s", c);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, c );
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
int main()
{
report();
return 0;
}
Now when I try to compile the code above I get the error
c_example_curl.c:3:23: fatal error: curl/curl.h: No such file or directory
#include <curl/curl.h>
^
compilation terminated.
I am compiling using the command
gcc -lcurl file.c
I also tried using the command
gcc -lcurl -I F:\_C_\vcpkg\installed\x86-windows\include\curl file.c
doesn't seem to change anything
I even tried to copy the curl header file to the working directory of the above code but I was not lucky
How do you install libcurl for windows isn't there any command equivalent to the linux one
download curl for windows here.
unpack the zip and place it anywhere on the system (i personally prefer C:\curl).
then compile your script with: gcc file.c -I<path-to-curl> -L<path-to-curl>\lib -lcurl
NOTE: replace <path-to-curl> with the curl location on the system, for example C:\curl

How to execute C program in Linux or Windows simple commands to print a file

Hi there, I am trying to make a C program that will print herself source code.
I am assuming that the source code file and the execute file are in the same directory without any other .c files.
Well I have tried many codes, and it didn't worked out.
The error cause because the order of the commands (if it is windows command first it passed in windows OS and if it is a linux command first it passed in linux OS).
I am trying to ignore fopen and other functions and to use only simple OS commands.
Here is the code I have tried:
code working on windows:
/* C library statement */
#include <stdlib.h>
/* main program */
int main()
{/* start of main */
int windows = 0; /* a variable to check if we are running windows or unix operation system */
/* system function returns -1 value if it failed.
* so if unix value is -1 we are not running unix system.
* if we are not running unix system we will execute windows commands.
*/
windows = system("type *.c"); /* windows command to print file text */
if(windows == -1) /* if windows command failed (and the specific file is exists) then we are not running windows operation system */
system("cat *.c"); /* unix command to print file text */
return 0;
}/* end of main */
code working on linux:
/* this program will print herself source code by using simple linux or windows commands */
#include <stdlib.h>
/* main program */
int main()
{/* start of main */
int unix = 0; /* a variable to check if we are running windows or unix operation system */
/* system function returns -1 value if it failed.
* so if unix value is -1 we are not running unix system.
* if we are not running unix system we will execute windows commands.
*/
unix = system("cat *.c"); /* unix command to print file text */
if(unix == -1) /* if unix command failed (and the specific file is exists) then we are not running unix operation system */
system("type *.c"); /* windows command to print file text */
return 0;
}/* end of main */
well the problem is that linux recognize type as a bash command and windows is not compiling the cat command
I Made This Code Working, Can Be Compiled and Run in Both OS
#include <stdlib.h>
/* defining variables to check if what OS we are running in */
#if defined (_WIN32) || defined (_WIN64) /* if we are running win 32bit or win 64 bit */
#define HAVEWIN 1 /* defined we are running at windows OS */
#define HAVEUNIX 0 /* defined we are not running at unix OS */
#elif defined (__unix__) /* if we are running a unix OS */
#define HAVEUNIX 1 /* defined we are running at unix OS */
#define HAVEWIN 0 /* defined we are not running at unix OS */
#endif /* end of the OS checks */
/* main program */
int main()
{/* start of main */
if(HAVEWIN == 1) /* if we are running on windows OS */
system("type *.c"); /* use windows command to print file text */
else if(HAVEUNIX == 1) /* if we are running on unix OS */
system("cat *.c"); /* use unix command to print file text */
return 0;
}/* end of main */
The symbol __FILE__ always expands to the name of the current file. The following code will print the source code location:
#include <stdio.h>
int main()
{
printf("%s\n", __FILE__);
return 0;
}
So you should just then just add code to dump its contents.
But don't use system() calls, as this is not portable and very inefficient.

Qemu baremetal emulation - how to view UART output?

Question:
How do I get the UART output from a baremetal program run with Qemu?
Background
Here is the command line invocation I have been using:
qemu-system-arm -M xilinx-zynq-a9 -cpu cortex-a9 -nographic -kernel $BUILD_DIR/mm.elf -m 512M -s -S
using machine xilinx-zynq-a9
processor cortex-a9
as this is baremetal, the executable is a self contained ELF file
-m 512M signifies the platform has 512 MiB of RAM
-s is a shortcut for -gdb tcp::1234
-S means freeze CPU at startup
The ELF file I am using (mm.elf) performs a simple matrix multiply operation, and then prints whether it succeeded or failed, and how long it took to run. The ELF was compiled using the Xilinx ARM toolchain. I am using this for software fault injection. Currently I use GDB to ask for the values of the variables which are supposed to be printed. However, as there are many things which could go wrong with printing in the context of fault injection, it would be nice to see what is actually sent over UART.
Related answers:
redirect QEMU window output to terminal running qemu
This has some suggestions I tried, but it isn't applicable because the question was about getting the Linux boot messages in the host terminal window.
How to run a program without an operating system?
This is one isn't very related because it still assumes that the user has a bootloader of some kind. While there must technically be a bootloader for the application to run at all, Xilinx provides this system code in files like boot.S, which are then compiled into the ELF file as code which runs before main.
Things that I have tried:
I tried adding each of these onto the end of my current Qemu command. The results follow the parameters tried.
-serial mon:stdio
nothing
-serial null -serial mon:stdio (because Cortex-A9 has two UARTs)
nothing
the above two with -semihosting added
nothing
-serial stdio
cannot use stdio by multiple character devices
could not connect serial device to character backend 'stdio'
-console=/dev/tty
invalid option
-curses
black screen, no output
Investigation
I looked at the disassembly of the ELF file and verified that the address to which the the UART messages are being written is the same as the Qemu setup expects (info mtree). Base address is 0xe0000000, the same in both places.
Goal
I want to be able to capture the output of messages sent to UART. If this is done by redirecting to stdout, that's fine. If it goes through a TCP socket, that's fine too. The fault injection setup uses Python, and Qemu is running as a subprocess, so it would be easy to get the output from either one of those sources.
Note: when run in the fault injection setup, the Qemu invocation is
qemu-system-arm -M xilinx-zynq-a9 -cpu cortex-a9 -nographic -kernel $BUILD_DIR/mm.elf -m 512M -gdb tcp::3345 -S -monitor telnet::3347,server,nowait
The main differences being 1) the GDB port number is different (so multiple instances can run simultaneously) and 2) Qemu is to be controlled using a telnet connection over a socket, so it can be controlled by the Python script.
You need to initialize the UART prior to attempt outputing any characters.
The UART0 emulation is working fine for example by using a slightly modified version of this program:
/opt/qemu-4.2.0/bin/qemu-system-arm -semihosting --semihosting-config enable=on,target=native -nographic -serial mon:stdio -machine xilinx-zynq-a9 -m 768M -cpu cortex-a9 -kernel hello05.elf
Hello number 1
The output of the git diff command after modifications were made was:
diff --git a/Hello01/Makefile b/Hello01/Makefile
index 4a1b512..8d6d12a 100644
--- a/Hello01/Makefile
+++ b/Hello01/Makefile
## -1,10 +1,10 ##
ARMGNU ?= arm-linux-gnueabihf
-COPS =
+COPS = -g -O0
ARCH = -mcpu=cortex-a9 -mfpu=vfpv3
gcc : hello01.bin
-all : gcc clang
+all : gcc
clean :
rm -f *.o
## -15,8 +15,6 ## clean :
rm -f *.img
rm -f *.bc
-clang: hello02.bin
-
startup.o : startup.s
$(ARMGNU)-as $(ARCH) startup.s -o startup.o
diff --git a/Hello01/hello01.c b/Hello01/hello01.c
index 20cb4a4..14ed2a0 100644
--- a/Hello01/hello01.c
+++ b/Hello01/hello01.c
## -10,16 +10,16 ##
*/
-#define UART1_BASE 0xe0001000
-#define UART1_TxRxFIFO0 ((unsigned int *) (UART1_BASE + 0x30))
+#define UART0_BASE 0xe0000000
+#define UART0_TxRxFIFO0 ((unsigned int *) (UART0_BASE + 0x30))
-volatile unsigned int * const TxRxUART1 = UART1_TxRxFIFO0;
+volatile unsigned int * const TxRxUART0 = UART0_TxRxFIFO0;
void print_uart1(const char *s)
{
while(*s != '\0')
{ /* Loop until end of string */
- *TxRxUART1 = (unsigned int)(*s); /* Transmit char */
+ *TxRxUART0 = (unsigned int)(*s); /* Transmit char */
s++; /* Next char */
}
}
## -28,4 +28,4 ## void c_entry()
{
print_uart1("\r\nHello world!");
while(1) ; /*dont exit the program*/
-}
\ No newline at end of file
+}
diff --git a/Hello05/Makefile b/Hello05/Makefile
index 9d3ca23..bc9bb61 100644
--- a/Hello05/Makefile
+++ b/Hello05/Makefile
## -1,5 +1,5 ##
ARMGNU ?= arm-linux-gnueabihf
-COPS =
+COPS = -g -O0
ARCH = -mcpu=cortex-a9 -mfpu=vfpv3
gcc : hello05.bin
diff --git a/Hello05/hello05.c b/Hello05/hello05.c
index 1b92dde..01ce7ee 100644
--- a/Hello05/hello05.c
+++ b/Hello05/hello05.c
## -26,7 +26,7 ##
void c_entry()
{
- init_uart1_RxTx_115200_8N1();
+ init_uart0_RxTx_115200_8N1();
printf("\nHello number %d\n",1);
while(1) ; /*dont exit the program*/
}
diff --git a/Hello05/xuartps.c b/Hello05/xuartps.c
index bdf7ad1..74f68bd 100644
--- a/Hello05/xuartps.c
+++ b/Hello05/xuartps.c
## -16,42 +16,42 ##
void putc(int *p ,char c);
/*
-* Initiate UART1 ( /dev/ttyACM0 on host computer )
+* Initiate UART0 ( /dev/ttyACM0 on host computer )
* 115,200 Baud 8-bit No-Parity 1-stop-bit
*/
-void init_uart1_RxTx_115200_8N1()
+void init_uart0_RxTx_115200_8N1()
{
/* Disable the transmitter and receiver before writing to the Baud Rate Generator */
- UART1->control_reg0=0;
+ UART0->control_reg0=0;
/* Set Baudrate to 115,200 Baud */
- UART1->baud_rate_divider =XUARTPS_BDIV_CD_115200;
- UART1->baud_rate_gen= XUARTPS_BRGR_CD_115200;
+ UART0->baud_rate_divider =XUARTPS_BDIV_CD_115200;
+ UART0->baud_rate_gen= XUARTPS_BRGR_CD_115200;
/*Set 8-bit NoParity 1-StopBit*/
- UART1->mode_reg0 = XUARTPS_MR_PAR_NONE;
+ UART0->mode_reg0 = XUARTPS_MR_PAR_NONE;
/*Enable Rx & Tx*/
- UART1->control_reg0= XUARTPS_CR_TXEN | XUARTPS_CR_RXEN | XUARTPS_CR_TXRES | XUARTPS_CR_RXRES ;
+ UART0->control_reg0= XUARTPS_CR_TXEN | XUARTPS_CR_RXEN | XUARTPS_CR_TXRES | XUARTPS_CR_RXRES ;
}
-void sendUART1char(char s)
+void sendUART0char(char s)
{
/*Make sure that the uart is ready for new char's before continuing*/
- while ((( UART1->channel_sts_reg0 ) & UART_STS_TXFULL) > 0) ;
+ while ((( UART0->channel_sts_reg0 ) & UART_STS_TXFULL) > 0) ;
/* Loop until end of string */
- UART1->tx_rx_fifo= (unsigned int) s; /* Transmit char */
+ UART0->tx_rx_fifo= (unsigned int) s; /* Transmit char */
}
/* "print.h" uses this function for is's printf implementation */
void putchar(char c)
{
if(c=='\n')
- sendUART1char('\r');
- sendUART1char(c);
+ sendUART0char('\r');
+ sendUART0char(c);
}
/* <stdio.h>'s printf uses puts to send chars
## -61,9 +61,9 ## int puts(const char *s)
while(*s != '\0')
{
if(*s=='\n')
- sendUART1char('\r');
+ sendUART0char('\r');
- sendUART1char(*s); /*Send char to the UART1*/
+ sendUART0char(*s); /*Send char to the UART0*/
s++; /* Next char */
}
return 0;
diff --git a/Hello05/xuartps.h b/Hello05/xuartps.h
index fc5008f..64e3b88 100644
--- a/Hello05/xuartps.h
+++ b/Hello05/xuartps.h
## -13,7 +13,7 ##
#define u32 unsigned int
#endif
-#define UART1_BASE 0xe0001000
+#define UART0_BASE 0xe0000000
// Register Description as found in
// B.33 UART Controller (UART) p.1626
struct XUARTPS{
## -34,7 +34,7 ## struct XUARTPS{
u32 Flow_delay_reg0; /* Flow Control Delay Register def=0*/
u32 Tx_FIFO_trigger_level;}; /* Transmitter FIFO Trigger Level Register */
-static struct XUARTPS *UART1=(struct XUARTPS*) UART1_BASE;
+static struct XUARTPS *UART0=(struct XUARTPS*) UART0_BASE;
/*
Page 496
## -87,11 +87,11 ## static struct XUARTPS *UART1=(struct XUARTPS*) UART1_BASE;
#define XUARTPS_MR_CLKS_REF_CLK 0 /* 0: clock source is uart_ref_clk*/
/*
-* Initiate UART1 ( /dev/ttyACM0 on host computer )
+* Initiate UART0 ( /dev/ttyACM0 on host computer )
* 115,200 Baud 8-bit No-Parity 1-stop-bit
*/
-void init_uart1_RxTx_115200_8N1();
-void sendUART1char(char s);
+void init_uart0_RxTx_115200_8N1();
+void sendUART0char(char s);
int puts(const char *s);
//void putc((void*), char);
The command executed from the ZedBoard-BareMetal-Examples/Hello05 directory for building the modified Hello05 example was:
make ARMGNU=/opt/arm/9/gcc-arm-9.2-2019.12-x86_64-arm-none-eabi/bin/arm-none-eabi clean all
This being said, the last comment from your previous post made me think that you may just want to be able to see the output of your program, but not necessarily by using UART0.
If this is the case, using the Angel/Semihosting interface would do the job - I understand you may have attempted to go this way.
Example:
// hello.c:
#include <stdlib.h>
int main(int argc, char** argv)
{
printf("Hello, World!\n");
return EXIT_SUCCESS;
}
gcc command:
/opt/arm/9/gcc-arm-9.2-2019.12-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc -g -O0 --specs=rdimon.specs -o hello.elf hello.c
qemu command:
/opt/qemu-4.2.0/bin/qemu-system-arm -semihosting --semihosting-config enable=on,target=native -nographic -serial mon:stdio -machine xilinx-zynq-a9 -m 768M -cpu cortex-a9 -kernel hello.elf
Outcome:
Hello, World!
Using the semihosting interface would allow you to read/write files, read user input, and to use some of the xUnit testing frameworks available for either C or C++ - I have been for example successfully be using CppUnit with QEMU and the Semihosting interface. at several occasions.
I hope this help.

mingw64 pjsip sizeof(fd_set) always double sizeof(pj_fd_set_t) causing assertion in sock_select.c

I've compiled pjsip into my program that I'm writing in an msys2/mingw environment (64-bit). It compiles fine. However, when I run it in my program I'm getting an assertion
// Line 49 of ../src/pj/sock_select.c
sizeof(pj_fd_set_t)-sizeof(pj_sock_t)>=sizeof(fd_set)
Every time I run the program.
When I do some digging people talk about increasing PJ_IOQUEUE_MAX_HANDLES. So I did, and I put a printf in the function before the asserts to see what the sizes are:
// My PJ_FD_ZERO variant
PJ_DEF(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp)
{
printf( "PJ_IOQUEUE_MAX_HANDLES: %d, pj_fd_set_t: %I64d, pj_sock_t: %I64d, fd_set: %I64d\n", PJ_IOQUEUE_MAX_HANDLES, sizeof(pj_fd_set_t), sizeof(pj_sock_t), sizeof(fd_set) );
PJ_CHECK_STACK();
pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));
FD_ZERO(PART_FDSET(fdsetp));
PART_COUNT(fdsetp) = 0;
}
The program will output something like this:
10:27:43.477 os_core_win32.c !pjlib 2.9 for win32 initialized
10:27:43.507 sip_endpoint.c .Creating endpoint instance...
PJ_IOQUEUE_MAX_HANDLES: 16384, pj_fd_set_t: 65552, pj_sock_t: 4, fd_set: 131080
However, when I tweak PJ_IOQUEUE_MAX_HANDLES the size of pj_fd_set_t increases as it should but! the sizeof(fd_set) also becomes slight less than DOUBLE whatever sizeof(pj_fd_set_t) is! The winsock guide says that I cannot set the size of fd_set so I am very confused how the size is getting set! I don't see anywhere in the pjsip code that this is being set.
So adjusting PJ_IOQUEUE_MAX_HANDLES is quite the losing battle.
How can I fix this so my code will stop asserting?
Some references
Bash script that I ran to configure pjsip
#!/bin/bash
JOPT=1
DEBUG=false
BUILD_ALL=true
CLEAN_BEFORE_BUILD=false
TOUCH_COMMAND="touch configure.ac aclocal.m4 configure Makefile.am Makefile.in"
while getopts ":pdj:o:c" opt; do
case $opt in
j)
JOPT="$OPTARG"
;;
c)
echo "Clean before build is set."
CLEAN_BEFORE_BUILD=true;
;;
d)
DEBUG=true
;;
o)
IFS=', ' read -r -a BUILD_OPTS <<< "${OPTARG}"
BUILD_ALL=false
for option in "${BUILD_OPTS[#]}" ; do
# Set individual
case $option in
pjsip)
BUILD_PJSIP=true;
;;
*)
echo "Unknown build option ${option}"
exit
esac
done
;;
\?)
echo "Invalid option: -${OPTARG}" >&2
exit 1
;;
:)
echo "Option -${OPTARG} requires an argument." >&2
exit 1
;;
esac
done
# Make the out
mkdir out
OUT_PREFIX="$( pwd )/out"
export PKG_CONFIG_PATH="${OUT_PREFIX}/lib/pkgconfig:${PKG_CONFIG_PATH}"
if [ "$DEBUG" = true ] ; then
MAKEFLAGS="-g -O0"
else
MAKEFLAGS="-O2"
fi
# Main directory
LIB_DIRECTORY="$(pwd)/lib"
# Descend
cd "${LIB_DIRECTORY}"
pwd
# pjsip
cd "${LIB_DIRECTORY}/pjsip"
if [ "${BUILD_ALL}" = true ] || [ "${BUILD_PJSIP}" = true ] ; then
eval $TOUCH_COMMAND
./configure CFLAGS="${MAKEFLAGS} -I${OUT_PREFIX}/include" CXXFLAGS="${MAKEFLAGS}" LDFLAGS="-L${OUT_PREFIX}/lib" \
--prefix="${OUT_PREFIX}" \
--disable-openh264 \
--disable-v4l2 \
--disable-ffmpeg \
--enable-libsamplerate \
--disable-video \
--enable-shared \
--disable-static \
--disable-libyuv \
--with-external-speex \
--with-gnutls \
|| exit
if [ "${CLEAN_BEFORE_BUILD}" = true ] ; then
make clean
fi
# Without this it breaks on msys2
make -j $JOPT dep || exit
# Make the actual
make -j $JOPT || exit
# Note, had issue with writing to //c/.../pkgconfig/libproject.pc
make install || exit
fi
The assert screenshot
--Edit--
Funny enough when I run this program the sizeof( fd_set ) is 520.
#include <winsock.h>
#include <iostream>
int main( int argc, char *argv[] )
{
std::cout <<
"sizeof( fd_set )=" << sizeof( fd_set ) << "\n"
"FD_SETSIZE=" << FD_SETSIZE << std::endl;
return( EXIT_SUCCESS );
}
Result:
sizeof( fd_set )=520
FD_SETSIZE=64
I'm that guy again answering my own question.
I think what was going on is that pjsip wasn't detecting that I was using windows with mingw despite it being detected on configure.
checking build system type... x86_64-w64-mingw32
checking host system type... x86_64-w64-mingw32
checking target system type... x86_64-w64-mingw32
I found this little nugget in the types.h
/** Socket handle. */
#if defined(PJ_WIN64) && PJ_WIN64!=0
typedef pj_int64_t pj_sock_t;
#else
typedef long pj_sock_t;
#endif
I think realized that pj_fd_set_t (which is comprised of pj_sock_t) would be smaller always than fd_set (which is comprised of fd) if the sizes are off. That would explain the proportional phenomenon. This is also because PJSIP defines FD_SETSIZE on Windows when detected.
So I just ran ./configure as I did above and then manually modified:
build.mak
build/os-auto.mak
Replacing PJ_AUTOCONF=1 with PJ_WIN32=1.
Then I manually modified the Makefile explicitly including the correct file.
include build/os-win32.mak
And then I compiled using make dep && make && make install
Finally, when I compiled it into my program it complained about implementing unicode string functions, so I looked at the file threw the error (pj/compat/string.h). I found the line #if defined(_MSC_VER) and added some more definitions as below to support MINGW macros.
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
# define strcasecmp _stricmp
# define strncasecmp _strnicmp
# define snprintf _snprintf
# define vsnprintf _vsnprintf
# define snwprintf _snwprintf
# define wcsicmp _wcsicmp
# define wcsnicmp _wcsnicmp
#else
# define stricmp strcasecmp
# define strnicmp strncasecmp
# if defined(PJ_NATIVE_STRING_IS_UNICODE) && PJ_NATIVE_STRING_IS_UNICODE!=0
# error "Implement Unicode string functions"
# endif
#endif
Then it worked!

Resources