March 9th, 2008 by admin
Eclipse is an open source development platform comprised of extensible frameworks, tools and run times for building, deploying and managing software across the life cycle.
CDT is the name of the C/C++ development plug-in. It includes a graphical GDB front end.
The following slides are a short visual “how to” demonstrating configuring and using CDT to debug a remote target with GDB.
eclipse_debug.pdf
February 13th, 2008 by admin
Shared libraries, sometime also referred to as DSO (for Dynamic Shared Objects) or DLL (for Dynamically Loadable Modules), offer an easy way to pack together useful functions and data as a code library that can be easily reused, updated separately from all the application making use of it and most important - under certain conditions allows most the code and data of the library to only be loaded once to the machine RAM regardless of the number of applications using it.
A shared library is thus normally comprised of a set of global functions which may be called by applications (or other libraries) that link with the library.
Given the shared nature of shared libraries, it is often useful to provide a constructor for the code library which will run each time the library is loaded by an application. Doing this is very simple, using the GNU specific constructor attribute.
Here is a code example:
/* init_demo.c */
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
static void __attribute__ ((constructor)) \
lib_init(void);
static void lib_init(void) {
printf("Library ready. \n");
return;
}
Then build the the shared library using the following GNU Makefile:
.PHONY: clean
libinitdemo.so.1.0.0: init_demo.c
$(CC) -fPIC init_demo.c -shared \
-Wl,-soname,libinitdemo.so.1 -o \
libinitdemo.so.1.0.0
clean:
$(RM) -f libinitdemo.so.1.0.0
TIP
Combining a shared library constructor as shown above with use of LD_PRELOAD can be a powerful way to add construction code to existing programs without changing their source code and indeed, without requiring access to their source code at all.
December 11th, 2007 by admin
It can sometime be very useful to force an application to force to use a specific network interface for routing traffic, the regular routing tables not withstanding.
An example for such cases is where an embedded Linux system has a management network interface and a separate regular network interface where regular traffic should go:
So long as the two interfaces use two different IP addresses from non overlapping network it is very easy - simply bind the management application socket to the management IP and let the routing table do the rest.
What to do, however, if product definition calls for supporting two different and separate, default gateway settings for management and media traffic? Although we can assign multiple default gateway routing table entries, how to make sure the management applications use one and all other traffic use another?
This is where the SO_BINDTODEVICE socket option comes to our rescue. We will install two default gateway entries: a normal one for the media traffic and another one for the management traffic, for which we will define a high metric so it will normally will not be used.
Then, we will set the SO_BINDTODEVICE socket option on sockets opened in management application, thus forcing the Linux networking stack to disregard any routing table entries not going through the specific device, but only for those specific sockets.
It looks something like this:
#include <sys/socket.h>
#include <net/if.h>
struct ifreq interface;
struct socket sock;
/* Management net interface name */
#define IFNAME "eth3"
/* Acquire socket here ... */
strncpy(interface.ifr_ifrn.ifrn_name, IFNAME, \
IFNAMSIZ);
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, \
(char *)&interface, sizeof(interface)) < 0) {
perror("SO_BINDTODEVICE failed");
/* Deal with error... */
}
But wait! this is all well and good when we have the management application source code. This however is not always the case. Fear not! this too can be dealt with by hijacking the socket library call:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#define __USE_GNU // Get RTLD_NEXT definition
#include <dlfcn.h>
/* Management interface */
#define IFNAME "eth3"
int socket(int domain, int type, int protocol) {
int (*origsock)(int domain, int type, int protocol);
char * error;
int sock;
origsock = dlsym(RTLD_NEXT, "socket");
if ((error = dlerror()) != NULL) {
fprintf (stderr, "%s\n", error);
exit(1);
}
sock = origsock(domain, type, protocol);
if(sock != -1) {
struct ifreq interface;
strncpy(interface.ifr_ifrn.ifrn_name, IFNAME, \
IFNAMSIZ);
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, \
(char *)&interface, sizeof(interface)) < 0) {
perror("sendpacket: setting SO_BINDTODEVICE");
exit(1);
}
}
return sock;
}
Compile this small library with (or create a proper Makefile)
$ gcc sendto.c -fPIC -o sendto.so -ldl -shared
To use:
LD_PRELOAD=sendto.so ./management_app
December 6th, 2007 by admin
It is sometime useful to be able to store the text of kernel panic messages in non volatile memory for postmortem fault analysis, in lieu of big enough storage device or network medium to store or send these message in the field.
The following code examples shows how this can be accomplished.
Some notes and caveats are due: the code does not deal with initializing the non volatile memory, if applicable. To use this example with NOR flash, as an example, code handling flash erasing will need to be added. In addition, this example does not display or clear saved messages and implementing this is left as an exercise to the reader.
Here is the Makefile:
default:
$(MAKE) -C /lib/modules/`uname -r`/build \
SUBDIRS=`pwd` modules
clean:
$(MAKE) -C /lib/modules/`uname -r`/build \
SUBDIRS=`pwd` clean
The simple Kbuild file is:
And the panic_msg.c is:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/notifier.h>
#include <linux/ioport.h>
#include <asm/io.h>
#define LOG_PREFIX "panic_msg: "
static unsigned long buf_address = 0;
module_param(buf_address, ulong, S_IRUSR);
MODULE_PARM_DESC(buf_address,
"The physical address of the panic message buffer.");
static unsigned long buf_size = 0;
module_param(buf_size, ulong, S_IRUSR);
MODULE_PARM_DESC(buf_size,
"The size in bytes of the panic message buffer.");
static unsigned int notifier_priority = INT_MAX;
module_param(notifier_priority, uint, S_IRUSR);
MODULE_PARM_DESC(notifier_priority,
"Notifier priority: INT_MAX >= x >= 0.");
static char * buf;
static int panic_msg_handler(
struct notifier_block *this,
unsigned long event,void *msg)
{
static unsigned int panic_event_handled = 0;
unsigned int msg_size = min(strlen(msg), buf_size);
if(!panic_event_handled) {
panic_event_handled = 1;
memcpy_toio((char *)msg, buf, msg_size);
}
return NOTIFY_OK;
}
static struct notifier_block panic_msg_notifier = {
.notifier_call = panic_msg_handler,
.next = NULL,
.priority = INT_MAX
};
static int __init panic_msg_init(void)
{
int ret = 0;
struct resource * res = NULL;
if((!buf_address) || (!buf_size)) {
printk(KERN_ERR LOG_PREFIX
"Address and size parameters are mandatory.\n",
buf_address, buf_size);
ret = -EINVAL;
goto error;
}
panic_msg_notifier.priority = notifier_priority;
res = request_mem_region(buf_address, buf_size,
"Panic message handler");
if(!res) {
printk(KERN_ERR LOG_PREFIX
"Failed requesting panic message buffer " \
"at address 0x%lx of size %ld.\n",
buf_address, buf_size);
ret = -EINVAL;
goto error;
}
buf = ioremap(buf_address, buf_size);
if(!buf) {
printk(KERN_ERR LOG_PREFIX
"Failed mapping panic msg buf at address" \
" 0x%lx of size %ld\n",
buf_address, buf_size);
ret = -EINVAL;
goto error;
}
if(atomic_notifier_chain_register(
&panic_notifier_list, &panic_msg_notifier)) {
printk(KERN_ERR LOG_PREFIX
"Failed registering panic message notifier.\n");
ret = -EINVAL;
goto error;
}
printk(KERN_INFO LOG_PREFIX
"Panic message buffer handler initialized.\n");
return 0;
error:
if(res) release_mem_region(buf_address, buf_size);
if(buf) iounmap(buf);
return ret;
}
static void __exit panic_msg_exit(void) {
if(atomic_notifier_chain_unregister(
&panic_notifier_list, &panic_msg_notifier)) {
printk(KERN_ERR LOG_PREFIX
"Failed removing panic msg buf mapping.\n");
}
iounmap(buf);
release_mem_region(buf_address, buf_size);
printk(KERN_INFO LOG_PREFIX
"Panic message buffer handler unloaded.\n");
return;
}
module_init(panic_msg_init);
module_exit(panic_msg_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gilad Ben-Yossef" \
" <gilad@codefidence.com>");
MODULE_DESCRIPTION("This module stores kernel " \
"panic messages in non volatile memory.");
Panic message example kernel module source code