C: struct X has no member named Y - c

I am working on a project with the XINU OS and while adding pipes to the system I get a compiler error when trying to add and use a new member to a struct I made earlier.
I honestly can not see what is wrong with my code, especially when I compare it to working pieces that vary by a variable name.
"/pipcreate.c:21: error: 'struct pipent' has no member named 'owner'"
As for the two lines commented out (reader = PR_CURR, writer = PR_CURR) if I uncomment those, and comment out the 'owner' line, it does compile fine.
Does anything stand out as the obvious problem, and I am just completely overlooking it?
pipe.h
/*typedef int32 pipid32 inside of kernel.h*/
/* Max number of pipes in the system */
#ifndef NPIP
#define NPIP 10
#endif
/* Pipe state constants */
#define PIPE_FREE 0 /* pipe table entry is unused */
#define PIPE_USED 1 /* pipe is currently used */
#define PIPE_CONNECTED 2 /* pipe is currently connected */
/* Misc pipe definitions */
#define isbadpipid(x) ( ((pid32)(x) < 0) || \
((pid32)(x) >= NPIP) || \
(piptab[(x)].pipstate == PIPE_FREE))
/* Definition of pipe table */
struct pipent { /* entry in the pipe table */
uint32 pipstate; /* pipe state: PIP_FREE, ect. */
uint32 pipid; /* pipe ID in table */
char buffer[256]; /* buffer to write to */
pid32 writer; /* pid for writer */
pid32 reader; /* pid for reader */
pid32 owner; /* CURR_PID upon pipe being created */
};
extern struct pipent piptab[];
extern int32 pipcount;
pipcreate.c
#include <xinu.h>
#include <string.h>
static pipid32 newpipid(void);
/*------------------------------------------------------------------------
* pipcreate -
*------------------------------------------------------------------------
*/
syscall pipcreate(void){
intmask mask; /* saved interrupt mask */
//struct pipent piptab[];
struct pipent *piptr; /* ptr to pipe's table entry */
pipid32 pipid; /* ID of newly created pipe */
mask = disable();
pipid = newpipid(); /* pipid to return */
piptr->pipstate = PIPE_USED;
piptr->owner = PR_CURR;
//piptr->writer = PR_CURR;
//piptr->reader = PR_CURR;
pipcount++; /* increment number of pipes */
piptr = &piptab[pipid];
restore(mask);
return pipid;
}
//newpipid - obtain a new (free) pipe ID
local pipid32 newpipid(void)
{
uint32 i;
static pipid32 nextpipid = 1;
/* Check all NPIP slots */
for(i = 0; i < NPIP; i++){
nextpipid %= NPIP; /* wrap around to beginning */
if(piptab[nextpipid].pipstate == PIPE_FREE){
return nextpipid++;
} else {
nextpipid++;
}
}
return (pid32) SYSERR;
}

