I've got a very basic, bare minimum libusb example going, which compiles, but the output produced by the following application:
#include <stdio.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>
int main(void) {
puts("Looking for USB devices...");
libusb_device **devices;
libusb_context *context = NULL;
ssize_t device_count = 0;
device_count = libusb_get_device_list(context, &devices);
if(device_count < 0) {
puts("Unable to retrieve USB device list!");
}
printf("%lu devices found\n", device_count);
return EXIT_SUCCESS;
}
is as follows:
Looking for USB devices...
Segmentation fault: 11
The failure occurs on line 13:
device_count = libusb_get_device_list(context, &devices);
I'm running the above on Mac OS X 10.9, and have libusb version 1.0.9 installed via Homebrew.
Any idea what could be the problem?
The code misses to initialise context.
Call libusb_init() prior to any operation on libusb.
Add a line like this before issueing any other call into libusb:
int result = libusb_init(&context);
if (0 > result)
{
fprintf(stderr, "libusb_init() failed with %d.\n", result);
exit(EXIT_FAILURE);
}
Related
(I have completely rewritten this question, as I have a minimal example now; see in history how original post looked like)
Consider this libusb program, which I compile under MINGW64 (part of MSYS2, which is updated as of today) on Windows 10 (also with latest updates as of today):
libusb-test.c
// build under MINGW64 on Windows with (assuming mingw64/mingw-w64-x86_64-libusb 1.0.26-1 installed):
// gcc -Wall -g -I/mingw64/include/libusb-1.0 libusb-test.c -o libusb-test.exe -lusb-1.0
#include <inttypes.h> //PRIu64
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "libusb.h"
int main(int argc, char *argv[]) {
libusb_device **devs;
ssize_t cnt;
int r=0, i;
struct libusb_device_descriptor desc;
r = libusb_init(NULL);
if (r < 0) {
printf("error: Cannot libusb_init, exiting\r\n");
return r;
}
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0) {
printf("error: Cannot libusb_get_device_list (Failed to enumerate USB devices), exiting\r\n");
libusb_exit(NULL);
return 1;
}
for (i = 0; devs[i]; i++) { // or: for (libusb_device **dev = devs; *dev; dev++)
libusb_device *dev = devs[i];
libusb_device_handle *handle = NULL;
printf("Trying device %d: %p\r\n", i, dev);
int ret = libusb_get_device_descriptor(dev, &desc);
if (ret) {
printf(" Failed to read device %d descriptor (%d)\r\n", i, ret);
} else {
ret = libusb_open(dev, &handle);
if (ret) {
printf(" Failed to open device %d (%d)\r\n", i, ret);
} else {
printf( " device %d open ( handle %p )\r\n", i, handle);
}
if (handle) {
libusb_close(handle);
handle = NULL;
}
}
} // end for
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
printf("Program finished; exiting.");
return r;
}
The program, after compiling, actually seems to run fine:
$ ./libusb-test.exe
Trying device 0: 000001eeb9321890
Failed to open device 0 (-5)
Trying device 1: 000001eeb9320c30
device 1 open ( handle 000001eeb93242e0 )
...
Trying device 12: 000001eeb9322640
device 12 open ( handle 000001eeb93242e0 )
Trying device 13: 000001eeb7a7bc50
Failed to open device 13 (-12)
Program finished; exiting.
... however, if I try to debug with gdb by breaking into main - it fails with "Cannot insert breakpoint":
$ gdb --args ./libusb-test.exe
GNU gdb (GDB) 12.1
...
Reading symbols from ./libusb-test.exe...
(gdb) b main
Breakpoint 1 at 0x140001593: file libusb-test.c, line 11.
(gdb) r
Starting program: C:\msys64\tmp\libusb-test.exe
[New Thread 20144.0x24c0]
[New Thread 20144.0x436c]
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x140001584
Command aborted.
(gdb)
Why does this happen - and how can I get gdb to break into this program?
I've been following the official documentation on creating a TUN device. There's very little documentation, but what even is there does not seem to work. Here's what I have so far:
#include <linux/if.h>
#include <linux/if_tun.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
int tun_alloc(char *dev)
{
struct ifreq ifr;
int fd, err;
if( (fd = open("/dev/net/tun", O_RDWR)) < 0 )
return 7; // tun_alloc_old(dev); // this does not happen, linux docs don't say what tun_alloc_old is anyway
memset(&ifr, 0, sizeof(ifr));
/* Flags: IFF_TUN - TUN device (no Ethernet headers)
* IFF_TAP - TAP device
*
* IFF_NO_PI - Do not provide packet information
*/
ifr.ifr_flags = IFF_TUN;
if( *dev ) {
printf("setting ifr.ifr_name to \"%s\"\n", dev);
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
printf("ifr.ifr_name is \"%s\"\n", ifr.ifr_name);
if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
perror("ERR");
close(fd);
printf("GOT ERROR: %d\n", err);
return err;
}
printf("past TUNSETIFF error checking\n");
strcpy(dev, ifr.ifr_name);
return fd;
}
int main() {
char name[128];
strcpy(&name, "tun23");
int tun = tun_alloc(name);
printf("tun_alloc: %s id: %d\n", name, tun);
if(tun == -1) return -1;
while(1) {
printf("in loop\n");
char buf[128];
ssize_t readAmount = read(tun, buf, 128);
printf("finished read\n");
if(readAmount == -1) {
printf("read 0 bytes\n");
continue;
}
printf("Read %d: ", readAmount);
for(int i = 0; i < 128; i++) {
printf("%hhx", buf[i]);
}
printf("\n");
}
return tun;
}
Compiler step is gcc -g3 test.c && a.out.
When ran as non-root, I get this output
setting ifr.ifr_name to "tun23"
ifr.ifr_name is "tun23"
ERR: Operation not permitted
GOT ERROR: -1
tun_alloc: tun23 id: -1
And as root, it successfully gets into the loop, but then the call to read seems to block.
setting ifr.ifr_name to "tun23"
ifr.ifr_name is "tun23"
past TUNSETIFF error checking
tun_alloc: tun23 id: 3
in loop
(In the event of an XY problem, the reason I'm doing this is to try and make a very simple vpn-like application)
The issue is that while it's blocking in this loop, no TUN devices are created. I am looking in /dev/. I'm not sure how I would give it any bytes to read.
Edit: added a proper perror call and the respective output Operation not permitted, valgrind output, and a couple print statements. Going to try and debug the strcpy error.
Edit: fixed the strcpy error, was pretty simple. Seems to fail in non-root due to a lack of permission to create TUN devices.
I have weird problem. I try to communicate with ifm AY1020 via modbusTCP using libmodbus from PC.
My code looks as follow:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <modbus/modbus.h>
int main()
{
modbus_t *ctx;
uint16_t *tab_reg;
int rc;
int i;
ctx = modbus_new_tcp("192.168.1.250", 502);
modbus_set_debug(ctx, TRUE);
tab_reg = (uint16_t *) malloc(5 * sizeof(uint16_t));
memset(tab_reg, 0, 5 * sizeof(uint16_t));
if (modbus_connect(ctx) == -1)
{
fprintf(stderr, "Connection failed: %s\n",modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
rc = modbus_read_registers(ctx, 3002, 2, tab_reg);
if (rc == -1)
{
fprintf(stderr, "%s\n", modbus_strerror(errno));
return -1;
}
for (i=0; i < rc; i++) {
printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
}
modbus_close(ctx);
modbus_free(ctx);
}
Thanks to debug I was able to get the frame that is generated in modbus_read_registers function:
[00][01][00][00][00][06][FF][03][0B][BA][00][02]
And I get this
ERROR Gateway path unavailable
Gateway path unavailable
After analysis you can find that device id in that frame is FF, but according to this error PLC expects 1.
Going further if during debugging I force change this value from FF to 01 everything works fine. It looks like it assign wrong ID.
I would be grateful for any help, advice, solution.
Best,
Paweł
Looking at the Man
You should call modbus_set_slave to set a specific destination device.
TCP
The slave number is only required in TCP if the message must reach a device on a serial network. The special value MODBUS_TCP_SLAVE (0xFF) can be used in TCP mode to restore the default value.
Emphasis mine
Your code should be
modbus_set_slave(ctx, 1);
rc = modbus_read_registers(ctx, 3002, 2, tab_reg);
I have a program in which I use ioctl(0, TIOCGWINSZ, (struct winsize *)) to find the size of the terminal window the program is running in. When I run it in the terminal, it works fine, but when I use LLDB, ioctl gives a window size of 0 x 0.
Example:
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdio.h>
int main(){
struct winsize tty_window_size;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &tty_window_size);
printf("Rows: %i, Cols: %i\n", tty_window_size.ws_row, tty_window_size.ws_col);
return 0;
}
Terminal transcript:
$ clang test.c
$ ./a.out
Rows: 24, Cols: 80
$ lldb ./a.out
(lldb) target create "./a.out"
Current executable set to './a.out' (x86_64).
(lldb) r
Process 32763 launched: './a.out' (x86_64)
Rows: 0, Cols: 0
Process 32763 exited with status = 0 (0x00000000)
Does anybody why this happens, or a way to fix this?
Thanks in advance.
lldb uses pty's to handle program input & output, but it seems like a bug that they aren't set to track lldb's terminal size. Please file that with the lldb.llvm.org bug tracker.
If you are on OS X, you can run your app in a separate Terminal window (which is probably what you want if you're doing anything fancy with the terminal anyway) by launching it like:
(lldb) process launch -tty
I don't know if this has been implemented on Linux yet or not.
Not sure it is useful since it is an old post. Anyway... I faced the same problem and found a workaround. if ioctl on stdout fails, then try with /dev/tty
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
void getTerminalSize(int *row, int *col) {
struct winsize ws;
*row = *col = 0; /* default value (indicates an error) */
if (!isatty(STDOUT_FILENO)) {
return;
}
ws.ws_row = ws.ws_col = 0;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_row == 0 || ws.ws_col == 0) {
int fd = open("/dev/tty", O_RDONLY);
if (fd != -1) {
ioctl(fd, TIOCGWINSZ, &ws);
close (fd);
}
}
*row = ws.ws_row;
*col = ws.ws_col;
}
int main(){
int row, col;
getTerminalSize(&row, &col);
printf("Row: %i, Col: %i\n", row, col);
return 0;
}
I'm fairly unexperienced with C and am running into a "Bus error" that I cannot understand the cause of. I had never heard of gdb but came across it on this forum and tried using it on my problem program and got the following output:
% gdb Proc1 GNU gdb 5.0
...
This GDB was
configured as
"sparc-sun-solaris2.8"...
(no
debugging symbols found)...
(gdb) run
Starting program:
/home/0/vlcek/CSE660/Lab3/Proc1
(no
debugging symbols found)...
(no
debugging symbols found)...
(no
debugging symbols found)...
Program
received signal SIGSEGV, Segmentation
fault. 0x10a64 in main ()
I have no idea what this means, is that saying there's an error in line 10 in my code? If so, line 10 in my code is merely "int main()" so I'm not sure the issue there... When I try running the program all it says is "Bus error" so I'm not sure where to go from here. I even tried putting a printf right after main and it doesn't print the string, only gives me a Bus error.
Below is my code:
// Compilation Command: gcc -o Proc1 Proc1.c ssem.o sshm.o
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ssem.h"
#include "sshm.h"
// Code of Proc1
int main()
{int i, internal_reg;
int key1 = 111111, key2 = 222222, key3 = 333333, key4 = 444444;
/* here create and initialize all semaphores */
int sem1 = sem_create(key1, 1);
if (sem1 < 0) {
perror("sem failed");
}
int sem2 = sem_create(key2, 1);
if (sem2 < 0) {
perror("sem failed");
}
int sem3 = sem_create(key3, 1);
if (sem3 < 0) {
perror("sem failed");
}
int sem4 = sem_create(key4, 1);
if (sem4 < 0) {
perror("sem failed");
}
/* here created: shared memory array Account of size 3 */
int *Account;
int shmid = shm_get(123456, (void**) &Account, 3*sizeof(int));
if (shmid < 0) {
perror("shm failed");
}
Account[0]=10000;
Account[1]=10000;
Account[2]=10000;
/* synchronize with Proc2, Proc3 and Proc4 (4 process 4 way synchronization)*/
for (i = 0; i < 1000; i++)
{
sem_signal(sem1);
sem_signal(sem1);
sem_signal(sem1);
internal_reg = Account[0];
internal_reg = internal_reg - 200;
Account[0] = internal_reg;
/* same thing, except we're adding $100 to Account1 now... */
internal_reg = Account[1];
internal_reg = internal_reg + 200;
Account[1] = internal_reg;
if (i % 100 == 0 && i != 0) {
printf("Account 0: $%i\n", Account[0]);
printf("Account 1: $%i\n", Account[1]);
}
if (i == 300 || i == 600) {
sleep(1);
}
sem_wait(sem2);
sem_wait(sem3);
sem_wait(sem4);
}
/* Here add a code that prints contents of each account
and their sum after 100th, 200th, 300th, ...., and 1000th iterations*/
}
/*in the code above include some wait and signal operations on semaphores. Do no
t over-synchronize. */
Here is the documentation for ssem and sshm:
/*
* ssem.c
*
* Version 1.0.0
* Date : 10 Jan 2002
*
*/
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include "ssem.h"
#define PERMS 0600
static struct sembuf op_lock[1] = {
0, -1, 0
};
static struct sembuf op_unlock[1] = {
0, 1, IPC_NOWAIT
};
int sem_create(int key,int initval)
{
int semid,i;
semid = semget((key_t)key, 1, IPC_CREAT | PERMS);
for(i=0;i<initval;i++)
semop(semid,&op_unlock[0],1);
return semid;
}
int sem_open(int key)
{
int semid;
semid = semget(key,0,0);
return semid;
}
int sem_wait(int semid)
{
return semop(semid,&op_lock[0],1);
}
int sem_signal(int semid)
{
return semop(semid,&op_unlock[0],1);
}
int sem_rm(int semid)
{
return semctl(semid, 0, IPC_RMID, 0);
}
/*
* sshm.c
*
* Routines for Simpler shared memory operations
* Version : 1.0.0.
* Date : 10 Jan 2002
*
*/
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include "sshm.h"
#define PERMS 0600
int shm_get(int key, void **start_ptr, int size)
{
int shmid;
shmid = shmget((key_t) key, size, PERMS | IPC_CREAT);
(*start_ptr) = (void *) shmat(shmid, (char *) 0, 0);
return shmid;
}
int shm_rm(int shmid)
{
return shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0);
}
After compiling Proc1.c with the -ggdb flag and running gdb I got the following:
Program received signal SIGSEGV,
Segmentation fault. 0x10a64 in main ()
at Proc1.c:36
36 Account[0]=10000
Why would this cause a segmentation fault?
After changing the declaration of Account to
int *Account = 0;
and adding
printf("Account == %p\n", Account);
before Account[0] = 10000;
I get the following upon running Proc1:
Account == ffffffff
Bus error
In order to get more sensible results from gdb you should compile your program with the -ggdb option. This will then include debugging information (like line numbers) into your program.
What you are currently seeing is the memory address (0x10a64) of the program counter. This will not help you very much unless you can correlate the assembly instructions you find there with a part of your C program yourself.
It looks like you are using shm_get properly. I think the library designer has made a terrible mistake in naming the function so similarly to shmget.
It's just as I thought. The Account pointer is ending up with an invalid value (aka 0xffffffff (aka (void *)(-1))) in it. The value (void *)(-1) generally indicates some sort of error, and it is explicitly mentioned in the manpage for shmat. This indicates that the shmat call inside the library failed. Here is how you can tell if it failed:
if (Account == (void *)(-1)) {
perror("shmat failed");
}
Account[0] = 10000;
// ...
Now, why it failed is an interesting mystery. Apparently the shmget call succeeded.
Personally, I think System V IPC is basically deprecated at this point and you should avoid using it if you can.
Depending on your compiler and your compiler options you might encounter an aliasing problem because your are casting the address of your Account pointer. These oldish interfaces are not in phase with modern antialiasing rules, meaning that the optimizer supposes that the value of Account wouldn't change.
Also you should get the argument for shm_get as close as possible to the expected type. Try perhaps something like the following.
void volatile* shmRet;
int shmid = shm_get(123456, (void**) &shmRet, 3*sizeof(int));
int *Account = shmRet;
I don't have the same architecture, so I don't know the exact prototype of your shm_get but usually it is also a bad idea to use fixed keys for this type of functions. There should be some function that returns you some key to use in your application.