ia64/xen-unstable
changeset 12834:2dd4569e0640
[LIBXC] Add an error reporting API to the libxc library.
- An 'xc_error' struct is used to pass around error
details. Currently contains two members 'code' an enumeration of
error types, and 'message' a free text description of the specific
problem.
- The xc_get_last_error() method returns a const pointer to the
internal instance of this struct manged by libxc. By returning a
const pointer we can add extra members to the end of the struct at
any time without worrying about ABI of callers. This will let us
provide more fine-grained info if needed in the future.
- The xc_error instance is statically defined inside libxc and marked
__thread. This ensures that errors are recorded per-thread, and
that when dealing with errors we never need to call malloc - all
storage needed is statically allocated.
- The xc_clear_last_error() method resets any currently recorded
error details
- The xc_error_code_to_desc() method converts the integer error code
into a generic user facing messsage. eg "Invalid kernel". Together
with the 'message' field from xc_error, this provides the user
visible feedback. eg "Invalid kernel: Non PAE-kernel on PAE host."
- A callback can be registered with xc_set_error_handler to receive
notification whenever an error is recorded, rather than querying
for error details after the fact with xc_get_last_error
- If built with -DDEBUG set, a default error handler will be
registered which calls fprintf(stderr), thus maintaining current
behaviour of logging errors to stderr during developer builds.
- The python binding for libxc is updated to use xc_get_last_error
to pull out error details whenever appropriate, instead of
returning info based on 'errno'
- The xc_set_error method is private to libxc internals, and is used
for setting error details
- The ERROR and PERROR macros have been updated to call xc_set_error
automatically specifying XC_INTERNAL_ERROR as the error code. This
gives a generic error report for all current failure points
- Some uses of the ERROR macro have been replaced with explicit
calls to xc_set_error to enable finer grained error reporting. In
particular the code dealing with invalid kernel types uses this
to report about PAE/architecture/wordsize mismatches
The patch has been tested by calling xm create against a varietry of
config files defining invalid kernels of various kinds. It has also
been tested with libvirt talking to xend. In both cases the error
messages were propagated all the way back up the stack.
There is only one place where I need to do further work. The suspend
& restore APIs in Xend invoke external helper programs rather than
calling libxc directly. This means that error details are essentially
lost. Since there is already code in XenD which scans STDERR from
these programs I will investigate adapting this to extract actual
error messages from these helpers.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
- An 'xc_error' struct is used to pass around error
details. Currently contains two members 'code' an enumeration of
error types, and 'message' a free text description of the specific
problem.
- The xc_get_last_error() method returns a const pointer to the
internal instance of this struct manged by libxc. By returning a
const pointer we can add extra members to the end of the struct at
any time without worrying about ABI of callers. This will let us
provide more fine-grained info if needed in the future.
- The xc_error instance is statically defined inside libxc and marked
__thread. This ensures that errors are recorded per-thread, and
that when dealing with errors we never need to call malloc - all
storage needed is statically allocated.
- The xc_clear_last_error() method resets any currently recorded
error details
- The xc_error_code_to_desc() method converts the integer error code
into a generic user facing messsage. eg "Invalid kernel". Together
with the 'message' field from xc_error, this provides the user
visible feedback. eg "Invalid kernel: Non PAE-kernel on PAE host."
- A callback can be registered with xc_set_error_handler to receive
notification whenever an error is recorded, rather than querying
for error details after the fact with xc_get_last_error
- If built with -DDEBUG set, a default error handler will be
registered which calls fprintf(stderr), thus maintaining current
behaviour of logging errors to stderr during developer builds.
- The python binding for libxc is updated to use xc_get_last_error
to pull out error details whenever appropriate, instead of
returning info based on 'errno'
- The xc_set_error method is private to libxc internals, and is used
for setting error details
- The ERROR and PERROR macros have been updated to call xc_set_error
automatically specifying XC_INTERNAL_ERROR as the error code. This
gives a generic error report for all current failure points
- Some uses of the ERROR macro have been replaced with explicit
calls to xc_set_error to enable finer grained error reporting. In
particular the code dealing with invalid kernel types uses this
to report about PAE/architecture/wordsize mismatches
The patch has been tested by calling xm create against a varietry of
config files defining invalid kernels of various kinds. It has also
been tested with libvirt talking to xend. In both cases the error
messages were propagated all the way back up the stack.
There is only one place where I need to do further work. The suspend
& restore APIs in Xend invoke external helper programs rather than
calling libxc directly. This means that error details are essentially
lost. Since there is already code in XenD which scans STDERR from
these programs I will investigate adapting this to extract actual
error messages from these helpers.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
author | kfraser@localhost.localdomain |
---|---|
date | Thu Dec 07 11:36:26 2006 +0000 (2006-12-07) |
parents | 1c15f97a220d |
children | 58284e749407 aab2b3f739d2 |
files | tools/libxc/xc_hvm_build.c tools/libxc/xc_linux_build.c tools/libxc/xc_load_elf.c tools/libxc/xc_private.c tools/libxc/xc_private.h tools/libxc/xenctrl.h tools/python/xen/lowlevel/xc/xc.c |
line diff
1.1 --- a/tools/libxc/xc_hvm_build.c Thu Dec 07 11:22:26 2006 +0000 1.2 +++ b/tools/libxc/xc_hvm_build.c Thu Dec 07 11:36:26 2006 +0000 1.3 @@ -285,7 +285,6 @@ static int xc_hvm_build_internal(int xc_ 1.4 1.5 if ( setup_guest(xc_handle, domid, memsize, image, image_size, &ctxt) < 0 ) 1.6 { 1.7 - ERROR("Error constructing guest OS"); 1.8 goto error_out; 1.9 } 1.10 1.11 @@ -329,26 +328,30 @@ static int parseelfimage(char *elfbase, 1.12 1.13 if ( !IS_ELF(*ehdr) ) 1.14 { 1.15 - ERROR("Kernel image does not have an ELF header."); 1.16 + xc_set_error(XC_INVALID_KERNEL, 1.17 + "Kernel image does not have an ELF header."); 1.18 return -EINVAL; 1.19 } 1.20 1.21 if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize ) 1.22 { 1.23 - ERROR("ELF program headers extend beyond end of image."); 1.24 + xc_set_error(XC_INVALID_KERNEL, 1.25 + "ELF program headers extend beyond end of image."); 1.26 return -EINVAL; 1.27 } 1.28 1.29 if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize ) 1.30 { 1.31 - ERROR("ELF section headers extend beyond end of image."); 1.32 + xc_set_error(XC_INVALID_KERNEL, 1.33 + "ELF section headers extend beyond end of image."); 1.34 return -EINVAL; 1.35 } 1.36 1.37 /* Find the section-header strings table. */ 1.38 if ( ehdr->e_shstrndx == SHN_UNDEF ) 1.39 { 1.40 - ERROR("ELF image has no section-header strings table (shstrtab)."); 1.41 + xc_set_error(XC_INVALID_KERNEL, 1.42 + "ELF image has no section-header strings table (shstrtab)."); 1.43 return -EINVAL; 1.44 } 1.45 shdr = (Elf32_Shdr *)(elfbase + ehdr->e_shoff + 1.46 @@ -370,7 +373,8 @@ static int parseelfimage(char *elfbase, 1.47 (ehdr->e_entry < kernstart) || 1.48 (ehdr->e_entry > kernend) ) 1.49 { 1.50 - ERROR("Malformed ELF image."); 1.51 + xc_set_error(XC_INVALID_KERNEL, 1.52 + "Malformed ELF image."); 1.53 return -EINVAL; 1.54 } 1.55
2.1 --- a/tools/libxc/xc_linux_build.c Thu Dec 07 11:22:26 2006 +0000 2.2 +++ b/tools/libxc/xc_linux_build.c Thu Dec 07 11:36:26 2006 +0000 2.3 @@ -120,7 +120,7 @@ static int probeimageformat(const char * 2.4 if ( probe_elf(image, image_size, load_funcs) && 2.5 probe_bin(image, image_size, load_funcs) ) 2.6 { 2.7 - ERROR( "Unrecognized image format" ); 2.8 + xc_set_error(XC_INVALID_KERNEL, "Not a valid ELF or raw kernel image"); 2.9 return -EINVAL; 2.10 } 2.11 2.12 @@ -618,17 +618,20 @@ static int compat_check(int xc_handle, s 2.13 xen_capabilities_info_t xen_caps = ""; 2.14 2.15 if (xc_version(xc_handle, XENVER_capabilities, &xen_caps) != 0) { 2.16 - ERROR("Cannot determine host capabilities."); 2.17 + xc_set_error(XC_INVALID_KERNEL, 2.18 + "Cannot determine host capabilities."); 2.19 return 0; 2.20 } 2.21 2.22 if (strstr(xen_caps, "xen-3.0-x86_32p")) { 2.23 if (dsi->pae_kernel == PAEKERN_no) { 2.24 - ERROR("Non PAE-kernel on PAE host."); 2.25 + xc_set_error(XC_INVALID_KERNEL, 2.26 + "Non PAE-kernel on PAE host."); 2.27 return 0; 2.28 } 2.29 } else if (dsi->pae_kernel != PAEKERN_no) { 2.30 - ERROR("PAE-kernel on non-PAE host."); 2.31 + xc_set_error(XC_INVALID_KERNEL, 2.32 + "PAE-kernel on non-PAE host."); 2.33 return 0; 2.34 } 2.35 2.36 @@ -1141,7 +1144,6 @@ static int xc_linux_build_internal(int x 2.37 console_evtchn, console_mfn, 2.38 features_bitmap) < 0 ) 2.39 { 2.40 - ERROR("Error constructing guest OS"); 2.41 goto error_out; 2.42 } 2.43
3.1 --- a/tools/libxc/xc_load_elf.c Thu Dec 07 11:22:26 2006 +0000 3.2 +++ b/tools/libxc/xc_load_elf.c Thu Dec 07 11:36:26 2006 +0000 3.3 @@ -29,20 +29,46 @@ loadelfsymtab( 3.4 */ 3.5 #if defined(__ia64__) 3.6 #define ELFCLASS ELFCLASS64 3.7 +#define ELFCLASS_DESC "64-bit" 3.8 + 3.9 #define ELFDATA ELFDATA2LSB 3.10 +#define ELFDATA_DESC "Little-Endian" 3.11 + 3.12 #define ELFMACHINE EM_IA_64 3.13 +#define ELFMACHINE_DESC "ia64" 3.14 + 3.15 + 3.16 #elif defined(__i386__) 3.17 #define ELFCLASS ELFCLASS32 3.18 +#define ELFCLASS_DESC "32-bit" 3.19 + 3.20 #define ELFDATA ELFDATA2LSB 3.21 +#define ELFDATA_DESC "Little-Endian" 3.22 + 3.23 #define ELFMACHINE EM_386 3.24 +#define ELFMACHINE_DESC "i386" 3.25 + 3.26 + 3.27 #elif defined(__x86_64__) 3.28 #define ELFCLASS ELFCLASS64 3.29 +#define ELFCLASS_DESC "64-bit" 3.30 + 3.31 #define ELFDATA ELFDATA2LSB 3.32 +#define ELFDATA_DESC "Little-Endian" 3.33 + 3.34 #define ELFMACHINE EM_X86_64 3.35 +#define ELFMACHINE_DESC "x86_64" 3.36 + 3.37 + 3.38 #elif defined(__powerpc__) 3.39 #define ELFCLASS ELFCLASS64 3.40 +#define ELFCLASS_DESC "64-bit" 3.41 + 3.42 #define ELFDATA ELFDATA2MSB 3.43 +#define ELFDATA_DESC "Big-Endian" 3.44 + 3.45 #define ELFMACHINE EM_PPC64 3.46 +#define ELFMACHINE_DESC "ppc64" 3.47 #endif 3.48 3.49 int probe_elf(const char *image, 3.50 @@ -231,7 +257,8 @@ unsigned long long xen_elfnote_numeric(s 3.51 *defined = 1; 3.52 return *(uint64_t*)ELFNOTE_DESC(note); 3.53 default: 3.54 - ERROR("elfnotes: unknown data size %#x for numeric type note %#x\n", 3.55 + xc_set_error(XC_INVALID_KERNEL, 3.56 + "elfnotes: unknown data size %#x for numeric type note %#x\n", 3.57 note->descsz, type); 3.58 return 0; 3.59 } 3.60 @@ -250,35 +277,59 @@ static int parseelfimage(const char *ima 3.61 3.62 if ( !IS_ELF(*ehdr) ) 3.63 { 3.64 - ERROR("Kernel image does not have an ELF header."); 3.65 + xc_set_error(XC_INVALID_KERNEL, 3.66 + "Kernel image does not have an ELF header."); 3.67 return -EINVAL; 3.68 } 3.69 3.70 - if ( (ehdr->e_ident[EI_CLASS] != ELFCLASS) || 3.71 - (ehdr->e_machine != ELFMACHINE) || 3.72 - (ehdr->e_ident[EI_DATA] != ELFDATA) || 3.73 - (ehdr->e_type != ET_EXEC) ) 3.74 + if (ehdr->e_machine != ELFMACHINE) 3.75 + { 3.76 + xc_set_error(XC_INVALID_KERNEL, 3.77 + "Kernel ELF architecture '%d' does not match Xen architecture '%d' (%s)", 3.78 + ehdr->e_machine, ELFMACHINE, ELFMACHINE_DESC); 3.79 + return -EINVAL; 3.80 + } 3.81 + if (ehdr->e_ident[EI_CLASS] != ELFCLASS) 3.82 { 3.83 - ERROR("Kernel not a Xen-compatible Elf image."); 3.84 + xc_set_error(XC_INVALID_KERNEL, 3.85 + "Kernel ELF wordsize '%d' does not match Xen wordsize '%d' (%s)", 3.86 + ehdr->e_ident[EI_CLASS], ELFCLASS, ELFCLASS_DESC); 3.87 + return -EINVAL; 3.88 + } 3.89 + if (ehdr->e_ident[EI_DATA] != ELFDATA) 3.90 + { 3.91 + xc_set_error(XC_INVALID_KERNEL, 3.92 + "Kernel ELF endianness '%d' does not match Xen endianness '%d' (%s)", 3.93 + ehdr->e_ident[EI_DATA], ELFDATA, ELFDATA_DESC); 3.94 + return -EINVAL; 3.95 + } 3.96 + if (ehdr->e_type != ET_EXEC) 3.97 + { 3.98 + xc_set_error(XC_INVALID_KERNEL, 3.99 + "Kernel ELF type '%d' does not match Xen type '%d'", 3.100 + ehdr->e_type, ET_EXEC); 3.101 return -EINVAL; 3.102 } 3.103 3.104 if ( (ehdr->e_phoff + (ehdr->e_phnum*ehdr->e_phentsize)) > image_len ) 3.105 { 3.106 - ERROR("ELF program headers extend beyond end of image."); 3.107 + xc_set_error(XC_INVALID_KERNEL, 3.108 + "ELF program headers extend beyond end of image."); 3.109 return -EINVAL; 3.110 } 3.111 3.112 if ( (ehdr->e_shoff + (ehdr->e_shnum*ehdr->e_shentsize)) > image_len ) 3.113 { 3.114 - ERROR("ELF section headers extend beyond end of image."); 3.115 + xc_set_error(XC_INVALID_KERNEL, 3.116 + "ELF section headers extend beyond end of image."); 3.117 return -EINVAL; 3.118 } 3.119 3.120 /* Find the section-header strings table. */ 3.121 if ( ehdr->e_shstrndx == SHN_UNDEF ) 3.122 { 3.123 - ERROR("ELF image has no section-header strings table (shstrtab)."); 3.124 + xc_set_error(XC_INVALID_KERNEL, 3.125 + "ELF image has no section-header strings table (shstrtab)."); 3.126 return -EINVAL; 3.127 } 3.128 shdr = (Elf_Shdr *)(image + ehdr->e_shoff + 3.129 @@ -325,22 +376,25 @@ static int parseelfimage(const char *ima 3.130 if ( ( loader == NULL || strncmp(loader, "generic", 7) ) && 3.131 ( guest_os == NULL || strncmp(guest_os, "linux", 5) ) ) 3.132 { 3.133 - ERROR("Will only load images built for the generic loader " 3.134 - "or Linux images"); 3.135 + xc_set_error(XC_INVALID_KERNEL, 3.136 + "Will only load images built for the generic loader " 3.137 + "or Linux images"); 3.138 return -EINVAL; 3.139 } 3.140 3.141 if ( xen_version == NULL || strncmp(xen_version, "xen-3.0", 7) ) 3.142 { 3.143 - ERROR("Will only load images built for Xen v3.0"); 3.144 + xc_set_error(XC_INVALID_KERNEL, 3.145 + "Will only load images built for Xen v3.0"); 3.146 return -EINVAL; 3.147 } 3.148 } 3.149 else 3.150 { 3.151 #if defined(__x86_64__) || defined(__i386__) 3.152 - ERROR("Not a Xen-ELF image: " 3.153 - "No ELF notes or '__xen_guest' section found."); 3.154 + xc_set_error(XC_INVALID_KERNEL, 3.155 + "Not a Xen-ELF image: " 3.156 + "No ELF notes or '__xen_guest' section found."); 3.157 return -EINVAL; 3.158 #endif 3.159 } 3.160 @@ -396,8 +450,9 @@ static int parseelfimage(const char *ima 3.161 3.162 if ( elf_pa_off_defined && !virt_base_defined ) 3.163 { 3.164 - ERROR("Neither ELF_PADDR_OFFSET nor VIRT_BASE found in ELF " 3.165 - " notes or __xen_guest section."); 3.166 + xc_set_error(XC_INVALID_KERNEL, 3.167 + "Neither ELF_PADDR_OFFSET nor VIRT_BASE found in ELF " 3.168 + " notes or __xen_guest section."); 3.169 return -EINVAL; 3.170 } 3.171 3.172 @@ -409,7 +464,8 @@ static int parseelfimage(const char *ima 3.173 vaddr = phdr->p_paddr - dsi->elf_paddr_offset + dsi->v_start; 3.174 if ( (vaddr + phdr->p_memsz) < vaddr ) 3.175 { 3.176 - ERROR("ELF program header %d is too large.", h); 3.177 + xc_set_error(XC_INVALID_KERNEL, 3.178 + "ELF program header %d is too large.", h); 3.179 return -EINVAL; 3.180 } 3.181 3.182 @@ -431,7 +487,8 @@ static int parseelfimage(const char *ima 3.183 (dsi->v_kernentry > kernend) || 3.184 (dsi->v_start > kernstart) ) 3.185 { 3.186 - ERROR("ELF start or entries are out of bounds."); 3.187 + xc_set_error(XC_INVALID_KERNEL, 3.188 + "ELF start or entries are out of bounds."); 3.189 return -EINVAL; 3.190 } 3.191
4.1 --- a/tools/libxc/xc_private.c Thu Dec 07 11:22:26 2006 +0000 4.2 +++ b/tools/libxc/xc_private.c Thu Dec 07 11:36:26 2006 +0000 4.3 @@ -8,6 +8,82 @@ 4.4 #include "xc_private.h" 4.5 #include "xg_private.h" 4.6 4.7 +#include <stdarg.h> 4.8 + 4.9 +static __thread xc_error last_error = { XC_ERROR_NONE, ""}; 4.10 +#if DEBUG 4.11 +static xc_error_handler error_handler = xc_default_error_handler; 4.12 +#else 4.13 +static xc_error_handler error_handler = NULL; 4.14 +#endif 4.15 + 4.16 +void xc_default_error_handler(const xc_error const *err) 4.17 +{ 4.18 + const char *desc = xc_error_code_to_desc(err->code); 4.19 + fprintf(stderr, "ERROR %s: %s\n", desc, err->message); 4.20 +} 4.21 + 4.22 +const xc_error const *xc_get_last_error(void) 4.23 +{ 4.24 + return &last_error; 4.25 +} 4.26 + 4.27 +void xc_clear_last_error(void) 4.28 +{ 4.29 + last_error.code = XC_ERROR_NONE; 4.30 + last_error.message[0] = '\0'; 4.31 +} 4.32 + 4.33 +const char *xc_error_code_to_desc(int code) 4.34 +{ 4.35 + /* Sync to members of xc_error_code enumeration in xenctrl.h */ 4.36 + switch ( code ) 4.37 + { 4.38 + case XC_ERROR_NONE: 4.39 + return "No error details"; 4.40 + case XC_INTERNAL_ERROR: 4.41 + return "Internal error"; 4.42 + case XC_INVALID_KERNEL: 4.43 + return "Invalid kernel"; 4.44 + } 4.45 + 4.46 + return "Unknown error code"; 4.47 +} 4.48 + 4.49 +xc_error_handler xc_set_error_handler(xc_error_handler handler) 4.50 +{ 4.51 + xc_error_handler old = error_handler; 4.52 + error_handler = handler; 4.53 + return old; 4.54 +} 4.55 + 4.56 + 4.57 +static void _xc_set_error(int code, const char *msg) 4.58 +{ 4.59 + last_error.code = code; 4.60 + strncpy(last_error.message, msg, XC_MAX_ERROR_MSG_LEN - 1); 4.61 + last_error.message[XC_MAX_ERROR_MSG_LEN-1] = '\0'; 4.62 +} 4.63 + 4.64 +void xc_set_error(int code, const char *fmt, ...) 4.65 +{ 4.66 + int saved_errno = errno; 4.67 + char msg[XC_MAX_ERROR_MSG_LEN]; 4.68 + va_list args; 4.69 + 4.70 + va_start(args, fmt); 4.71 + vsnprintf(msg, XC_MAX_ERROR_MSG_LEN-1, fmt, args); 4.72 + msg[XC_MAX_ERROR_MSG_LEN-1] = '\0'; 4.73 + va_end(args); 4.74 + 4.75 + _xc_set_error(code, msg); 4.76 + 4.77 + errno = saved_errno; 4.78 + 4.79 + if ( error_handler != NULL ) 4.80 + error_handler(&last_error); 4.81 +} 4.82 + 4.83 int lock_pages(void *addr, size_t len) 4.84 { 4.85 int e = 0;
5.1 --- a/tools/libxc/xc_private.h Thu Dec 07 11:22:26 2006 +0000 5.2 +++ b/tools/libxc/xc_private.h Thu Dec 07 11:36:26 2006 +0000 5.3 @@ -59,24 +59,15 @@ 5.4 #define PPRINTF(_f, _a...) 5.5 #endif 5.6 5.7 -#define ERROR(_m, _a...) \ 5.8 -do { \ 5.9 - int __saved_errno = errno; \ 5.10 - DPRINTF("ERROR: " _m "\n" , ## _a ); \ 5.11 - errno = __saved_errno; \ 5.12 -} while (0) 5.13 +void xc_set_error(int code, const char *fmt, ...); 5.14 + 5.15 +#define ERROR(_m, _a...) xc_set_error(XC_INTERNAL_ERROR, _m , ## _a ) 5.16 +#define PERROR(_m, _a...) xc_set_error(XC_INTERNAL_ERROR, _m " (%d = %s)", \ 5.17 + _m , ## _a , errno, strerror(errno)) 5.18 5.19 int lock_pages(void *addr, size_t len); 5.20 void unlock_pages(void *addr, size_t len); 5.21 5.22 -#define PERROR(_m, _a...) \ 5.23 -do { \ 5.24 - int __saved_errno = errno; \ 5.25 - DPRINTF("ERROR: " _m " (%d = %s)\n" , ## _a , \ 5.26 - __saved_errno, strerror(__saved_errno)); \ 5.27 - errno = __saved_errno; \ 5.28 -} while (0) 5.29 - 5.30 static inline void safe_munlock(const void *addr, size_t len) 5.31 { 5.32 int saved_errno = errno;
6.1 --- a/tools/libxc/xenctrl.h Thu Dec 07 11:22:26 2006 +0000 6.2 +++ b/tools/libxc/xenctrl.h Thu Dec 07 11:36:26 2006 +0000 6.3 @@ -682,4 +682,46 @@ int xc_hvm_set_isa_irq_level( 6.4 int xc_hvm_set_pci_link_route( 6.5 int xc_handle, domid_t dom, uint8_t link, uint8_t isa_irq); 6.6 6.7 + 6.8 +typedef enum { 6.9 + XC_ERROR_NONE = 0, 6.10 + XC_INTERNAL_ERROR = 1, 6.11 + XC_INVALID_KERNEL = 2, 6.12 +} xc_error_code; 6.13 + 6.14 +#define XC_MAX_ERROR_MSG_LEN 1024 6.15 +typedef struct { 6.16 + int code; 6.17 + char message[XC_MAX_ERROR_MSG_LEN]; 6.18 +} xc_error; 6.19 + 6.20 +/* 6.21 + * Return a pointer to the last error. This pointer and the 6.22 + * data pointed to are only valid until the next call to 6.23 + * libxc. 6.24 + */ 6.25 +const xc_error const *xc_get_last_error(void); 6.26 + 6.27 +/* 6.28 + * Clear the last error 6.29 + */ 6.30 +void xc_clear_last_error(void); 6.31 + 6.32 +typedef void (*xc_error_handler)(const xc_error const* err); 6.33 + 6.34 +/* 6.35 + * The default error handler which prints to stderr 6.36 + */ 6.37 +void xc_default_error_handler(const xc_error const* err); 6.38 + 6.39 +/* 6.40 + * Convert an error code into a text description 6.41 + */ 6.42 +const char *xc_error_code_to_desc(int code); 6.43 + 6.44 +/* 6.45 + * Registers a callback to handle errors 6.46 + */ 6.47 +xc_error_handler xc_set_error_handler(xc_error_handler handler); 6.48 + 6.49 #endif
7.1 --- a/tools/python/xen/lowlevel/xc/xc.c Thu Dec 07 11:22:26 2006 +0000 7.2 +++ b/tools/python/xen/lowlevel/xc/xc.c Thu Dec 07 11:36:26 2006 +0000 7.3 @@ -29,7 +29,7 @@ 7.4 #define PKG "xen.lowlevel.xc" 7.5 #define CLS "xc" 7.6 7.7 -static PyObject *xc_error, *zero; 7.8 +static PyObject *xc_error_obj, *zero; 7.9 7.10 typedef struct { 7.11 PyObject_HEAD; 7.12 @@ -40,6 +40,23 @@ typedef struct { 7.13 static PyObject *dom_op(XcObject *self, PyObject *args, 7.14 int (*fn)(int, uint32_t)); 7.15 7.16 +static PyObject *pyxc_error_to_exception(void) 7.17 +{ 7.18 + PyObject *pyerr; 7.19 + const xc_error const *err = xc_get_last_error(); 7.20 + const char *desc = xc_error_code_to_desc(err->code); 7.21 + 7.22 + if (err->message[1]) 7.23 + pyerr = Py_BuildValue("(iss)", err->code, desc, err->message); 7.24 + else 7.25 + pyerr = Py_BuildValue("(is)", err->code, desc); 7.26 + 7.27 + xc_clear_last_error(); 7.28 + 7.29 + PyErr_SetObject(xc_error_obj, pyerr); 7.30 + 7.31 + return NULL; 7.32 +} 7.33 7.34 static PyObject *pyxc_domain_dumpcore(XcObject *self, PyObject *args) 7.35 { 7.36 @@ -53,7 +70,7 @@ static PyObject *pyxc_domain_dumpcore(Xc 7.37 return NULL; 7.38 7.39 if (xc_domain_dumpcore(self->xc_handle, dom, corefile) != 0) 7.40 - return PyErr_SetFromErrno(xc_error); 7.41 + return pyxc_error_to_exception(); 7.42 7.43 Py_INCREF(zero); 7.44 return zero; 7.45 @@ -101,13 +118,13 @@ static PyObject *pyxc_domain_create(XcOb 7.46 7.47 if ( (ret = xc_domain_create(self->xc_handle, ssidref, 7.48 handle, flags, &dom)) < 0 ) 7.49 - return PyErr_SetFromErrno(xc_error); 7.50 + return pyxc_error_to_exception(); 7.51 7.52 return PyInt_FromLong(dom); 7.53 7.54 out_exception: 7.55 errno = EINVAL; 7.56 - PyErr_SetFromErrno(xc_error); 7.57 + PyErr_SetFromErrno(xc_error_obj); 7.58 return NULL; 7.59 } 7.60 7.61 @@ -119,7 +136,7 @@ static PyObject *pyxc_domain_max_vcpus(X 7.62 return NULL; 7.63 7.64 if (xc_domain_max_vcpus(self->xc_handle, dom, max) != 0) 7.65 - return PyErr_SetFromErrno(xc_error); 7.66 + return pyxc_error_to_exception(); 7.67 7.68 Py_INCREF(zero); 7.69 return zero; 7.70 @@ -164,7 +181,7 @@ static PyObject *pyxc_vcpu_setaffinity(X 7.71 } 7.72 7.73 if ( xc_vcpu_setaffinity(self->xc_handle, dom, vcpu, cpumap) != 0 ) 7.74 - return PyErr_SetFromErrno(xc_error); 7.75 + return pyxc_error_to_exception(); 7.76 7.77 Py_INCREF(zero); 7.78 return zero; 7.79 @@ -184,7 +201,7 @@ static PyObject *pyxc_domain_setcpuweigh 7.80 return NULL; 7.81 7.82 if ( xc_domain_setcpuweight(self->xc_handle, dom, cpuweight) != 0 ) 7.83 - return PyErr_SetFromErrno(xc_error); 7.84 + return pyxc_error_to_exception(); 7.85 7.86 Py_INCREF(zero); 7.87 return zero; 7.88 @@ -215,14 +232,13 @@ static PyObject *pyxc_domain_sethandle(X 7.89 } 7.90 7.91 if (xc_domain_sethandle(self->xc_handle, dom, handle) < 0) 7.92 - return PyErr_SetFromErrno(xc_error); 7.93 + return pyxc_error_to_exception(); 7.94 7.95 Py_INCREF(zero); 7.96 return zero; 7.97 7.98 out_exception: 7.99 - errno = EINVAL; 7.100 - PyErr_SetFromErrno(xc_error); 7.101 + PyErr_SetFromErrno(xc_error_obj); 7.102 return NULL; 7.103 } 7.104 7.105 @@ -251,7 +267,7 @@ static PyObject *pyxc_domain_getinfo(XcO 7.106 if (nr_doms < 0) 7.107 { 7.108 free(info); 7.109 - return PyErr_SetFromErrno(xc_error); 7.110 + return pyxc_error_to_exception(); 7.111 } 7.112 7.113 list = PyList_New(nr_doms); 7.114 @@ -306,10 +322,10 @@ static PyObject *pyxc_vcpu_getinfo(XcObj 7.115 7.116 rc = xc_vcpu_getinfo(self->xc_handle, dom, vcpu, &info); 7.117 if ( rc < 0 ) 7.118 - return PyErr_SetFromErrno(xc_error); 7.119 + return pyxc_error_to_exception(); 7.120 rc = xc_vcpu_getaffinity(self->xc_handle, dom, vcpu, &cpumap); 7.121 if ( rc < 0 ) 7.122 - return PyErr_SetFromErrno(xc_error); 7.123 + return pyxc_error_to_exception(); 7.124 7.125 info_dict = Py_BuildValue("{s:i,s:i,s:i,s:L,s:i}", 7.126 "online", info.online, 7.127 @@ -360,9 +376,7 @@ static PyObject *pyxc_linux_build(XcObje 7.128 ramdisk, cmdline, features, flags, 7.129 store_evtchn, &store_mfn, 7.130 console_evtchn, &console_mfn) != 0 ) { 7.131 - if (!errno) 7.132 - errno = EINVAL; 7.133 - return PyErr_SetFromErrno(xc_error); 7.134 + return pyxc_error_to_exception(); 7.135 } 7.136 return Py_BuildValue("{s:i,s:i}", 7.137 "store_mfn", store_mfn, 7.138 @@ -389,14 +403,14 @@ static PyObject *pyxc_hvm_build(XcObject 7.139 return NULL; 7.140 7.141 if ( xc_hvm_build(self->xc_handle, dom, memsize, image) != 0 ) 7.142 - return PyErr_SetFromErrno(xc_error); 7.143 + return pyxc_error_to_exception(); 7.144 7.145 /* Set up the HVM info table. */ 7.146 va_map = xc_map_foreign_range(self->xc_handle, dom, XC_PAGE_SIZE, 7.147 PROT_READ | PROT_WRITE, 7.148 HVM_INFO_PFN); 7.149 if ( va_map == NULL ) 7.150 - return PyErr_SetFromErrno(xc_error); 7.151 + return PyErr_SetFromErrno(xc_error_obj); 7.152 va_hvm = (struct hvm_info_table *)(va_map + HVM_INFO_OFFSET); 7.153 memset(va_hvm, 0, sizeof(*va_hvm)); 7.154 strncpy(va_hvm->signature, "HVM INFO", 8); 7.155 @@ -431,7 +445,7 @@ static PyObject *pyxc_evtchn_alloc_unbou 7.156 return NULL; 7.157 7.158 if ( (port = xc_evtchn_alloc_unbound(self->xc_handle, dom, remote_dom)) < 0 ) 7.159 - return PyErr_SetFromErrno(xc_error); 7.160 + return pyxc_error_to_exception(); 7.161 7.162 return PyInt_FromLong(port); 7.163 } 7.164 @@ -452,7 +466,7 @@ static PyObject *pyxc_physdev_pci_access 7.165 ret = xc_physdev_pci_access_modify( 7.166 self->xc_handle, dom, bus, dev, func, enable); 7.167 if ( ret != 0 ) 7.168 - return PyErr_SetFromErrno(xc_error); 7.169 + return pyxc_error_to_exception(); 7.170 7.171 Py_INCREF(zero); 7.172 return zero; 7.173 @@ -474,7 +488,7 @@ static PyObject *pyxc_readconsolering(Xc 7.174 7.175 ret = xc_readconsolering(self->xc_handle, &str, &count, clear); 7.176 if ( ret < 0 ) 7.177 - return PyErr_SetFromErrno(xc_error); 7.178 + return pyxc_error_to_exception(); 7.179 7.180 return PyString_FromStringAndSize(str, count); 7.181 } 7.182 @@ -504,7 +518,7 @@ static PyObject *pyxc_physinfo(XcObject 7.183 int i; 7.184 7.185 if ( xc_physinfo(self->xc_handle, &info) != 0 ) 7.186 - return PyErr_SetFromErrno(xc_error); 7.187 + return pyxc_error_to_exception(); 7.188 7.189 *q=0; 7.190 for(i=0;i<sizeof(info.hw_cap)/4;i++) 7.191 @@ -542,25 +556,25 @@ static PyObject *pyxc_xeninfo(XcObject * 7.192 xen_version = xc_version(self->xc_handle, XENVER_version, NULL); 7.193 7.194 if ( xc_version(self->xc_handle, XENVER_extraversion, &xen_extra) != 0 ) 7.195 - return PyErr_SetFromErrno(xc_error); 7.196 + return pyxc_error_to_exception(); 7.197 7.198 if ( xc_version(self->xc_handle, XENVER_compile_info, &xen_cc) != 0 ) 7.199 - return PyErr_SetFromErrno(xc_error); 7.200 + return pyxc_error_to_exception(); 7.201 7.202 if ( xc_version(self->xc_handle, XENVER_changeset, &xen_chgset) != 0 ) 7.203 - return PyErr_SetFromErrno(xc_error); 7.204 + return pyxc_error_to_exception(); 7.205 7.206 if ( xc_version(self->xc_handle, XENVER_capabilities, &xen_caps) != 0 ) 7.207 - return PyErr_SetFromErrno(xc_error); 7.208 + return pyxc_error_to_exception(); 7.209 7.210 if ( xc_version(self->xc_handle, XENVER_platform_parameters, &p_parms) != 0 ) 7.211 - return PyErr_SetFromErrno(xc_error); 7.212 + return pyxc_error_to_exception(); 7.213 7.214 sprintf(str, "virt_start=0x%lx", p_parms.virt_start); 7.215 7.216 xen_pagesize = xc_version(self->xc_handle, XENVER_pagesize, NULL); 7.217 if (xen_pagesize < 0 ) 7.218 - return PyErr_SetFromErrno(xc_error); 7.219 + return pyxc_error_to_exception(); 7.220 7.221 return Py_BuildValue("{s:i,s:i,s:s,s:s,s:i,s:s,s:s,s:s,s:s,s:s,s:s}", 7.222 "xen_major", xen_version >> 16, 7.223 @@ -593,7 +607,7 @@ static PyObject *pyxc_sedf_domain_set(Xc 7.224 return NULL; 7.225 if ( xc_sedf_domain_set(self->xc_handle, domid, period, 7.226 slice, latency, extratime,weight) != 0 ) 7.227 - return PyErr_SetFromErrno(xc_error); 7.228 + return pyxc_error_to_exception(); 7.229 7.230 Py_INCREF(zero); 7.231 return zero; 7.232 @@ -610,7 +624,7 @@ static PyObject *pyxc_sedf_domain_get(Xc 7.233 7.234 if (xc_sedf_domain_get(self->xc_handle, domid, &period, 7.235 &slice,&latency,&extratime,&weight)) 7.236 - return PyErr_SetFromErrno(xc_error); 7.237 + return pyxc_error_to_exception(); 7.238 7.239 return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i,s:i}", 7.240 "domid", domid, 7.241 @@ -638,7 +652,7 @@ static PyObject *pyxc_shadow_control(PyO 7.242 7.243 if ( xc_shadow_control(xc->xc_handle, dom, op, NULL, 0, NULL, 0, NULL) 7.244 < 0 ) 7.245 - return PyErr_SetFromErrno(xc_error); 7.246 + return pyxc_error_to_exception(); 7.247 7.248 Py_INCREF(zero); 7.249 return zero; 7.250 @@ -668,7 +682,7 @@ static PyObject *pyxc_shadow_mem_control 7.251 op = XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION; 7.252 } 7.253 if ( xc_shadow_control(xc->xc_handle, dom, op, NULL, 0, &mb, 0, NULL) < 0 ) 7.254 - return PyErr_SetFromErrno(xc_error); 7.255 + return pyxc_error_to_exception(); 7.256 7.257 mbarg = mb; 7.258 return Py_BuildValue("i", mbarg); 7.259 @@ -678,7 +692,7 @@ static PyObject *pyxc_sched_id_get(XcObj 7.260 7.261 int sched_id; 7.262 if (xc_sched_id(self->xc_handle, &sched_id) != 0) 7.263 - return PyErr_SetFromErrno(xc_error); 7.264 + return PyErr_SetFromErrno(xc_error_obj); 7.265 7.266 return Py_BuildValue("i", sched_id); 7.267 } 7.268 @@ -704,7 +718,7 @@ static PyObject *pyxc_sched_credit_domai 7.269 sdom.cap = cap; 7.270 7.271 if ( xc_sched_credit_domain_set(self->xc_handle, domid, &sdom) != 0 ) 7.272 - return PyErr_SetFromErrno(xc_error); 7.273 + return pyxc_error_to_exception(); 7.274 7.275 Py_INCREF(zero); 7.276 return zero; 7.277 @@ -719,7 +733,7 @@ static PyObject *pyxc_sched_credit_domai 7.278 return NULL; 7.279 7.280 if ( xc_sched_credit_domain_get(self->xc_handle, domid, &sdom) != 0 ) 7.281 - return PyErr_SetFromErrno(xc_error); 7.282 + return pyxc_error_to_exception(); 7.283 7.284 return Py_BuildValue("{s:H,s:H}", 7.285 "weight", sdom.weight, 7.286 @@ -735,7 +749,7 @@ static PyObject *pyxc_domain_setmaxmem(X 7.287 return NULL; 7.288 7.289 if (xc_domain_setmaxmem(self->xc_handle, dom, maxmem_kb) != 0) 7.290 - return PyErr_SetFromErrno(xc_error); 7.291 + return pyxc_error_to_exception(); 7.292 7.293 Py_INCREF(zero); 7.294 return zero; 7.295 @@ -762,7 +776,7 @@ static PyObject *pyxc_domain_memory_incr 7.296 if ( xc_domain_memory_increase_reservation(self->xc_handle, dom, 7.297 nr_extents, extent_order, 7.298 address_bits, NULL) ) 7.299 - return PyErr_SetFromErrno(xc_error); 7.300 + return pyxc_error_to_exception(); 7.301 7.302 Py_INCREF(zero); 7.303 return zero; 7.304 @@ -784,7 +798,7 @@ static PyObject *pyxc_domain_ioport_perm 7.305 ret = xc_domain_ioport_permission( 7.306 self->xc_handle, dom, first_port, nr_ports, allow_access); 7.307 if ( ret != 0 ) 7.308 - return PyErr_SetFromErrno(xc_error); 7.309 + return pyxc_error_to_exception(); 7.310 7.311 Py_INCREF(zero); 7.312 return zero; 7.313 @@ -807,7 +821,7 @@ static PyObject *pyxc_domain_irq_permiss 7.314 ret = xc_domain_irq_permission( 7.315 xc->xc_handle, dom, pirq, allow_access); 7.316 if ( ret != 0 ) 7.317 - return PyErr_SetFromErrno(xc_error); 7.318 + return pyxc_error_to_exception(); 7.319 7.320 Py_INCREF(zero); 7.321 return zero; 7.322 @@ -830,7 +844,7 @@ static PyObject *pyxc_domain_iomem_permi 7.323 ret = xc_domain_iomem_permission( 7.324 xc->xc_handle, dom, first_pfn, nr_pfns, allow_access); 7.325 if ( ret != 0 ) 7.326 - return PyErr_SetFromErrno(xc_error); 7.327 + return pyxc_error_to_exception(); 7.328 7.329 Py_INCREF(zero); 7.330 return zero; 7.331 @@ -870,7 +884,7 @@ static PyObject *dom_op(XcObject *self, 7.332 return NULL; 7.333 7.334 if (fn(self->xc_handle, dom) != 0) 7.335 - return PyErr_SetFromErrno(xc_error); 7.336 + return pyxc_error_to_exception(); 7.337 7.338 Py_INCREF(zero); 7.339 return zero; 7.340 @@ -1199,7 +1213,7 @@ static int 7.341 PyXc_init(XcObject *self, PyObject *args, PyObject *kwds) 7.342 { 7.343 if ((self->xc_handle = xc_interface_open()) == -1) { 7.344 - PyErr_SetFromErrno(xc_error); 7.345 + pyxc_error_to_exception(); 7.346 return -1; 7.347 } 7.348 7.349 @@ -1272,7 +1286,7 @@ PyMODINIT_FUNC initxc(void) 7.350 if (m == NULL) 7.351 return; 7.352 7.353 - xc_error = PyErr_NewException(PKG ".Error", PyExc_RuntimeError, NULL); 7.354 + xc_error_obj = PyErr_NewException(PKG ".Error", PyExc_RuntimeError, NULL); 7.355 zero = PyInt_FromLong(0); 7.356 7.357 /* KAF: This ensures that we get debug output in a timely manner. */ 7.358 @@ -1282,8 +1296,8 @@ PyMODINIT_FUNC initxc(void) 7.359 Py_INCREF(&PyXcType); 7.360 PyModule_AddObject(m, CLS, (PyObject *)&PyXcType); 7.361 7.362 - Py_INCREF(xc_error); 7.363 - PyModule_AddObject(m, "Error", xc_error); 7.364 + Py_INCREF(xc_error_obj); 7.365 + PyModule_AddObject(m, "Error", xc_error_obj); 7.366 7.367 /* Expose some libxc constants to Python */ 7.368 PyModule_AddIntConstant(m, "XEN_SCHEDULER_SEDF", XEN_SCHEDULER_SEDF);