One possibility is that the source file pipcreat.c is not actually including pipe.h (from the shown #include list, it appears not). A simple check for this would be to add a blatant syntax error to pipe.h and see if the compiler complains about it.

If you're using gcc, add the -M option to the compiler command line - it'll spit out the full path of all the header files being included. grep that output for pipe.h and you'll find out why yours isn't being used.

So I think the problem was something to do with having some object files still present after making changes and compiling again.
Basically I think I just had to run clean from my Makefile first, which I thought I had done, but maybe not.

It is a problem of the version of jvmti.h used by the jdk. A new method that exist in recent version of jvmti.h but dont exist before.

Related

What kinds of data in a device driver can be shared among processes?

In device drivers, how can we tell what data is shared among processes and what is local to a process? The Linux Device Drivers book mentions
Any time that a hardware or software resource is shared beyond a single thread of execution, and the possibility exists that one thread could encounter an inconsistent view of that resource, you must explicitly manage access to that resource.
But what kinds of software resources can be shared among threads and what kinds of data cannot be shared? I know that global variables are generally considered as shared memory but what other kinds of things need to be protected?
For example, is the struct inode and struct file types passed in file operations like open, release, read, write, etc. considered to be shared?
In the open call inside main.c , why is dev (in the line dev = container_of(inode->i_cdev, struct scull_dev, cdev);) not protected with a lock if it points to a struct scull_dev entry in the global array scull_devices?
In scull_write, why isn't the line int quantum = dev->quantum, qset = dev->qset; locked with a semaphore since it's accessing a global variable?
/* In scull.h */
struct scull_qset {
void **data; /* pointer to an array of pointers which each point to a quantum buffer */
struct scull_qset *next;
};
struct scull_dev {
struct scull_qset *data; /* Pointer to first quantum set */
int quantum; /* the current quantum size */
int qset; /* the current array size */
unsigned long size; /* amount of data stored here */
unsigned int access_key; /* used by sculluid and scullpriv */
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev; /* Char device structure */
};
/* In main.c */
struct scull_dev *scull_devices; /* allocated in scull_init_module */
int scull_major = SCULL_MAJOR;
int scull_minor = 0;
int scull_nr_devs = SCULL_NR_DEVS;
int scull_quantum = SCULL_QUANTUM;
int scull_qset = SCULL_QSET;
ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
struct scull_dev *dev = filp->private_data; /* flip->private_data assigned in scull_open */
struct scull_qset *dptr;
int quantum = dev->quantum, qset = dev->qset;
int itemsize = quantum * qset;
int item; /* item in linked list */
int s_pos; /* position in qset data array */
int q_pos; /* position in quantum */
int rest;
ssize_t retval = -ENOMEM; /* value used in "goto out" statements */
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
/* find listitem, qset index and offset in the quantum */
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest / quantum;
q_pos = rest % quantum;
/* follow the list up to the right position */
dptr = scull_follow(dev, item);
if (dptr == NULL)
goto out;
if (!dptr->data) {
dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);
if (!dptr->data)
goto out;
memset(dptr->data, 0, qset * sizeof(char *));
}
if (!dptr->data[s_pos]) {
dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
if (!dptr->data[s_pos])
goto out;
}
/* write only up to the end of this quantum */
if (count > quantum - q_pos)
count = quantum - q_pos;
if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) {
retval = -EFAULT;
goto out;
}
*f_pos += count;
retval = count;
/* update the size */
if (dev->size < *f_pos)
dev->size = *f_pos;
out:
up(&dev->sem);
return retval;
}
int scull_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev; /* device information */
/* Question: Why was the lock not placed here? */
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */
/* now trim to 0 the length of the device if open was write-only */
if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
scull_trim(dev); /* ignore errors */
up(&dev->sem);
}
return 0; /* success */
}
int scull_init_module(void)
{
int result, i;
dev_t dev = 0;
/* assigns major and minor numbers (left out for brevity) */
/*
* allocate the devices -- we can't have them static, as the number
* can be specified at load time
*/
scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);
if (!scull_devices) {
result = -ENOMEM;
goto fail; /* isn't this redundant? */
}
memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));
/* Initialize each device. */
for (i = 0; i < scull_nr_devs; i++) {
scull_devices[i].quantum = scull_quantum;
scull_devices[i].qset = scull_qset;
init_MUTEX(&scull_devices[i].sem);
scull_setup_cdev(&scull_devices[i], i);
}
/* some other stuff (left out for brevity) */
return 0; /* succeed */
fail:
scull_cleanup_module(); /* left out for brevity */
return result;
}
/*
* Set up the char_dev structure for this device.
*/
static void scull_setup_cdev(struct scull_dev *dev, int index)
{
int err, devno = MKDEV(scull_major, scull_minor + index);
cdev_init(&dev->cdev, &scull_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &scull_fops; /* isn't this redundant? */
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}
All data in memory can be considered a "shared resource" if both threads are able to access it*. The only resource they wouldn't be shared between processors is the data in the registers, which is abstracted away in C.
There are two reasons that you would not practically consider two resources to be shared (even though they do not actually mean that two threads could not theoretically access them, some nightmarish code could sometimes bypass these).
Only one thread can/does access it. Clearly if only one thread accesses a variable then there can be no race conditions. This is the reason local variables and single threaded programs do not need locking mechanisms.
The value is constant. You can't get different results based on order of access if the value can never change.
The program you have shown here is incomplete, so it is hard to say, but each of the variables accessed without locking must meet one of the criteria for this program to be thread safe.
There are some non-obvious ways to meet the criteria, such as if a variable is constant or limited to one thread only in a specific context.
You gave two examples of lines that were not locked. For the first line.
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
This line does not actually access any variables, it just computes where the struct containing cdev would be. There can be no race conditions because nobody else has access to your pointers (though they have access to what they point to), they are only accessible within the function (this is not true of what they point to). This meets criteria (1).
The other example is
int quantum = dev->quantum, qset = dev->qset;
This one is a bit harder to say without context, but my best guess is that it is assumed that dev->quantum and dev->qset will never change during the function call. This seems supported by the fact that they are only called in scull_init_module which should only be called once at the very beginning. I believe this fits criteria (2).
Which brings up another way that you might change a shared variable without locking, if you know that other threads will not try to access it until you are done for some other reason (eg they are not extant yet)
In short, all memory is shared, but sometimes you can get away with acting like its not.
*There are embedded systems where each processor has some amount of RAM that only it could use, but this is not the typical case.

MSP430 SD card application running on top of FATFS appears too restrictive . Is my understanding correct?

I am working my way through an SD card application code example provided by TI for their MSP530 LaunchPad microcontroller development kit. It appears that the example restricts the number of directories and number of files to 10 each (a total of 100 files) which seems overly restrictive for a 32GB SD card. The current code compiles to use less than half of the program space and less than half of available RAM. I am wondering if I misunderstand the code, or if the code is limited by some other reason, such as the available stack size in memory. Below is the code and my comments.
There are several layers: SDCardLogMode, sdcard (SDCardLib), and ff (HAL layer). I've reduced the code below to illustrate the constructions but not runnable - I am more interested if I understand it correctly and if my solution to increase the number of allowed files and directories is flawed.
SDCardLogMode.c there are two places of interest here. The first is the declaration of char dirs[10][MAX_DIR_LEN] and files[10][MAX_FILE_LEN]. the MAX LENs are 8 and 12 respectively and are the maximum allowed length of a name.
/*******************************************************************************
*
* SDCardLogMode.c
* ******************************************************************************/
#include "stdlib.h"
#include "string.h"
#include "SDCardLogMode.h"
#include "driverlib.h"
#include "sdcard.h"
#include "HAL_SDCard.h"
#pragma PERSISTENT(numLogFiles)
uint8_t numLogFiles = 0;
SDCardLib sdCardLib;
char dirs[10][MAX_DIR_LEN];
char files[10][MAX_FILE_LEN]; //10 file names. MAX_FILE_LEN =10
uint8_t dirNum = 0;
uint8_t fileNum = 0;
#define MAX_BUF_SIZE 32
char buffer[MAX_BUF_SIZE];
// FatFs Static Variables
static FIL fil; /* File object */
static char filename[31];
static FRESULT rc;
//....
Later in the same SDCardLogMode.c file is the following function (also reduced for readability). Here the interesting thing is that the code calls SDCardLib_getDirectory(&sdCardLib, "data_log", dirs, &dirNum, files, &fileNum) which consume the "data_log" path and produces dir, and updates &dirNum, files, and &fileNum. I do not believe &sdCardLib (which holds a handle to the FATFS and an interface pointer) is used in this function. At least not that I can tell.
What is puzzling is what's the point of calling SDCardLib_getDirectory() and then not using anything it produces? I did not find any downstream use of the dirs and files char arrays. Nor did I find any use of dirNum and fileNum either.
In the code snippets I show the code for SDCardLib_getDirectory(). I could not find where SDCardLib parameter is used. And as mentioned earlier, I found no use of files and dirs arrays. I can see where the file and directory count could be used to generate new names, but there are already static variables to hold the file count. Can anyone see a reason why the SDCard_getDirectory() was called?
/*
* Store TimeStamp from PC when logging starts to SDCard
*/
void storeTimeStampSDCard()
{
int i = 0;
uint16_t bw = 0;
unsigned long long epoch;
// FRESULT rc;
// Increment log file number
numLogFiles++;
,
//Detect SD card
SDCardLib_Status st = SDCardLib_detectCard(&sdCardLib);
if (st == SDCARDLIB_STATUS_NOT_PRESENT) {
SDCardLib_unInit(&sdCardLib);
mode = '0';
noSDCard = 1; //jn added
return;
}
// Read directory and file
rc = SDCardLib_getDirectory(&sdCardLib, "data_log", dirs, &dirNum, files, &fileNum);
//Create the directory under the root directory
rc = SDCardLib_createDirectory(&sdCardLib, "data_log");
if (rc != FR_OK && rc != FR_EXIST) {
SDCardLib_unInit(&sdCardLib);
mode = '0';
return;
}
//........
}
Now jumping to sdcard.c (SDCardLib layer) to look at SDCardLib_getDirectory() is interesting. It takes the array pointer assigns it to a one dimensional array (e.g. char (*fileList)[MAX_FILE_LEN] and indexes it each time it writes a filename). This code seem fragile since the SDCardLib_createDirectory() simply returns f_mkdir(directoryName), it does not check how many files already exist. Perhaps TI assumes this checking should be done at the application layer above SDCardLogMode....
void SDCardLib_unInit(SDCardLib * lib)
{
/* Unregister work area prior to discard it */
f_mount(0, NULL);
}
FRESULT SDCardLib_getDirectory(SDCardLib * lib,
char * directoryName,
char (*dirList)[MAX_DIR_LEN], uint8_t *dirNum,
char (*fileList)[MAX_FILE_LEN], uint8_t *fileNum)
{
FRESULT rc; /* Result code */
DIRS dir; /* Directory object */
FILINFO fno; /* File information object */
uint8_t dirCnt = 0; /* track current directory count */
uint8_t fileCnt = 0; /* track current directory count */
rc = f_opendir(&dir, directoryName);
for (;;)
{
rc = f_readdir(&dir, &fno); // Read a directory item
if (rc || !fno.fname[0]) break; // Error or end of dir
if (fno.fattrib & AM_DIR) //this is a directory
{
strcat(*dirList, fno.fname); //add this to our list of names
dirCnt++;
dirList++;
}
else //this is a file
{
strcat(*fileList, fno.fname); //add this to our list of names
fileCnt++;
fileList++;
}
}
*dirNum = dirCnt;
*fileNum = fileCnt;
return rc;
}
Below is SDCardLib_createDirectory(SDCardLib *lib, char *directoryName). It just creates a directory, it does not check on the existing number of files.
FRESULT SDCardLib_createDirectory(SDCardLib * lib, char * directoryName)
{
return f_mkdir(directoryName);
}
So coming back to my questions:
Did I understand this code correctly, does it really does limit the number of directories and files to 10 each?
If so, why would the number of files and directories be so limited? The particular MSP430 that this example code came with has 256KB of program space and 8KB of RAM. The compiled code consumes less than half of the available resources (68KB of program space and about 2.5KB of RAM). Is it because any larger would overflow the stack segment?
I want to increase the number of files that can be stored. If I look at the underlying FATFS code, it does not to impose a limit on the number of files or directories (at least not until the sd card is full). If I never intend to display or search the contents of a directory on the MSP430 my thought is to remove SDCard_getDirectory() and the two char arrays (files and dirs). Would there a reason why this would be a bad idea?
There are other microcontrollers with less memory.
The SDCardLib_getDirectory() function treats its dirList and fileList parameters as simple strings, i.e., it calls strcat() on the same pointers. This means that it can read as many names as fit into 10*8 or 10*12 bytes.
And calling strcat() without adding a delimiter means that it is impossible to get the individual names out of the string.
This codes demonstrates that it is possible to use the FatFs library, and in which order its functions need to be called, but it is not necessarily a good example of how to do that. I recommend that you write your own code.

How to create a simple sysfs class attribute in Linux kernel v3.2

I'm learning how to use sysfs in my Linux modules, but I'm having the hardest time finding current documentation on these topics. The Linux Device Drivers 3rd Edition book I've been using seems to be rather dated in this area unfortunately (e.g. the class_device structure appears to be completely gone in current Linux versions).
I'm simply trying to get an attribute to appear, under the respective sysfs class for my module, that will allow me to read the value of a module variable from kernel space.
In my code, I have a class created that allows udev to create a device node at /dev/foo for my module:
dev_t foo_dev;
alloc_chrdev_region(&foo_dev, 0, 1, "bar");
struct class *bar = class_create(THIS_MODULE, "bar");
device_create(bar, NULL, foo_dev, NULL, "foo");
struct cdev foo_dev_file;
cdev_init(&foo_dev_file, &fops); /* fops defined earlier */
cdev_add(&foo_dev_file, foo_dev, 1);
When I insert the module I get a sysfs class directory created and populated with some default attributes at /sys/class/bar/foo/. How can I create attributes that show up under this new directory?
I have the concepts down pretty well I believe -- create attribute structure, define sysfs_ops functions, etc -- my problem is that I don't know which particular kernel structure to use (class_attribute?), nor how to make these attributes appear under the right sysfs directory.
Would anyone point me to a tutorial or article detailing the process for current Linux kernels?
Even though my knowledge is still fairly low on the topic, I'm going to post an answer just because of the age of this question. If somebody else has a better answer, please post! :)
First off, I'm going to assume that you've read that whole chapter (specifically about kobjects & ksets). So just about every struct in the device driver model has these cutely included in them. If you want to manipulate the kobject for the class its self (not sure if that's wise or not), that's your struct class's dev_kobj member.
However, you want to manipulate the attributes of that class. I believe you do this by defining a (usually static), NULL-terminated array of them as follows and then assigning its address to the struct class's class_attrs member (taken from drivers/uwb/driver.c):
static struct class_attribute uwb_class_attrs[] = {
__ATTR(beacon_timeout_ms, S_IWUSR | S_IRUGO,
beacon_timeout_ms_show, beacon_timeout_ms_store),
__ATTR_NULL,
};
/** Device model classes */
struct class uwb_rc_class = {
.name = "uwb_rc",
.class_attrs = uwb_class_attrs,
};
When I don't know how to use something, I usually git grep the repository for somebody else who has used it and try to learn from it that way. It would seem that this is why they tend to say kernel "hackers" and not "developers".
Minimal runnable example
Usage:
insmod /sysfs.ko
cd /sys/kernel/lkmc_sysfs
printf 12345 >foo
cat foo
# => 1234
dd if=foo bs=1 count=2 skip=1 status=none
# => 23
sysfs.c
#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <uapi/linux/stat.h> /* S_IRUSR, S_IWUSR */
enum { FOO_SIZE_MAX = 4 };
static int foo_size;
static char foo_tmp[FOO_SIZE_MAX];
static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buff)
{
strncpy(buff, foo_tmp, foo_size);
return foo_size;
}
static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buff, size_t count)
{
foo_size = min(count, (size_t)FOO_SIZE_MAX);
strncpy(foo_tmp, buff, foo_size);
return count;
}
static struct kobj_attribute foo_attribute =
__ATTR(foo, S_IRUGO | S_IWUSR, foo_show, foo_store);
static struct attribute *attrs[] = {
&foo_attribute.attr,
NULL,
};
static struct attribute_group attr_group = {
.attrs = attrs,
};
static struct kobject *kobj;
static int myinit(void)
{
int ret;
kobj = kobject_create_and_add("lkmc_sysfs", kernel_kobj);
if (!kobj)
return -ENOMEM;
ret = sysfs_create_group(kobj, &attr_group);
if (ret)
kobject_put(kobj);
return ret;
}
static void myexit(void)
{
kobject_put(kobj);
}
module_init(myinit);
module_exit(myexit);
MODULE_LICENSE("GPL");
GitHub upstream.
Tested with Linux kernel 5.0.
There is a good tutorial in the link below
http://pete.akeo.ie/2011/08/writing-linux-device-driver-for-kernels.html
parrot_driver.c:
/*
* Linux 2.6 and 3.0 'parrot' sample device driver
*
* Copyright (c) 2011, Pete Batard <pete#akeo.ie>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/kfifo.h>
#include "parrot_driver.h"
/* Module information */
MODULE_AUTHOR(AUTHOR);
MODULE_DESCRIPTION(DESCRIPTION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
/* Device variables */
static struct class* parrot_class = NULL;
static struct device* parrot_device = NULL;
static int parrot_major;
/* Flag used with the one_shot mode */
static bool message_read;
/* A mutex will ensure that only one process accesses our device */
static DEFINE_MUTEX(parrot_device_mutex);
/* Use a Kernel FIFO for read operations */
static DECLARE_KFIFO(parrot_msg_fifo, char, PARROT_MSG_FIFO_SIZE);
/* This table keeps track of each message length in the FIFO */
static unsigned int parrot_msg_len[PARROT_MSG_FIFO_MAX];
/* Read and write index for the table above */
static int parrot_msg_idx_rd, parrot_msg_idx_wr;
/* Module parameters that can be provided on insmod */
static bool debug = false; /* print extra debug info */
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "enable debug info (default: false)");
static bool one_shot = true; /* only read a single message after open() */
module_param(one_shot, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "disable the readout of multiple messages at once (default: true)");
static int parrot_device_open(struct inode* inode, struct file* filp)
{
dbg("");
/* Our sample device does not allow write access */
if ( ((filp->f_flags & O_ACCMODE) == O_WRONLY)
|| ((filp->f_flags & O_ACCMODE) == O_RDWR) ) {
warn("write access is prohibited\n");
return -EACCES;
}
/* Ensure that only one process has access to our device at any one time
* For more info on concurrent accesses, see http://lwn.net/images/pdf/LDD3/ch05.pdf */
if (!mutex_trylock(&parrot_device_mutex)) {
warn("another process is accessing the device\n");
return -EBUSY;
}
message_read = false;
return 0;
}
static int parrot_device_close(struct inode* inode, struct file* filp)
{
dbg("");
mutex_unlock(&parrot_device_mutex);
return 0;
}
static ssize_t parrot_device_read(struct file* filp, char __user *buffer, size_t length, loff_t* offset)
{
int retval;
unsigned int copied;
/* The default from 'cat' is to issue multiple reads until the FIFO is depleted
* one_shot avoids that */
if (one_shot && message_read) return 0;
dbg("");
if (kfifo_is_empty(&parrot_msg_fifo)) {
dbg("no message in fifo\n");
return 0;
}
retval = kfifo_to_user(&parrot_msg_fifo, buffer, parrot_msg_len[parrot_msg_idx_rd], &copied);
/* Ignore short reads (but warn about them) */
if (parrot_msg_len[parrot_msg_idx_rd] != copied) {
warn("short read detected\n");
}
/* loop into the message length table */
parrot_msg_idx_rd = (parrot_msg_idx_rd+1)%PARROT_MSG_FIFO_MAX;
message_read = true;
return retval ? retval : copied;
}
/* The file_operation scructure tells the kernel which device operations are handled.
* For a list of available file operations, see http://lwn.net/images/pdf/LDD3/ch03.pdf */
static struct file_operations fops = {
.read = parrot_device_read,
.open = parrot_device_open,
.release = parrot_device_close
};
/* Placing data into the read FIFO is done through sysfs */
static ssize_t sys_add_to_fifo(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
{
unsigned int copied;
dbg("");
if (kfifo_avail(&parrot_msg_fifo) < count) {
warn("not enough space left on fifo\n");
return -ENOSPC;
}
if ((parrot_msg_idx_wr+1)%PARROT_MSG_FIFO_MAX == parrot_msg_idx_rd) {
/* We've looped into our message length table */
warn("message length table is full\n");
return -ENOSPC;
}
/* The buffer is already in kernel space, so no need for ..._from_user() */
copied = kfifo_in(&parrot_msg_fifo, buf, count);
parrot_msg_len[parrot_msg_idx_wr] = copied;
if (copied != count) {
warn("short write detected\n");
}
parrot_msg_idx_wr = (parrot_msg_idx_wr+1)%PARROT_MSG_FIFO_MAX;
return copied;
}
/* This sysfs entry resets the FIFO */
static ssize_t sys_reset(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
{
dbg("");
/* Ideally, we would have a mutex around the FIFO, to ensure that we don't reset while in use.
* To keep this sample simple, and because this is a sysfs operation, we don't do that */
kfifo_reset(&parrot_msg_fifo);
parrot_msg_idx_rd = parrot_msg_idx_wr = 0;
return count;
}
/* Declare the sysfs entries. The macros create instances of dev_attr_fifo and dev_attr_reset */
static DEVICE_ATTR(fifo, S_IWUSR, NULL, sys_add_to_fifo);
static DEVICE_ATTR(reset, S_IWUSR, NULL, sys_reset);
/* Module initialization and release */
static int __init parrot_module_init(void)
{
int retval;
dbg("");
/* First, see if we can dynamically allocate a major for our device */
parrot_major = register_chrdev(0, DEVICE_NAME, &fops);
if (parrot_major < 0) {
err("failed to register device: error %d\n", parrot_major);
retval = parrot_major;
goto failed_chrdevreg;
}
/* We can either tie our device to a bus (existing, or one that we create)
* or use a "virtual" device class. For this example, we choose the latter */
parrot_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(parrot_class)) {
err("failed to register device class '%s'\n", CLASS_NAME);
retval = PTR_ERR(parrot_class);
goto failed_classreg;
}
/* With a class, the easiest way to instantiate a device is to call device_create() */
parrot_device = device_create(parrot_class, NULL, MKDEV(parrot_major, 0), NULL, CLASS_NAME "_" DEVICE_NAME);
if (IS_ERR(parrot_device)) {
err("failed to create device '%s_%s'\n", CLASS_NAME, DEVICE_NAME);
retval = PTR_ERR(parrot_device);
goto failed_devreg;
}
/* Now we can create the sysfs endpoints (don't care about errors).
* dev_attr_fifo and dev_attr_reset come from the DEVICE_ATTR(...) earlier */
retval = device_create_file(parrot_device, &dev_attr_fifo);
if (retval < 0) {
warn("failed to create write /sys endpoint - continuing without\n");
}
retval = device_create_file(parrot_device, &dev_attr_reset);
if (retval < 0) {
warn("failed to create reset /sys endpoint - continuing without\n");
}
mutex_init(&parrot_device_mutex);
/* This device uses a Kernel FIFO for its read operation */
INIT_KFIFO(parrot_msg_fifo);
parrot_msg_idx_rd = parrot_msg_idx_wr = 0;
return 0;
failed_devreg:
class_unregister(parrot_class);
class_destroy(parrot_class);
failed_classreg:
unregister_chrdev(parrot_major, DEVICE_NAME);
failed_chrdevreg:
return -1;
}
static void __exit parrot_module_exit(void)
{
dbg("");
device_remove_file(parrot_device, &dev_attr_fifo);
device_remove_file(parrot_device, &dev_attr_reset);
device_destroy(parrot_class, MKDEV(parrot_major, 0));
class_unregister(parrot_class);
class_destroy(parrot_class);
unregister_chrdev(parrot_major, DEVICE_NAME);
}
/* Let the kernel know the calls for module init and exit */
module_init(parrot_module_init);
module_exit(parrot_module_exit);
parrot_driver.h:
/*
* Linux 2.6 and 3.0 'parrot' sample device driver
*
* Copyright (c) 2011, Pete Batard <pete#akeo.ie>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DEVICE_NAME "device"
#define CLASS_NAME "parrot"
#define PARROT_MSG_FIFO_SIZE 1024
#define PARROT_MSG_FIFO_MAX 128
#define AUTHOR "Pete Batard <pete#akeo.ie>"
#define DESCRIPTION "'parrot' sample device driver"
#define VERSION "0.3"
/* We'll use our own macros for printk */
#define dbg(format, arg...) do { if (debug) pr_info(CLASS_NAME ": %s: " format , __FUNCTION__ , ## arg); } while (0)
#define err(format, arg...) pr_err(CLASS_NAME ": " format, ## arg)
#define info(format, arg...) pr_info(CLASS_NAME ": " format, ## arg)
#define warn(format, arg...) pr_warn(CLASS_NAME ": " format, ## arg)

What are the benefits of unnamed structs / unions in C?

I found one code implemented as the similar demo shown below ..
struct st
{
int a;
struct
{
int b;
};
};
6.58 Unnamed struct/union fields within structs/unions
As permitted by ISO C11.
But What are benefits of it ?
Because anyway I can access the data members in a same manner like
int main()
{
struct st s;
s.a=11;
s.b=22;
return 0;
}
compiled on gcc 4.5.2 with ,
gcc -Wall demo.c -o demo
and no errors ,
It does not have to be an anonymous struct inside a struct, which I do not find very useful: this will typically only change the layout slightly by introducing more padding, with no other visible effects (compared to inlining the members of the child struct into the parent struct).
I think that the advantage of anonymous struct/unions is elsewhere:
they can be used to place an anonymous struct inside an union or an anonymous union inside a struct.
Example:
union u
{
int i;
struct { char b1; char b2; char b3; char b4; };
};
The benefit is pretty obvious, isn't it? It saves the programmer from coming up with a name! Since naming things is hard, it's nice that it's possible to avoid doing so if there is no real need.
It's also a pretty clear signal that this struct is local and never used anywhere else but in the context of being a field in the parent struct, which is really, really nice information since it reduces the possibility of needless coupling.
Think of it as static; it restricts the visibility of the inner struct to the outer one, in a manner similar to (but not, of course, equivalent with) how static restricts the visibility of global symbols to the compilation unit in which they appear.
I just ran into a huge benefit of anonymous union. However be warned this is not a story for the faint hearted nor is it a recommended practice.
Note: See also Anonymous union within struct not in c99?
In an older C program of hundreds of source code files there is a global variable, a struct, which contained a struct as a member. So the type definition for the global variable looked some thing like:
typedef struct {
LONG lAmount;
STRUCTONE largeStruct; // memory area actually used for several different struct objects
ULONG ulFlags;
} STRUCTCOMMON;
The struct, STRUCTONE, was one of several large structs however the others were all smaller than STRUCTONE at the time this code was written. So this memory area, largeStruct was being used as a union but without the proper source statements indicating so. Instead various struct variables were copied into this area using memcpy(). To make matters worse sometimes this was through the actual name of the global variable and sometimes through a pointer to the global variable.
As typically happens as time progresses recent changes resulted in one of the other structs becoming the largest. And I was faced with having to go through a hundred files looking for where this was being used along with all the various aliases and everything else.
And then I remembered anonymous unions. So I modified the typedef to be the following:
typedef struct {
LONG lAmount;
union {
// anonymous union to allow for allocation of largest space needed
STRUCTONE largeStruct; // memory area actually used for several different struct objects
STRUCTTHREE largerStruct; // memory area for even larger struct
};
ULONG ulFlags;
} STRUCTCOMMON;
And then recompiled every thing.
So now all those days of source code review and regression testing I was unhappily looking forward to are no longer necessary.
And I can now begin the process of slowly modifying source using this global to bring this source up to more modern standards on my own time table.
Addendum - Anonymous struct within anonymous union
Working in this same source code body I ran into an application of this technique with a binary record that could contain date from one of several different structs which were supposed to be the same length. The problem I found was due to a programmer error, one struct was a different size than the others.
As part of correcting this problem, I wanted a solution that would allow the compiler to figure out the correct sizes for the data structures.
Since these structs contained some differences in a couple of members of the structs with padding variables added to make them all the same size, I went with anonymous unions which worked fine except for one of the structs.
I found I could add an anonymous struct as part of the union so that as long as the various members of the union and the added anonymous struct had different names, it would compile fine with Visual Studio 2015.
Important Note: This solution requires #pragma pack(1) with Visual Studio 2015 to pack the structs and unions on byte boundaries. Without the use of the pragma the compiler may introduce unknown padding into the various structs and unions.
I created the following define in order to standardize the anonymous union and anonymous struct.
#define PROGRPT_UNION_STRUCT \
union { \
SHORT sOperand1; /* operand 1 (SHORT) */ \
LONG lOperand1; /* operand 1 (LONG) */ \
PROGRPT_ITEM Operand1; /* operand 1 */ \
struct { \
UCHAR uchReserved3; /* */ \
USHORT usLoopEnd; /* offset for loop end */ \
UCHAR uchReserved4; /* */ \
}; \
};
Then used it as in this sample of three of the several structs that are used to access the binary data in the data record read from a file.
/* loop record */
typedef struct {
UCHAR uchOperation; /* operation code (LOOP) */
UCHAR uchRow; /* position (row) */
UCHAR uchLoopBrace; /* loop brace (begin/end) */
UCHAR uchReserved1; /* */
TCHAR auchReserved2[ 2 ]; /* */
UCHAR uchCondition; /* condition code */
PROGRPT_ITEM LoopItem; /* loop record */
PROGRPT_UNION_STRUCT
PROGRPT_ITEM Reserved5; /* */
} PROGRPT_LOOPREC;
/* print record */
typedef struct {
UCHAR uchOperation; /* operation code (PRINT) */
UCHAR uchRow; /* position (row) */
UCHAR uchColumn; /* position (column) */
UCHAR uchMaxColumn; /* max no of column */
TCHAR auchFormat[ 2 ]; /* print format/style */
UCHAR uchCondition; /* condition code */
PROGRPT_ITEM PrintItem; /* print item */
PROGRPT_UNION_STRUCT
PROGRPT_ITEM Operand2; /* ope2 for condition */
} PROGRPT_PRINTREC;
/* mathematics record ( accumulator.total = LONG (+,-,*,/) opr2) */
typedef struct {
UCHAR uchOperation; /* operation code (MATH) */
UCHAR uchRow; /* position (row) */
UCHAR uchColumn; /* position (column) */
UCHAR uchMaxColumn; /* max no of column */
TCHAR auchFormat[ 2 ]; /* format style */
UCHAR uchCondition; /* condition code */
PROGRPT_ITEM Accumulator; /* accumulator */
PROGRPT_UNION_STRUCT
PROGRPT_ITEM Operand2; /* operand 2 */
} PROGRPT_MATHTTL;
which were originally
typedef struct {
UCHAR uchOperation; /* operation code (LOOP) */
UCHAR uchRow; /* position (row) */
UCHAR uchLoopBrace; /* loop brace (begin/end) */
UCHAR uchReserved1; /* */
TCHAR auchReserved2[ 2 ]; /* */
UCHAR uchCondition; /* condition code */
PROGRPT_ITEM LoopItem; /* loop record */
UCHAR uchReserved3; /* */
USHORT usLoopEnd; /* offset for loop end */
UCHAR uchReserved4; /* */
PROGRPT_ITEM Reserved5; /* */
} PROGRPT_LOOPREC;
/* print record */
typedef struct {
UCHAR uchOperation; /* operation code (PRINT) */
UCHAR uchRow; /* position (row) */
UCHAR uchColumn; /* position (column) */
UCHAR uchMaxColumn; /* max no of column */
TCHAR auchFormat[ 2 ]; /* print format/style */
UCHAR uchCondition; /* condition code */
PROGRPT_ITEM PrintItem; /* print item */
PROGRPT_ITEM Operand1; /* ope1 for condition */
PROGRPT_ITEM Operand2; /* ope2 for condition */
} PROGRPT_PRINTREC;
/* mathematics record ( accumulator.total = LONG (+,-,*,/) opr2) */
typedef struct {
UCHAR uchOperation; /* operation code (MATH) */
UCHAR uchRow; /* position (row) */
UCHAR uchColumn; /* position (column) */
UCHAR uchMaxColumn; /* max no of column */
TCHAR auchFormat[ 2 ]; /* format style */
UCHAR uchCondition; /* condition code */
PROGRPT_ITEM Accumulator; /* accumulator */
LONG lOperand1; /* operand 1 (LONG) */
PROGRPT_ITEM Operand2; /* operand 2 */
} PROGRPT_MATHTTL;
Using a union of all the various record types that looks like:
typedef union {
PROGRPT_LOOPREC Loop; /* loop record */
PROGRPT_PRINTREC Print; /* print record */
PROGRPT_MATHOPE MathOpe; /* math (with operand) */
PROGRPT_MATHTTL MathTtl; /* math (with total) */
PROGRPT_MATHCO MathCo; /* math (with count) */
} PROGRPT_RECORD;
These record formats are used in the code similar to the following:
for ( usLoopIndex = 0; usLoopIndex < usMaxNoOfRec; ) {
ULONG ulActualRead = 0; /* actual length of read record function */
PROGRPT_RECORD auchRecord;
/* --- retrieve a formatted record --- */
ProgRpt_ReadFile( ulReadOffset, &auchRecord, PROGRPT_MAX_REC_LEN, &ulActualRead );
if ( ulActualRead != PROGRPT_MAX_REC_LEN ) {
return ( LDT_ERR_ADR );
}
/* --- analyze operation code of format record, and
store it to current row item buffer --- */
switch ( auchRecord.Loop.uchOperation ) {
case PROGRPT_OP_PRINT: /* print operation */
sRetCode = ProgRpt_FinPRINT( &ReportInfo, &auchRecord.Print, uchMinorClass, NULL );
break;
case PROGRPT_OP_MATH: /* mathematics operation */
sRetCode = ProgRpt_FinMATH(&auchRecord.MathOpe, NULL );
break;
case PROGRPT_OP_LOOP: /* loop (begin) operation */
ProgRpt_PrintLoopBegin( &ReportInfo, &auchRecord.Loop );
switch ( auchRecord.Loop.LoopItem.uchMajor ) {
case PROGRPT_INDKEY_TERMNO:
sRetCode = ProgRpt_IndLOOP( &ReportInfo, &auchRecord.Loop, uchMinorClass, usTerminalNo, ulReadOffset );
usLoopIndex += auchRecord.Loop.usLoopEnd;
ulReadOffset += ( PROGRPT_MAX_REC_LEN * auchRecord.Loop.usLoopEnd );
break;
default:
return ( LDT_ERR_ADR );
}
break;
default:
return ( LDT_ERR_ADR );
}
// .......
I've used anonymous structs in developing contiguous address structures that I'll be accessing via pointers. More specifically, I'll use anonymous structs within the parent struct to enable bit-fielding certain portions of the memory that is divided into smaller portions of labeled data.
Be careful of how your compiler packs the bit-fielded information, the first member of the bitfielded struct can either be the LSB or MSB.
typedef struct
{
uint32_t a;
struct
{
uint32_t b : 16;
uint32_t c : 8;
uint32_t d : 7;
uint32_t e : 1;
};
}Parent;
#define ADDRESS ((Parent*)(uint16_t)0xF0F0)
ADDRESS->a = data_32_bits;
ADDRESS->b = data_16_bits;
ADDRESS->c = data_8_bits;
ADDRESS->d = data_7_bits;
ADDRESS->e = data_1_bit;

How to debug driver load error?

I've made a driver for Windows, compiled it and tried to start it via SC manager, but I get the system error from the SC manager API:
ERROR_PROC_NOT_FOUND The specified procedure could not be found.
Is there a way to get more information about why exactly the driver fails to start?
WinDbg or something? If I comment out all code in my DriverEntry routine, the driver starts.
The only thing I'm calling is a procedure in another source module (in my own project, though). I can comment out all external dependencies and I still get the same error.
Edit:
I've also tried different DDKs, i.e. 2003 DDK und Vista WDK (but not Win7 WDK)
Edit2:
Here is my driver sour code file driver.cpp:
#ifdef __cplusplus
extern "C" {
#endif
#include <ntddk.h>
#include <ntstrsafe.h>
#ifdef __cplusplus
}; // extern "C"
#endif
#include "../distorm/src/distorm.h"
void DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
}
#define MAX_INSTRUCTIONS 20
#ifdef __cplusplus
extern "C" {
#endif
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
UNICODE_STRING pFcnName;
// Holds the result of the decoding.
_DecodeResult res;
// Decoded instruction information.
_DecodedInst decodedInstructions[MAX_INSTRUCTIONS];
// next is used for instruction's offset synchronization.
// decodedInstructionsCount holds the count of filled instructions' array by the decoder.
unsigned int decodedInstructionsCount = 0, i, next;
// Default decoding mode is 32 bits, could be set by command line.
_DecodeType dt = Decode32Bits;
// Default offset for buffer is 0, could be set in command line.
_OffsetType offset = 0;
char* errch = NULL;
// Buffer to disassemble.
char *buf;
int len = 100;
// Register unload routine
DriverObject->DriverUnload = DriverUnload;
DbgPrint("diStorm Loaded!\n");
// Get address of KeBugCheck
RtlInitUnicodeString(&pFcnName, L"KeBugCheck");
buf = (char *)MmGetSystemRoutineAddress(&pFcnName);
offset = (unsigned) (_OffsetType)buf;
DbgPrint("Resolving KeBugCheck # 0x%08x\n", buf);
// Decode the buffer at given offset (virtual address).
while (1) {
res = distorm_decode(offset, (const unsigned char*)buf, len, dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount);
if (res == DECRES_INPUTERR) {
DbgPrint(("NULL Buffer?!\n"));
break;
}
for (i = 0; i < decodedInstructionsCount; i++) {
// Note that we print the offset as a 64 bits variable!!!
// It might be that you'll have to change it to %08X...
DbgPrint("%08I64x (%02d) %s %s %s\n", decodedInstructions[i].offset, decodedInstructions[i].size,
(char*)decodedInstructions[i].instructionHex.p,
(char*)decodedInstructions[i].mnemonic.p,
(char*)decodedInstructions[i].operands.p);
}
if (res == DECRES_SUCCESS || decodedInstructionsCount == 0) {
break; // All instructions were decoded.
}
// Synchronize:
next = (unsigned int)(decodedInstructions[decodedInstructionsCount-1].offset - offset);
next += decodedInstructions[decodedInstructionsCount-1].size;
// Advance ptr and recalc offset.
buf += next;
len -= next;
offset += next;
}
DbgPrint(("Done!\n"));
return STATUS_SUCCESS;
}
#ifdef __cplusplus
}; // extern "C"
#endif
My directory structure is like this:
base_dir\driver\driver.cpp
\distorm\src\all_the_c_files
\distorm\distorm.h
\distorm\config.h
My SOURCES file:
# $Id$
TARGETNAME=driver
TARGETPATH=obj
TARGETTYPE=DRIVER
# Additional defines for the C/C++ preprocessor
C_DEFINES=$(C_DEFINES) -DSUPPORT_64BIT_OFFSET
SOURCES=driver.cpp \
distorm_dummy.c \
drvversion.rc
INCLUDES=..\distorm\src;
TARGETLIBS=$(DDK_LIB_PATH)\ntdll.lib \
$(DDK_LIB_PATH)\ntstrsafe.lib
You can download diStorm from here: http://ragestorm.net/distorm/dl.php?id=8
distorm_dummy is the same as the dummy.c from the diStorm lib.
Enable "Show loader snaps" using gflags -- in the debug output, you should find information about which import the loader is not able to resolve.
Not surprisingly, you have all the information you need to solve this on your own.
ERROR_PROC_NOT_FOUND The specified procedure could not be found.
This, combined with your dependency Walker output, pretty much points to a broken Import Table
Why is your IT broken? I'm not sure, could be a problem with your build/linker settings, since rather obviously, HAL.DLL is right there in %windir%\system32.
Reasons for a broken load order are many and you'll have to track them down yourself.
Have you tried running Dependency Walker on the compiled .sys and see if there is actually some missing function imports?
Build it with the 6000 WDK/DDK (because with the "actual" Build 7600... it links against wdfldr.sys, but under Windows Vista and XP Systems this sys file is not available).
I don't know where you can download it officially but i did use a torrent...
You can add deferred breakpoints in WinDbg.
If you specify a breakpoint, while the driver is not loaded (or with bu), it will be triggered, when the driver does get loaded and enters the function.
The command for specifiying breakpoints is :
bp <module_name>!<function_name>
e.g. :
bp my_driver!DriverEntry

Resources