Merge branch 'akpm' (patches from Andrew)
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 17 Feb 2015 22:35:02 +0000 (14:35 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 17 Feb 2015 22:35:02 +0000 (14:35 -0800)
Merge yet more updates from Andrew Morton:

 - a pile of minor fs fixes and cleanups

 - kexec updates

 - random misc fixes in various places: vmcore, rbtree, eventfd, ipc, seccomp.

 - a series of python-based kgdb helper scripts

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (58 commits)
  seccomp: cap SECCOMP_RET_ERRNO data to MAX_ERRNO
  samples/seccomp: improve label helper
  ipc,sem: use current->state helpers
  scripts/gdb: disable pagination while printing from breakpoint handler
  scripts/gdb: define maintainer
  scripts/gdb: convert CpuList to generator function
  scripts/gdb: convert ModuleList to generator function
  scripts/gdb: use a generator instead of iterator for task list
  scripts/gdb: ignore byte-compiled python files
  scripts/gdb: port to python3 / gdb7.7
  scripts/gdb: add basic documentation
  scripts/gdb: add lx-lsmod command
  scripts/gdb: add class to iterate over CPU masks
  scripts/gdb: add lx_current convenience function
  scripts/gdb: add internal helper and convenience function for per-cpu lookup
  scripts/gdb: add get_gdbserver_type helper
  scripts/gdb: add internal helper and convenience function to retrieve thread_info
  scripts/gdb: add is_target_arch helper
  scripts/gdb: add helper and convenience function to look up tasks
  scripts/gdb: add task iteration class
  ...

43 files changed:
.gitignore
Documentation/gdb-kernel-debugging.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/powerpc/kernel/machine_kexec_64.c
fs/affs/affs.h
fs/affs/amigaffs.c
fs/affs/bitmap.c
fs/affs/dir.c
fs/affs/file.c
fs/affs/inode.c
fs/affs/namei.c
fs/affs/super.c
fs/befs/linuxvfs.c
fs/coda/dir.c
fs/eventfd.c
fs/fat/inode.c
fs/proc/vmcore.c
fs/reiserfs/inode.c
fs/ufs/super.c
include/linux/kexec.h
include/linux/rbtree.h
include/uapi/linux/kexec.h
ipc/sem.c
kernel/kexec.c
kernel/module.c
kernel/ptrace.c
kernel/seccomp.c
kernel/signal.c
lib/Kconfig.debug
samples/seccomp/bpf-fancy.c
samples/seccomp/bpf-helper.c
scripts/Makefile
scripts/gdb/Makefile [new file with mode: 0644]
scripts/gdb/linux/.gitignore [new file with mode: 0644]
scripts/gdb/linux/Makefile [new file with mode: 0644]
scripts/gdb/linux/cpus.py [new file with mode: 0644]
scripts/gdb/linux/dmesg.py [new file with mode: 0644]
scripts/gdb/linux/modules.py [new file with mode: 0644]
scripts/gdb/linux/symbols.py [new file with mode: 0644]
scripts/gdb/linux/tasks.py [new file with mode: 0644]
scripts/gdb/linux/utils.py [new file with mode: 0644]
scripts/gdb/vmlinux-gdb.py [new file with mode: 0644]

index 9ac91060ea6437322d2ac112fe1d9f51d50981f1..acb6afe6b7a3a4acbc0f5f3d00f2a2ead1b8999e 100644 (file)
@@ -43,6 +43,7 @@ Module.symvers
 /TAGS
 /linux
 /vmlinux
+/vmlinux-gdb.py
 /vmlinuz
 /System.map
 /Module.markers
diff --git a/Documentation/gdb-kernel-debugging.txt b/Documentation/gdb-kernel-debugging.txt
new file mode 100644 (file)
index 0000000..7050ce8
--- /dev/null
@@ -0,0 +1,160 @@
+Debugging kernel and modules via gdb
+====================================
+
+The kernel debugger kgdb, hypervisors like QEMU or JTAG-based hardware
+interfaces allow to debug the Linux kernel and its modules during runtime
+using gdb. Gdb comes with a powerful scripting interface for python. The
+kernel provides a collection of helper scripts that can simplify typical
+kernel debugging steps. This is a short tutorial about how to enable and use
+them. It focuses on QEMU/KVM virtual machines as target, but the examples can
+be transferred to the other gdb stubs as well.
+
+
+Requirements
+------------
+
+ o gdb 7.2+ (recommended: 7.4+) with python support enabled (typically true
+   for distributions)
+
+
+Setup
+-----
+
+ o Create a virtual Linux machine for QEMU/KVM (see www.linux-kvm.org and
+   www.qemu.org for more details). For cross-development,
+   http://landley.net/aboriginal/bin keeps a pool of machine images and
+   toolchains that can be helpful to start from.
+
+ o Build the kernel with CONFIG_GDB_SCRIPTS enabled, but leave
+   CONFIG_DEBUG_INFO_REDUCED off. If your architecture supports
+   CONFIG_FRAME_POINTER, keep it enabled.
+
+ o Install that kernel on the guest.
+
+   Alternatively, QEMU allows to boot the kernel directly using -kernel,
+   -append, -initrd command line switches. This is generally only useful if
+   you do not depend on modules. See QEMU documentation for more details on
+   this mode.
+
+ o Enable the gdb stub of QEMU/KVM, either
+    - at VM startup time by appending "-s" to the QEMU command line
+   or
+    - during runtime by issuing "gdbserver" from the QEMU monitor
+      console
+
+ o cd /path/to/linux-build
+
+ o Start gdb: gdb vmlinux
+
+   Note: Some distros may restrict auto-loading of gdb scripts to known safe
+   directories. In case gdb reports to refuse loading vmlinux-gdb.py, add
+
+    add-auto-load-safe-path /path/to/linux-build
+
+   to ~/.gdbinit. See gdb help for more details.
+
+ o Attach to the booted guest:
+    (gdb) target remote :1234
+
+
+Examples of using the Linux-provided gdb helpers
+------------------------------------------------
+
+ o Load module (and main kernel) symbols:
+    (gdb) lx-symbols
+    loading vmlinux
+    scanning for modules in /home/user/linux/build
+    loading @0xffffffffa0020000: /home/user/linux/build/net/netfilter/xt_tcpudp.ko
+    loading @0xffffffffa0016000: /home/user/linux/build/net/netfilter/xt_pkttype.ko
+    loading @0xffffffffa0002000: /home/user/linux/build/net/netfilter/xt_limit.ko
+    loading @0xffffffffa00ca000: /home/user/linux/build/net/packet/af_packet.ko
+    loading @0xffffffffa003c000: /home/user/linux/build/fs/fuse/fuse.ko
+    ...
+    loading @0xffffffffa0000000: /home/user/linux/build/drivers/ata/ata_generic.ko
+
+ o Set a breakpoint on some not yet loaded module function, e.g.:
+    (gdb) b btrfs_init_sysfs
+    Function "btrfs_init_sysfs" not defined.
+    Make breakpoint pending on future shared library load? (y or [n]) y
+    Breakpoint 1 (btrfs_init_sysfs) pending.
+
+ o Continue the target
+    (gdb) c
+
+ o Load the module on the target and watch the symbols being loaded as well as
+   the breakpoint hit:
+    loading @0xffffffffa0034000: /home/user/linux/build/lib/libcrc32c.ko
+    loading @0xffffffffa0050000: /home/user/linux/build/lib/lzo/lzo_compress.ko
+    loading @0xffffffffa006e000: /home/user/linux/build/lib/zlib_deflate/zlib_deflate.ko
+    loading @0xffffffffa01b1000: /home/user/linux/build/fs/btrfs/btrfs.ko
+
+    Breakpoint 1, btrfs_init_sysfs () at /home/user/linux/fs/btrfs/sysfs.c:36
+    36              btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
+
+ o Dump the log buffer of the target kernel:
+    (gdb) lx-dmesg
+    [     0.000000] Initializing cgroup subsys cpuset
+    [     0.000000] Initializing cgroup subsys cpu
+    [     0.000000] Linux version 3.8.0-rc4-dbg+ (...
+    [     0.000000] Command line: root=/dev/sda2 resume=/dev/sda1 vga=0x314
+    [     0.000000] e820: BIOS-provided physical RAM map:
+    [     0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
+    [     0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
+    ....
+
+ o Examine fields of the current task struct:
+    (gdb) p $lx_current().pid
+    $1 = 4998
+    (gdb) p $lx_current().comm
+    $2 = "modprobe\000\000\000\000\000\000\000"
+
+ o Make use of the per-cpu function for the current or a specified CPU:
+    (gdb) p $lx_per_cpu("runqueues").nr_running
+    $3 = 1
+    (gdb) p $lx_per_cpu("runqueues", 2).nr_running
+    $4 = 0
+
+ o Dig into hrtimers using the container_of helper:
+    (gdb) set $next = $lx_per_cpu("hrtimer_bases").clock_base[0].active.next
+    (gdb) p *$container_of($next, "struct hrtimer", "node")
+    $5 = {
+      node = {
+        node = {
+          __rb_parent_color = 18446612133355256072,
+          rb_right = 0x0 <irq_stack_union>,
+          rb_left = 0x0 <irq_stack_union>
+        },
+        expires = {
+          tv64 = 1835268000000
+        }
+      },
+      _softexpires = {
+        tv64 = 1835268000000
+      },
+      function = 0xffffffff81078232 <tick_sched_timer>,
+      base = 0xffff88003fd0d6f0,
+      state = 1,
+      start_pid = 0,
+      start_site = 0xffffffff81055c1f <hrtimer_start_range_ns+20>,
+      start_comm = "swapper/2\000\000\000\000\000\000"
+    }
+
+
+List of commands and functions
+------------------------------
+
+The number of commands and convenience functions may evolve over the time,
+this is just a snapshot of the initial version:
+
+ (gdb) apropos lx
+ function lx_current -- Return current task
+ function lx_module -- Find module by name and return the module variable
+ function lx_per_cpu -- Return per-cpu variable
+ function lx_task_by_pid -- Find Linux task by PID and return the task_struct variable
+ function lx_thread_info -- Calculate Linux thread_info from task variable
+ lx-dmesg -- Print Linux kernel log buffer
+ lx-lsmod -- List currently loaded modules
+ lx-symbols -- (Re-)load symbols of Linux kernel and currently loaded modules
+
+Detailed help can be obtained via "help <command-name>" for commands and "help
+function <function-name>" for convenience functions.
index 3eee4c7739aec4675ae08daa1a1fe6d49fccb22d..0597c5b3c4ee0a27fde7e0d189cee46be9822181 100644 (file)
@@ -4232,6 +4232,11 @@ W:       http://www.icp-vortex.com/
 S:     Supported
 F:     drivers/scsi/gdt*
 
+GDB KERNEL DEBUGGING HELPER SCRIPTS
+M:     Jan Kiszka <jan.kiszka@siemens.com>
+S:     Supported
+F:     scripts/gdb/
+
 GEMTEK FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
index 33cb15efd257564251edd7a5e6d90740c0cf3339..dd8796caa23982428676d25ed78967d3b2d0e069 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -926,6 +926,9 @@ ifdef CONFIG_SAMPLES
 endif
 ifdef CONFIG_BUILD_DOCSRC
        $(Q)$(MAKE) $(build)=Documentation
+endif
+ifdef CONFIG_GDB_SCRIPTS
+       $(Q)ln -fsn `cd $(srctree) && /bin/pwd`/scripts/gdb/vmlinux-gdb.py
 endif
        +$(call if_changed,link-vmlinux)
 
@@ -1181,7 +1184,7 @@ MRPROPER_FILES += .config .config.old .version .old_version $(version_h) \
                  Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \
                  signing_key.priv signing_key.x509 x509.genkey         \
                  extra_certificates signing_key.x509.keyid             \
-                 signing_key.x509.signer
+                 signing_key.x509.signer vmlinux-gdb.py
 
 # clean - Delete most, but leave enough to build external modules
 #
index f96d1ec241891b9683761d3e04c2daed29d670d1..1a74446fd9e5a38c0535e8ec77b057fe8e80fbd5 100644 (file)
@@ -96,8 +96,6 @@ int default_machine_kexec_prepare(struct kimage *image)
        return 0;
 }
 
-#define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE)
-
 static void copy_segments(unsigned long ind)
 {
        unsigned long entry;
index ff44ff3ff015f6bda981be87dde47d79bf2a7fcc..c8764bd7497de19c366d40794659b6e7cd037dee 100644 (file)
@@ -30,6 +30,8 @@
 #define AFFS_AC_SIZE           (AFFS_CACHE_SIZE/sizeof(struct affs_ext_key)/2)
 #define AFFS_AC_MASK           (AFFS_AC_SIZE-1)
 
+#define AFFSNAMEMAX 30U
+
 struct affs_ext_key {
        u32     ext;                            /* idx of the extended block */
        u32     key;                            /* block number */
index c852f2fa17102a24935f27adb68198fe90a82f92..388da1ea815d07dd43af7a856293a4c3c840e400 100644 (file)
@@ -30,7 +30,7 @@ affs_insert_hash(struct inode *dir, struct buffer_head *bh)
        ino = bh->b_blocknr;
        offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]);
 
-       pr_debug("%s(dir=%u, ino=%d)\n", __func__, (u32)dir->i_ino, ino);
+       pr_debug("%s(dir=%lu, ino=%d)\n", __func__, dir->i_ino, ino);
 
        dir_bh = affs_bread(sb, dir->i_ino);
        if (!dir_bh)
@@ -80,8 +80,8 @@ affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
        sb = dir->i_sb;
        rem_ino = rem_bh->b_blocknr;
        offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]);
-       pr_debug("%s(dir=%d, ino=%d, hashval=%d)\n",
-                __func__, (u32)dir->i_ino, rem_ino, offset);
+       pr_debug("%s(dir=%lu, ino=%d, hashval=%d)\n", __func__, dir->i_ino,
+                rem_ino, offset);
 
        bh = affs_bread(sb, dir->i_ino);
        if (!bh)
@@ -483,11 +483,10 @@ affs_check_name(const unsigned char *name, int len, bool notruncate)
 {
        int      i;
 
-       if (len > 30) {
+       if (len > AFFSNAMEMAX) {
                if (notruncate)
                        return -ENAMETOOLONG;
-               else
-                       len = 30;
+               len = AFFSNAMEMAX;
        }
        for (i = 0; i < len; i++) {
                if (name[i] < ' ' || name[i] == ':'
@@ -508,7 +507,7 @@ affs_check_name(const unsigned char *name, int len, bool notruncate)
 int
 affs_copy_name(unsigned char *bstr, struct dentry *dentry)
 {
-       int len = min(dentry->d_name.len, 30u);
+       u32 len = min(dentry->d_name.len, AFFSNAMEMAX);
 
        *bstr++ = len;
        memcpy(bstr, dentry->d_name.name, len);
index c8de51185c23b1468ac8cab62500a287148023ee..675148950fed973963f8229c41f964070fe60039 100644 (file)
@@ -99,7 +99,6 @@ err_bh_read:
 
 err_range:
        affs_error(sb, "affs_free_block","Block %u outside partition", block);
-       return;
 }
 
 /*
index 59f07bec92a6c18918b6f28b0b0bc057952ebe9e..ac4f318aafba875a6df22b4ce3784f8f00278044 100644 (file)
@@ -54,8 +54,7 @@ affs_readdir(struct file *file, struct dir_context *ctx)
        u32                      ino;
        int                      error = 0;
 
-       pr_debug("%s(ino=%lu,f_pos=%lx)\n",
-                __func__, inode->i_ino, (unsigned long)ctx->pos);
+       pr_debug("%s(ino=%lu,f_pos=%llx)\n", __func__, inode->i_ino, ctx->pos);
 
        if (ctx->pos < 2) {
                file->private_data = (void *)0;
@@ -115,11 +114,11 @@ inside:
                                break;
                        }
 
-                       namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], (u8)30);
+                       namelen = min(AFFS_TAIL(sb, fh_bh)->name[0],
+                                     (u8)AFFSNAMEMAX);
                        name = AFFS_TAIL(sb, fh_bh)->name + 1;
-                       pr_debug("readdir(): dir_emit(\"%.*s\", "
-                                "ino=%u), hash=%d, f_pos=%x\n",
-                                namelen, name, ino, hash_pos, (u32)ctx->pos);
+                       pr_debug("readdir(): dir_emit(\"%.*s\", ino=%u), hash=%d, f_pos=%llx\n",
+                                namelen, name, ino, hash_pos, ctx->pos);
 
                        if (!dir_emit(ctx, name, namelen, ino, DT_UNKNOWN))
                                goto done;
index 8faa6593ca6defe4ab77c169f3fe9673b84a9ec3..d2468bf95669850520a2a0dc852b1185c5234c7b 100644 (file)
@@ -180,8 +180,7 @@ affs_get_extblock_slow(struct inode *inode, u32 ext)
                ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
                if (ext < AFFS_I(inode)->i_extcnt)
                        goto read_ext;
-               if (ext > AFFS_I(inode)->i_extcnt)
-                       BUG();
+               BUG_ON(ext > AFFS_I(inode)->i_extcnt);
                bh = affs_alloc_extblock(inode, bh, ext);
                if (IS_ERR(bh))
                        return bh;
@@ -198,8 +197,7 @@ affs_get_extblock_slow(struct inode *inode, u32 ext)
                struct buffer_head *prev_bh;
 
                /* allocate a new extended block */
-               if (ext > AFFS_I(inode)->i_extcnt)
-                       BUG();
+               BUG_ON(ext > AFFS_I(inode)->i_extcnt);
 
                /* get previous extended block */
                prev_bh = affs_get_extblock(inode, ext - 1);
@@ -299,8 +297,8 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul
        struct buffer_head      *ext_bh;
        u32                      ext;
 
-       pr_debug("%s(%u, %lu)\n",
-                __func__, (u32)inode->i_ino, (unsigned long)block);
+       pr_debug("%s(%lu, %llu)\n", __func__, inode->i_ino,
+                (unsigned long long)block);
 
        BUG_ON(block > (sector_t)0x7fffffffUL);
 
@@ -330,8 +328,9 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul
 
                /* store new block */
                if (bh_result->b_blocknr)
-                       affs_warning(sb, "get_block", "block already set (%lx)",
-                                    (unsigned long)bh_result->b_blocknr);
+                       affs_warning(sb, "get_block",
+                                    "block already set (%llx)",
+                                    (unsigned long long)bh_result->b_blocknr);
                AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr);
                AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1);
                affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1);
@@ -353,8 +352,8 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul
        return 0;
 
 err_big:
-       affs_error(inode->i_sb, "get_block", "strange block request %d",
-                  (int)block);
+       affs_error(inode->i_sb, "get_block", "strange block request %llu",
+                  (unsigned long long)block);
        return -EIO;
 err_ext:
        // unlock cache
@@ -399,6 +398,13 @@ affs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter,
        size_t count = iov_iter_count(iter);
        ssize_t ret;
 
+       if (rw == WRITE) {
+               loff_t size = offset + count;
+
+               if (AFFS_I(inode)->mmu_private < size)
+                       return 0;
+       }
+
        ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, affs_get_block);
        if (ret < 0 && (rw & WRITE))
                affs_write_failed(mapping, offset + count);
@@ -503,7 +509,7 @@ affs_do_readpage_ofs(struct page *page, unsigned to)
        u32 bidx, boff, bsize;
        u32 tmp;
 
-       pr_debug("%s(%u, %ld, 0, %d)\n", __func__, (u32)inode->i_ino,
+       pr_debug("%s(%lu, %ld, 0, %d)\n", __func__, inode->i_ino,
                 page->index, to);
        BUG_ON(to > PAGE_CACHE_SIZE);
        kmap(page);
@@ -539,7 +545,7 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize)
        u32 size, bsize;
        u32 tmp;
 
-       pr_debug("%s(%u, %d)\n", __func__, (u32)inode->i_ino, newsize);
+       pr_debug("%s(%lu, %d)\n", __func__, inode->i_ino, newsize);
        bsize = AFFS_SB(sb)->s_data_blksize;
        bh = NULL;
        size = AFFS_I(inode)->mmu_private;
@@ -608,7 +614,7 @@ affs_readpage_ofs(struct file *file, struct page *page)
        u32 to;
        int err;
 
-       pr_debug("%s(%u, %ld)\n", __func__, (u32)inode->i_ino, page->index);
+       pr_debug("%s(%lu, %ld)\n", __func__, inode->i_ino, page->index);
        to = PAGE_CACHE_SIZE;
        if (((page->index + 1) << PAGE_CACHE_SHIFT) > inode->i_size) {
                to = inode->i_size & ~PAGE_CACHE_MASK;
@@ -631,8 +637,8 @@ static int affs_write_begin_ofs(struct file *file, struct address_space *mapping
        pgoff_t index;
        int err = 0;
 
-       pr_debug("%s(%u, %llu, %llu)\n", __func__, (u32)inode->i_ino,
-                (unsigned long long)pos, (unsigned long long)pos + len);
+       pr_debug("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos,
+                pos + len);
        if (pos > AFFS_I(inode)->mmu_private) {
                /* XXX: this probably leaves a too-big i_size in case of
                 * failure. Should really be updating i_size at write_end time
@@ -681,9 +687,8 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
         * due to write_begin.
         */
 
-       pr_debug("%s(%u, %llu, %llu)\n",
-                __func__, (u32)inode->i_ino, (unsigned long long)pos,
-               (unsigned long long)pos + len);
+       pr_debug("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos,
+                pos + len);
        bsize = AFFS_SB(sb)->s_data_blksize;
        data = page_address(page);
 
@@ -831,8 +836,8 @@ affs_truncate(struct inode *inode)
        struct buffer_head *ext_bh;
        int i;
 
-       pr_debug("truncate(inode=%d, oldsize=%u, newsize=%u)\n",
-                (u32)inode->i_ino, (u32)AFFS_I(inode)->mmu_private, (u32)inode->i_size);
+       pr_debug("truncate(inode=%lu, oldsize=%llu, newsize=%llu)\n",
+                inode->i_ino, AFFS_I(inode)->mmu_private, inode->i_size);
 
        last_blk = 0;
        ext = 0;
@@ -863,7 +868,7 @@ affs_truncate(struct inode *inode)
        if (IS_ERR(ext_bh)) {
                affs_warning(sb, "truncate",
                             "unexpected read error for ext block %u (%ld)",
-                            (unsigned int)ext, PTR_ERR(ext_bh));
+                            ext, PTR_ERR(ext_bh));
                return;
        }
        if (AFFS_I(inode)->i_lc) {
@@ -911,7 +916,7 @@ affs_truncate(struct inode *inode)
                        if (IS_ERR(bh)) {
                                affs_warning(sb, "truncate",
                                             "unexpected read error for last block %u (%ld)",
-                                            (unsigned int)ext, PTR_ERR(bh));
+                                            ext, PTR_ERR(bh));
                                return;
                        }
                        tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next);
index d0609a282e1dadb8f34198e600af6d1c47cebb2e..6f34510449e892b3afc807760d1108cba16d0dc2 100644 (file)
@@ -13,8 +13,6 @@
 #include <linux/gfp.h>
 #include "affs.h"
 
-extern const struct inode_operations affs_symlink_inode_operations;
-
 struct inode *affs_iget(struct super_block *sb, unsigned long ino)
 {
        struct affs_sb_info     *sbi = AFFS_SB(sb);
@@ -348,9 +346,8 @@ affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s3
        u32 block = 0;
        int retval;
 
-       pr_debug("%s(dir=%u, inode=%u, \"%pd\", type=%d)\n",
-                __func__, (u32)dir->i_ino,
-                (u32)inode->i_ino, dentry, type);
+       pr_debug("%s(dir=%lu, inode=%lu, \"%pd\", type=%d)\n", __func__,
+                dir->i_ino, inode->i_ino, dentry, type);
 
        retval = -EIO;
        bh = affs_bread(sb, inode->i_ino);
index bbc38530e924eb61fe69297dd761b41ddb14db82..ffb7bd82c2a5e8ffa84d08e49a6f8bbb086527ca 100644 (file)
@@ -64,15 +64,16 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate)
 {
        const u8 *name = qstr->name;
        unsigned long hash;
-       int i;
+       int retval;
+       u32 len;
 
-       i = affs_check_name(qstr->name, qstr->len, notruncate);
-       if (i)
-               return i;
+       retval = affs_check_name(qstr->name, qstr->len, notruncate);
+       if (retval)
+               return retval;
 
        hash = init_name_hash();
-       i = min(qstr->len, 30u);
-       for (; i > 0; name++, i--)
+       len = min(qstr->len, AFFSNAMEMAX);
+       for (; len > 0; name++, len--)
                hash = partial_name_hash(toupper(*name), hash);
        qstr->hash = end_name_hash(hash);
 
@@ -114,10 +115,10 @@ static inline int __affs_compare_dentry(unsigned int len,
         * If the names are longer than the allowed 30 chars,
         * the excess is ignored, so their length may differ.
         */
-       if (len >= 30) {
-               if (name->len < 30)
+       if (len >= AFFSNAMEMAX) {
+               if (name->len < AFFSNAMEMAX)
                        return 1;
-               len = 30;
+               len = AFFSNAMEMAX;
        } else if (len != name->len)
                return 1;
 
@@ -156,10 +157,10 @@ affs_match(struct dentry *dentry, const u8 *name2, toupper_t toupper)
        const u8 *name = dentry->d_name.name;
        int len = dentry->d_name.len;
 
-       if (len >= 30) {
-               if (*name2 < 30)
+       if (len >= AFFSNAMEMAX) {
+               if (*name2 < AFFSNAMEMAX)
                        return 0;
-               len = 30;
+               len = AFFSNAMEMAX;
        } else if (len != *name2)
                return 0;
 
@@ -173,9 +174,9 @@ int
 affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len)
 {
        toupper_t toupper = affs_get_toupper(sb);
-       int hash;
+       u32 hash;
 
-       hash = len = min(len, 30u);
+       hash = len = min(len, AFFSNAMEMAX);
        for (; len > 0; len--)
                hash = (hash * 13 + toupper(*name++)) & 0x7ff;
 
@@ -248,9 +249,8 @@ affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 int
 affs_unlink(struct inode *dir, struct dentry *dentry)
 {
-       pr_debug("%s(dir=%d, %lu \"%pd\")\n",
-                __func__, (u32)dir->i_ino, dentry->d_inode->i_ino,
-               dentry);
+       pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
+                dentry->d_inode->i_ino, dentry);
 
        return affs_remove_header(dentry);
 }
@@ -317,9 +317,8 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 int
 affs_rmdir(struct inode *dir, struct dentry *dentry)
 {
-       pr_debug("%s(dir=%u, %lu \"%pd\")\n",
-               __func__, (u32)dir->i_ino, dentry->d_inode->i_ino,
-                dentry);
+       pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
+                dentry->d_inode->i_ino, dentry);
 
        return affs_remove_header(dentry);
 }
@@ -404,8 +403,7 @@ affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 {
        struct inode *inode = old_dentry->d_inode;
 
-       pr_debug("%s(%u, %u, \"%pd\")\n",
-                __func__, (u32)inode->i_ino, (u32)dir->i_ino,
+       pr_debug("%s(%lu, %lu, \"%pd\")\n", __func__, inode->i_ino, dir->i_ino,
                 dentry);
 
        return affs_add_entry(dir, inode, dentry, ST_LINKFILE);
@@ -419,9 +417,8 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct buffer_head *bh = NULL;
        int retval;
 
-       pr_debug("%s(old=%u,\"%pd\" to new=%u,\"%pd\")\n",
-                __func__, (u32)old_dir->i_ino, old_dentry,
-                (u32)new_dir->i_ino, new_dentry);
+       pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__,
+                old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry);
 
        retval = affs_check_name(new_dentry->d_name.name,
                                 new_dentry->d_name.len,
index f754ab68a840a22d1d9eae18f78706a8537f07ea..4cf0e9113fb60c67f0944b4465262f4172ab8125 100644 (file)
@@ -432,39 +432,39 @@ got_root:
                sb->s_flags |= MS_RDONLY;
        }
        switch (chksum) {
-               case MUFS_FS:
-               case MUFS_INTLFFS:
-               case MUFS_DCFFS:
-                       sbi->s_flags |= SF_MUFS;
-                       /* fall thru */
-               case FS_INTLFFS:
-               case FS_DCFFS:
-                       sbi->s_flags |= SF_INTL;
-                       break;
-               case MUFS_FFS:
-                       sbi->s_flags |= SF_MUFS;
-                       break;
-               case FS_FFS:
-                       break;
-               case MUFS_OFS:
-                       sbi->s_flags |= SF_MUFS;
-                       /* fall thru */
-               case FS_OFS:
-                       sbi->s_flags |= SF_OFS;
-                       sb->s_flags |= MS_NOEXEC;
-                       break;
-               case MUFS_DCOFS:
-               case MUFS_INTLOFS:
-                       sbi->s_flags |= SF_MUFS;
-               case FS_DCOFS:
-               case FS_INTLOFS:
-                       sbi->s_flags |= SF_INTL | SF_OFS;
-                       sb->s_flags |= MS_NOEXEC;
-                       break;
-               default:
-                       pr_err("Unknown filesystem on device %s: %08X\n",
-                              sb->s_id, chksum);
-                       return -EINVAL;
+       case MUFS_FS:
+       case MUFS_INTLFFS:
+       case MUFS_DCFFS:
+               sbi->s_flags |= SF_MUFS;
+               /* fall thru */
+       case FS_INTLFFS:
+       case FS_DCFFS:
+               sbi->s_flags |= SF_INTL;
+               break;
+       case MUFS_FFS:
+               sbi->s_flags |= SF_MUFS;
+               break;
+       case FS_FFS:
+               break;
+       case MUFS_OFS:
+               sbi->s_flags |= SF_MUFS;
+               /* fall thru */
+       case FS_OFS:
+               sbi->s_flags |= SF_OFS;
+               sb->s_flags |= MS_NOEXEC;
+               break;
+       case MUFS_DCOFS:
+       case MUFS_INTLOFS:
+               sbi->s_flags |= SF_MUFS;
+       case FS_DCOFS:
+       case FS_INTLOFS:
+               sbi->s_flags |= SF_INTL | SF_OFS;
+               sb->s_flags |= MS_NOEXEC;
+               break;
+       default:
+               pr_err("Unknown filesystem on device %s: %08X\n",
+                      sb->s_id, chksum);
+               return -EINVAL;
        }
 
        if (mount_flags & SF_VERBOSE) {
@@ -584,7 +584,7 @@ affs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail  = free;
        buf->f_fsid.val[0] = (u32)id;
        buf->f_fsid.val[1] = (u32)(id >> 32);
-       buf->f_namelen = 30;
+       buf->f_namelen = AFFSNAMEMAX;
        return 0;
 }
 
@@ -602,6 +602,7 @@ static void affs_kill_sb(struct super_block *sb)
                affs_free_bitmap(sb);
                affs_brelse(sbi->s_root_bh);
                kfree(sbi->s_prefix);
+               mutex_destroy(&sbi->s_bmlock);
                kfree(sbi);
        }
 }
index edf47774b03d56f7ab0671a4b6d57b7f4193a550..e089f1985fcaa35e4e213669776e0f3190fc0db8 100644 (file)
@@ -274,9 +274,9 @@ more:
 static struct inode *
 befs_alloc_inode(struct super_block *sb)
 {
-        struct befs_inode_info *bi;
-        bi = (struct befs_inode_info *)kmem_cache_alloc(befs_inode_cachep,
-                                                       GFP_KERNEL);
+       struct befs_inode_info *bi;
+
+       bi = kmem_cache_alloc(befs_inode_cachep, GFP_KERNEL);
         if (!bi)
                 return NULL;
         return &bi->vfs_inode;
index 86c893884eb988010e7beea589363cd64eb7cc0b..281ee011bb6a936125cdcfdde6d8122e66447b15 100644 (file)
 
 #include "coda_int.h"
 
-/* dir inode-ops */
-static int coda_create(struct inode *dir, struct dentry *new, umode_t mode, bool excl);
-static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, unsigned int flags);
-static int coda_link(struct dentry *old_dentry, struct inode *dir_inode, 
-                    struct dentry *entry);
-static int coda_unlink(struct inode *dir_inode, struct dentry *entry);
-static int coda_symlink(struct inode *dir_inode, struct dentry *entry,
-                       const char *symname);
-static int coda_mkdir(struct inode *dir_inode, struct dentry *entry, umode_t mode);
-static int coda_rmdir(struct inode *dir_inode, struct dentry *entry);
-static int coda_rename(struct inode *old_inode, struct dentry *old_dentry, 
-                       struct inode *new_inode, struct dentry *new_dentry);
-
-/* dir file-ops */
-static int coda_readdir(struct file *file, struct dir_context *ctx);
-
-/* dentry ops */
-static int coda_dentry_revalidate(struct dentry *de, unsigned int flags);
-static int coda_dentry_delete(const struct dentry *);
-
-/* support routines */
-static int coda_venus_readdir(struct file *, struct dir_context *);
-
 /* same as fs/bad_inode.c */
 static int coda_return_EIO(void)
 {
@@ -58,38 +35,6 @@ static int coda_return_EIO(void)
 }
 #define CODA_EIO_ERROR ((void *) (coda_return_EIO))
 
-const struct dentry_operations coda_dentry_operations =
-{
-       .d_revalidate   = coda_dentry_revalidate,
-       .d_delete       = coda_dentry_delete,
-};
-
-const struct inode_operations coda_dir_inode_operations =
-{
-       .create         = coda_create,
-       .lookup         = coda_lookup,
-       .link           = coda_link,
-       .unlink         = coda_unlink,
-       .symlink        = coda_symlink,
-       .mkdir          = coda_mkdir,
-       .rmdir          = coda_rmdir,
-       .mknod          = CODA_EIO_ERROR,
-       .rename         = coda_rename,
-       .permission     = coda_permission,
-       .getattr        = coda_getattr,
-       .setattr        = coda_setattr,
-};
-
-const struct file_operations coda_dir_operations = {
-       .llseek         = generic_file_llseek,
-       .read           = generic_read_dir,
-       .iterate        = coda_readdir,
-       .open           = coda_open,
-       .release        = coda_release,
-       .fsync          = coda_fsync,
-};
-
-
 /* inode operations for directories */
 /* access routines: lookup, readlink, permission */
 static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsigned int flags)
@@ -374,33 +319,6 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
        return error;
 }
 
-
-/* file operations for directories */
-static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
-{
-       struct coda_file_info *cfi;
-       struct file *host_file;
-       int ret;
-
-       cfi = CODA_FTOC(coda_file);
-       BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
-       host_file = cfi->cfi_container;
-
-       if (host_file->f_op->iterate) {
-               struct inode *host_inode = file_inode(host_file);
-               mutex_lock(&host_inode->i_mutex);
-               ret = -ENOENT;
-               if (!IS_DEADDIR(host_inode)) {
-                       ret = host_file->f_op->iterate(host_file, ctx);
-                       file_accessed(host_file);
-               }
-               mutex_unlock(&host_inode->i_mutex);
-               return ret;
-       }
-       /* Venus: we must read Venus dirents from a file */
-       return coda_venus_readdir(coda_file, ctx);
-}
-
 static inline unsigned int CDT2DT(unsigned char cdt)
 {
        unsigned int dt;
@@ -495,6 +413,33 @@ out:
        return 0;
 }
 
+/* file operations for directories */
+static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
+{
+       struct coda_file_info *cfi;
+       struct file *host_file;
+       int ret;
+
+       cfi = CODA_FTOC(coda_file);
+       BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+       host_file = cfi->cfi_container;
+
+       if (host_file->f_op->iterate) {
+               struct inode *host_inode = file_inode(host_file);
+
+               mutex_lock(&host_inode->i_mutex);
+               ret = -ENOENT;
+               if (!IS_DEADDIR(host_inode)) {
+                       ret = host_file->f_op->iterate(host_file, ctx);
+                       file_accessed(host_file);
+               }
+               mutex_unlock(&host_inode->i_mutex);
+               return ret;
+       }
+       /* Venus: we must read Venus dirents from a file */
+       return coda_venus_readdir(coda_file, ctx);
+}
+
 /* called when a cache lookup succeeds */
 static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)
 {
@@ -603,3 +548,32 @@ int coda_revalidate_inode(struct inode *inode)
        }
        return 0;
 }
+
+const struct dentry_operations coda_dentry_operations = {
+       .d_revalidate   = coda_dentry_revalidate,
+       .d_delete       = coda_dentry_delete,
+};
+
+const struct inode_operations coda_dir_inode_operations = {
+       .create         = coda_create,
+       .lookup         = coda_lookup,
+       .link           = coda_link,
+       .unlink         = coda_unlink,
+       .symlink        = coda_symlink,
+       .mkdir          = coda_mkdir,
+       .rmdir          = coda_rmdir,
+       .mknod          = CODA_EIO_ERROR,
+       .rename         = coda_rename,
+       .permission     = coda_permission,
+       .getattr        = coda_getattr,
+       .setattr        = coda_setattr,
+};
+
+const struct file_operations coda_dir_operations = {
+       .llseek         = generic_file_llseek,
+       .read           = generic_read_dir,
+       .iterate        = coda_readdir,
+       .open           = coda_open,
+       .release        = coda_release,
+       .fsync          = coda_fsync,
+};
index 4b0a226024fa51801b0cd718fcfae79ef828e8e4..8d0c0df018549b86b9759225c2aa2ef88a5728dc 100644 (file)
@@ -118,18 +118,18 @@ static unsigned int eventfd_poll(struct file *file, poll_table *wait)
 {
        struct eventfd_ctx *ctx = file->private_data;
        unsigned int events = 0;
-       unsigned long flags;
+       u64 count;
 
        poll_wait(file, &ctx->wqh, wait);
+       smp_rmb();
+       count = ctx->count;
 
-       spin_lock_irqsave(&ctx->wqh.lock, flags);
-       if (ctx->count > 0)
+       if (count > 0)
                events |= POLLIN;
-       if (ctx->count == ULLONG_MAX)
+       if (count == ULLONG_MAX)
                events |= POLLERR;
-       if (ULLONG_MAX - 1 > ctx->count)
+       if (ULLONG_MAX - 1 > count)
                events |= POLLOUT;
-       spin_unlock_irqrestore(&ctx->wqh.lock, flags);
 
        return events;
 }
index 7b41a2dcdd7662d8d7be045d94523b97299dd879..497c7c5263c7ca3962c385605fbbb558d351f759 100644 (file)
@@ -580,7 +580,7 @@ static void fat_set_state(struct super_block *sb,
 {
        struct buffer_head *bh;
        struct fat_boot_sector *b;
-       struct msdos_sb_info *sbi = sb->s_fs_info;
+       struct msdos_sb_info *sbi = MSDOS_SB(sb);
 
        /* do not change any thing if mounted read only */
        if ((sb->s_flags & MS_RDONLY) && !force)
index a90d6d3541992552d30d2b4a2bac062d352f576d..4e61388ec03d2af3a426bb788f2382f4f27db1aa 100644 (file)
@@ -546,8 +546,8 @@ static int __init update_note_header_size_elf64(const Elf64_Ehdr *ehdr_ptr)
                nhdr_ptr = notes_section;
                while (nhdr_ptr->n_namesz != 0) {
                        sz = sizeof(Elf64_Nhdr) +
-                               ((nhdr_ptr->n_namesz + 3) & ~3) +
-                               ((nhdr_ptr->n_descsz + 3) & ~3);
+                               (((u64)nhdr_ptr->n_namesz + 3) & ~3) +
+                               (((u64)nhdr_ptr->n_descsz + 3) & ~3);
                        if ((real_sz + sz) > max_sz) {
                                pr_warn("Warning: Exceeded p_memsz, dropping PT_NOTE entry n_namesz=0x%x, n_descsz=0x%x\n",
                                        nhdr_ptr->n_namesz, nhdr_ptr->n_descsz);
@@ -732,8 +732,8 @@ static int __init update_note_header_size_elf32(const Elf32_Ehdr *ehdr_ptr)
                nhdr_ptr = notes_section;
                while (nhdr_ptr->n_namesz != 0) {
                        sz = sizeof(Elf32_Nhdr) +
-                               ((nhdr_ptr->n_namesz + 3) & ~3) +
-                               ((nhdr_ptr->n_descsz + 3) & ~3);
+                               (((u64)nhdr_ptr->n_namesz + 3) & ~3) +
+                               (((u64)nhdr_ptr->n_descsz + 3) & ~3);
                        if ((real_sz + sz) > max_sz) {
                                pr_warn("Warning: Exceeded p_memsz, dropping PT_NOTE entry n_namesz=0x%x, n_descsz=0x%x\n",
                                        nhdr_ptr->n_namesz, nhdr_ptr->n_descsz);
index a7eec9888f10f1d2e3f6b0f92bbddba8aaea21cc..e72401e1f9956238064c91805279233a721bffe1 100644 (file)
@@ -2766,7 +2766,7 @@ static int reiserfs_write_begin(struct file *file,
        int old_ref = 0;
 
        inode = mapping->host;
-       *fsdata = 0;
+       *fsdata = NULL;
        if (flags & AOP_FLAG_CONT_EXPAND &&
            (pos & (inode->i_sb->s_blocksize - 1)) == 0) {
                pos ++;
index da73801301d588bf14eb4e107e42609bedbfb51b..8092d3759a5e560001ad75bdb9a5238c053a8523 100644 (file)
 
 void lock_ufs(struct super_block *sb)
 {
-#if defined(CONFIG_SMP) || defined (CONFIG_PREEMPT)
        struct ufs_sb_info *sbi = UFS_SB(sb);
 
        mutex_lock(&sbi->mutex);
        sbi->mutex_owner = current;
-#endif
 }
 
 void unlock_ufs(struct super_block *sb)
 {
-#if defined(CONFIG_SMP) || defined (CONFIG_PREEMPT)
        struct ufs_sb_info *sbi = UFS_SB(sb);
 
        sbi->mutex_owner = NULL;
        mutex_unlock(&sbi->mutex);
-#endif
 }
 
 static struct inode *ufs_nfs_get_inode(struct super_block *sb, u64 ino, u32 generation)
@@ -1415,9 +1411,11 @@ static struct kmem_cache * ufs_inode_cachep;
 static struct inode *ufs_alloc_inode(struct super_block *sb)
 {
        struct ufs_inode_info *ei;
-       ei = (struct ufs_inode_info *)kmem_cache_alloc(ufs_inode_cachep, GFP_NOFS);
+
+       ei = kmem_cache_alloc(ufs_inode_cachep, GFP_NOFS);
        if (!ei)
                return NULL;
+
        ei->vfs_inode.i_version = 1;
        return &ei->vfs_inode;
 }
index 9d957b7ae095ed7f2980db140a9c21a6aae70084..e60a745ac1982cd0ba11c29bad97d3175c681002 100644 (file)
@@ -1,6 +1,19 @@
 #ifndef LINUX_KEXEC_H
 #define LINUX_KEXEC_H
 
+#define IND_DESTINATION_BIT 0
+#define IND_INDIRECTION_BIT 1
+#define IND_DONE_BIT        2
+#define IND_SOURCE_BIT      3
+
+#define IND_DESTINATION  (1 << IND_DESTINATION_BIT)
+#define IND_INDIRECTION  (1 << IND_INDIRECTION_BIT)
+#define IND_DONE         (1 << IND_DONE_BIT)
+#define IND_SOURCE       (1 << IND_SOURCE_BIT)
+#define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE)
+
+#if !defined(__ASSEMBLY__)
+
 #include <uapi/linux/kexec.h>
 
 #ifdef CONFIG_KEXEC
  */
 
 typedef unsigned long kimage_entry_t;
-#define IND_DESTINATION  0x1
-#define IND_INDIRECTION  0x2
-#define IND_DONE         0x4
-#define IND_SOURCE       0x8
 
 struct kexec_segment {
        /*
@@ -122,8 +131,6 @@ struct kimage {
        kimage_entry_t *entry;
        kimage_entry_t *last_entry;
 
-       unsigned long destination;
-
        unsigned long start;
        struct page *control_code_page;
        struct page *swap_page;
@@ -313,4 +320,7 @@ struct task_struct;
 static inline void crash_kexec(struct pt_regs *regs) { }
 static inline int kexec_should_crash(struct task_struct *p) { return 0; }
 #endif /* CONFIG_KEXEC */
+
+#endif /* !defined(__ASSEBMLY__) */
+
 #endif /* LINUX_KEXEC_H */
index 57e75ae9910f7584f47c523ae1671ce916e9ed67..fb31765e935a0590ae0a6d82dda16a4a89dc36a4 100644 (file)
@@ -51,7 +51,7 @@ struct rb_root {
 
 #define RB_EMPTY_ROOT(root)  ((root)->rb_node == NULL)
 
-/* 'empty' nodes are nodes that are known not to be inserted in an rbree */
+/* 'empty' nodes are nodes that are known not to be inserted in an rbtree */
 #define RB_EMPTY_NODE(node)  \
        ((node)->__rb_parent_color == (unsigned long)(node))
 #define RB_CLEAR_NODE(node)  \
index 6925f5b42f890983220abd05939f74574f8d43c2..99048e501b88fb1224efb2a84e49afbcc583cffb 100644 (file)
@@ -55,12 +55,6 @@ struct kexec_segment {
        size_t memsz;
 };
 
-/* Load a new kernel image as described by the kexec_segment array
- * consisting of passed number of segments at the entry-point address.
- * The flags allow different useage types.
- */
-extern int kexec_load(void *, size_t, struct kexec_segment *,
-               unsigned long int);
 #endif /* __KERNEL__ */
 
 #endif /* _UAPILINUX_KEXEC_H */
index 6115146563f94e5bfab0973be730b3388fb3fc59..92842113c6a9dfff0ca026f6ec2ff1bc663b2f38 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1941,7 +1941,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
        queue.sleeper = current;
 
 sleep_again:
-       current->state = TASK_INTERRUPTIBLE;
+       __set_current_state(TASK_INTERRUPTIBLE);
        sem_unlock(sma, locknum);
        rcu_read_unlock();
 
index c85277639b34ff220618d973ec8b84df557434e2..38c25b1f2fd5c7e4922f36cf884519c1bd485a85 100644 (file)
@@ -444,7 +444,7 @@ arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
 }
 
 /*
- * Free up memory used by kernel, initrd, and comand line. This is temporary
+ * Free up memory used by kernel, initrd, and command line. This is temporary
  * memory allocation which is not needed any more after these buffers have
  * been loaded into separate segments and have been copied elsewhere.
  */
@@ -856,8 +856,6 @@ static int kimage_set_destination(struct kimage *image,
 
        destination &= PAGE_MASK;
        result = kimage_add_entry(image, destination | IND_DESTINATION);
-       if (result == 0)
-               image->destination = destination;
 
        return result;
 }
@@ -869,8 +867,6 @@ static int kimage_add_page(struct kimage *image, unsigned long page)
 
        page &= PAGE_MASK;
        result = kimage_add_entry(image, page | IND_SOURCE);
-       if (result == 0)
-               image->destination += PAGE_SIZE;
 
        return result;
 }
@@ -1288,19 +1284,22 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
        if (nr_segments > 0) {
                unsigned long i;
 
-               /* Loading another kernel to reboot into */
-               if ((flags & KEXEC_ON_CRASH) == 0)
-                       result = kimage_alloc_init(&image, entry, nr_segments,
-                                                  segments, flags);
-               /* Loading another kernel to switch to if this one crashes */
-               else if (flags & KEXEC_ON_CRASH) {
-                       /* Free any current crash dump kernel before
+               if (flags & KEXEC_ON_CRASH) {
+                       /*
+                        * Loading another kernel to switch to if this one
+                        * crashes.  Free any current crash dump kernel before
                         * we corrupt it.
                         */
+
                        kimage_free(xchg(&kexec_crash_image, NULL));
                        result = kimage_alloc_init(&image, entry, nr_segments,
                                                   segments, flags);
                        crash_map_reserved_pages();
+               } else {
+                       /* Loading another kernel to reboot into. */
+
+                       result = kimage_alloc_init(&image, entry, nr_segments,
+                                                  segments, flags);
                }
                if (result)
                        goto out;
index 8426ad48362c73f96e8031a7c9b0cd16eba1d426..b34813f725e970fa79b97e625fab6c568543aaf8 100644 (file)
@@ -3025,8 +3025,13 @@ static void do_free_init(struct rcu_head *head)
        kfree(m);
 }
 
-/* This is where the real work happens */
-static int do_init_module(struct module *mod)
+/*
+ * This is where the real work happens.
+ *
+ * Keep it uninlined to provide a reliable breakpoint target, e.g. for the gdb
+ * helper command 'lx-symbols'.
+ */
+static noinline int do_init_module(struct module *mod)
 {
        int ret = 0;
        struct mod_initfree *freeinit;
index 1eb9d90c3af926b3217a44b8355a10733a73bd7e..227fec36b12a7b2650a77fd58a9cdb5e18c3e8f1 100644 (file)
@@ -1077,7 +1077,6 @@ int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr,
 }
 
 #if defined CONFIG_COMPAT
-#include <linux/compat.h>
 
 int compat_ptrace_request(struct task_struct *child, compat_long_t request,
                          compat_ulong_t addr, compat_ulong_t data)
index 4ef9687ac115f21aae6ce4321e2639866892389d..4f44028943e663391fe35827c8c5acb4966b5101 100644 (file)
@@ -629,7 +629,9 @@ static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd)
 
        switch (action) {
        case SECCOMP_RET_ERRNO:
-               /* Set the low-order 16-bits as a errno. */
+               /* Set low-order bits as an errno, capped at MAX_ERRNO. */
+               if (data > MAX_ERRNO)
+                       data = MAX_ERRNO;
                syscall_set_return_value(current, task_pt_regs(current),
                                         -data, 0);
                goto skip;
index 33a52759cc0edfc62a2638a6608becee10d28694..a390499943e48e63e77f14d631f75505485e84cb 100644 (file)
@@ -3550,7 +3550,7 @@ SYSCALL_DEFINE2(signal, int, sig, __sighandler_t, handler)
 SYSCALL_DEFINE0(pause)
 {
        while (!signal_pending(current)) {
-               current->state = TASK_INTERRUPTIBLE;
+               __set_current_state(TASK_INTERRUPTIBLE);
                schedule();
        }
        return -ERESTARTNOHAND;
@@ -3563,7 +3563,7 @@ int sigsuspend(sigset_t *set)
        current->saved_sigmask = current->blocked;
        set_current_blocked(set);
 
-       current->state = TASK_INTERRUPTIBLE;
+       __set_current_state(TASK_INTERRUPTIBLE);
        schedule();
        set_restore_sigmask();
        return -ERESTARTNOHAND;
index ecb3516f6546431b1daf17ec77967b3a84416b12..c5cefb3c009ce9cd51199dc5fef683d7bc9b1bdc 100644 (file)
@@ -167,6 +167,17 @@ config DEBUG_INFO_DWARF4
          But it significantly improves the success of resolving
          variables in gdb on optimized code.
 
+config GDB_SCRIPTS
+       bool "Provide GDB scripts for kernel debugging"
+       depends on DEBUG_INFO
+       help
+         This creates the required links to GDB helper scripts in the
+         build directory. If you load vmlinux into gdb, the helper
+         scripts will be automatically imported by gdb as well, and
+         additional functions are available to analyze a Linux kernel
+         instance. See Documentation/gdb-kernel-debugging.txt for further
+         details.
+
 config ENABLE_WARN_DEPRECATED
        bool "Enable __deprecated logic"
        default y
index 8eb483aaec465efcc1f40c70a8c76d179eb094a2..e8b24f443709dd04a3df7c541e26075b12bb1048 100644 (file)
@@ -25,7 +25,9 @@
 
 int main(int argc, char **argv)
 {
-       struct bpf_labels l;
+       struct bpf_labels l = {
+               .count = 0,
+       };
        static const char msg1[] = "Please type something: ";
        static const char msg2[] = "You typed: ";
        char buf[256];
index 579cfe3318862f360cc45cd440db633e6c6f0664..05cb4d5ff9f5bef632baa98eb687f1781dcb5e5e 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "bpf-helper.h"
@@ -63,6 +64,11 @@ __u32 seccomp_bpf_label(struct bpf_labels *labels, const char *label)
 {
        struct __bpf_label *begin = labels->labels, *end;
        int id;
+
+       if (labels->count == BPF_LABELS_MAX) {
+               fprintf(stderr, "Too many labels\n");
+               exit(1);
+       }
        if (labels->count == 0) {
                begin->label = label;
                begin->location = 0xffffffff;
index 72902b5f27213696604f077bc8ad78e8f82d9bd0..2016a64497ab1cca3074a73a76057ff02947b3a0 100644 (file)
@@ -36,6 +36,7 @@ subdir-$(CONFIG_MODVERSIONS) += genksyms
 subdir-y                     += mod
 subdir-$(CONFIG_SECURITY_SELINUX) += selinux
 subdir-$(CONFIG_DTC)         += dtc
+subdir-$(CONFIG_GDB_SCRIPTS) += gdb
 
 # Let clean descend into subdirs
 subdir-        += basic kconfig package
diff --git a/scripts/gdb/Makefile b/scripts/gdb/Makefile
new file mode 100644 (file)
index 0000000..62f5f65
--- /dev/null
@@ -0,0 +1 @@
+subdir-y := linux
diff --git a/scripts/gdb/linux/.gitignore b/scripts/gdb/linux/.gitignore
new file mode 100644 (file)
index 0000000..52e4e61
--- /dev/null
@@ -0,0 +1,2 @@
+*.pyc
+*.pyo
diff --git a/scripts/gdb/linux/Makefile b/scripts/gdb/linux/Makefile
new file mode 100644 (file)
index 0000000..6cf1ecf
--- /dev/null
@@ -0,0 +1,11 @@
+always := gdb-scripts
+
+SRCTREE := $(shell cd $(srctree) && /bin/pwd)
+
+$(obj)/gdb-scripts:
+ifneq ($(KBUILD_SRC),)
+       $(Q)ln -fsn $(SRCTREE)/$(obj)/*.py $(objtree)/$(obj)
+endif
+       @:
+
+clean-files := *.pyc *.pyo $(if $(KBUILD_SRC),*.py)
diff --git a/scripts/gdb/linux/cpus.py b/scripts/gdb/linux/cpus.py
new file mode 100644 (file)
index 0000000..4297b83
--- /dev/null
@@ -0,0 +1,135 @@
+#
+# gdb helper commands and functions for Linux kernel debugging
+#
+#  per-cpu tools
+#
+# Copyright (c) Siemens AG, 2011-2013
+#
+# Authors:
+#  Jan Kiszka <jan.kiszka@siemens.com>
+#
+# This work is licensed under the terms of the GNU GPL version 2.
+#
+
+import gdb
+
+from linux import tasks, utils
+
+
+MAX_CPUS = 4096
+
+
+def get_current_cpu():
+    if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU:
+        return gdb.selected_thread().num - 1
+    elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB:
+        tid = gdb.selected_thread().ptid[2]
+        if tid > (0x100000000 - MAX_CPUS - 2):
+            return 0x100000000 - tid - 2
+        else:
+            return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu']
+    else:
+        raise gdb.GdbError("Sorry, obtaining the current CPU is not yet "
+                           "supported with this gdb server.")
+
+
+def per_cpu(var_ptr, cpu):
+    if cpu == -1:
+        cpu = get_current_cpu()
+    if utils.is_target_arch("sparc:v9"):
+        offset = gdb.parse_and_eval(
+            "trap_block[{0}].__per_cpu_base".format(str(cpu)))
+    else:
+        try:
+            offset = gdb.parse_and_eval(
+                "__per_cpu_offset[{0}]".format(str(cpu)))
+        except gdb.error:
+            # !CONFIG_SMP case
+            offset = 0
+    pointer = var_ptr.cast(utils.get_long_type()) + offset
+    return pointer.cast(var_ptr.type).dereference()
+
+
+cpu_mask = {}
+
+
+def cpu_mask_invalidate(event):
+    global cpu_mask
+    cpu_mask = {}
+    gdb.events.stop.disconnect(cpu_mask_invalidate)
+    if hasattr(gdb.events, 'new_objfile'):
+        gdb.events.new_objfile.disconnect(cpu_mask_invalidate)
+
+
+def cpu_list(mask_name):
+    global cpu_mask
+    mask = None
+    if mask_name in cpu_mask:
+        mask = cpu_mask[mask_name]
+    if mask is None:
+        mask = gdb.parse_and_eval(mask_name + ".bits")
+        if hasattr(gdb, 'events'):
+            cpu_mask[mask_name] = mask
+            gdb.events.stop.connect(cpu_mask_invalidate)
+            if hasattr(gdb.events, 'new_objfile'):
+                gdb.events.new_objfile.connect(cpu_mask_invalidate)
+    bits_per_entry = mask[0].type.sizeof * 8
+    num_entries = mask.type.sizeof * 8 / bits_per_entry
+    entry = -1
+    bits = 0
+
+    while True:
+        while bits == 0:
+            entry += 1
+            if entry == num_entries:
+                return
+            bits = mask[entry]
+            if bits != 0:
+                bit = 0
+                break
+
+        while bits & 1 == 0:
+            bits >>= 1
+            bit += 1
+
+        cpu = entry * bits_per_entry + bit
+
+        bits >>= 1
+        bit += 1
+
+        yield cpu
+
+
+class PerCpu(gdb.Function):
+    """Return per-cpu variable.
+
+$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the
+given CPU number. If CPU is omitted, the CPU of the current context is used.
+Note that VAR has to be quoted as string."""
+
+    def __init__(self):
+        super(PerCpu, self).__init__("lx_per_cpu")
+
+    def invoke(self, var_name, cpu=-1):
+        var_ptr = gdb.parse_and_eval("&" + var_name.string())
+        return per_cpu(var_ptr, cpu)
+
+
+PerCpu()
+
+
+class LxCurrentFunc(gdb.Function):
+    """Return current task.
+
+$lx_current([CPU]): Return the per-cpu task variable for the given CPU
+number. If CPU is omitted, the CPU of the current context is used."""
+
+    def __init__(self):
+        super(LxCurrentFunc, self).__init__("lx_current")
+
+    def invoke(self, cpu=-1):
+        var_ptr = gdb.parse_and_eval("&current_task")
+        return per_cpu(var_ptr, cpu).dereference()
+
+
+LxCurrentFunc()
diff --git a/scripts/gdb/linux/dmesg.py b/scripts/gdb/linux/dmesg.py
new file mode 100644 (file)
index 0000000..3c947f0
--- /dev/null
@@ -0,0 +1,65 @@
+#
+# gdb helper commands and functions for Linux kernel debugging
+#
+#  kernel log buffer dump
+#
+# Copyright (c) Siemens AG, 2011, 2012
+#
+# Authors:
+#  Jan Kiszka <jan.kiszka@siemens.com>
+#
+# This work is licensed under the terms of the GNU GPL version 2.
+#
+
+import gdb
+import string
+
+from linux import utils
+
+
+class LxDmesg(gdb.Command):
+    """Print Linux kernel log buffer."""
+
+    def __init__(self):
+        super(LxDmesg, self).__init__("lx-dmesg", gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        log_buf_addr = int(str(gdb.parse_and_eval("log_buf")).split()[0], 16)
+        log_first_idx = int(gdb.parse_and_eval("log_first_idx"))
+        log_next_idx = int(gdb.parse_and_eval("log_next_idx"))
+        log_buf_len = int(gdb.parse_and_eval("log_buf_len"))
+
+        inf = gdb.inferiors()[0]
+        start = log_buf_addr + log_first_idx
+        if log_first_idx < log_next_idx:
+            log_buf_2nd_half = -1
+            length = log_next_idx - log_first_idx
+            log_buf = inf.read_memory(start, length)
+        else:
+            log_buf_2nd_half = log_buf_len - log_first_idx
+            log_buf = inf.read_memory(start, log_buf_2nd_half) + \
+                inf.read_memory(log_buf_addr, log_next_idx)
+
+        pos = 0
+        while pos < log_buf.__len__():
+            length = utils.read_u16(log_buf[pos + 8:pos + 10])
+            if length == 0:
+                if log_buf_2nd_half == -1:
+                    gdb.write("Corrupted log buffer!\n")
+                    break
+                pos = log_buf_2nd_half
+                continue
+
+            text_len = utils.read_u16(log_buf[pos + 10:pos + 12])
+            text = log_buf[pos + 16:pos + 16 + text_len]
+            time_stamp = utils.read_u64(log_buf[pos:pos + 8])
+
+            for line in memoryview(text).tobytes().splitlines():
+                gdb.write("[{time:12.6f}] {line}\n".format(
+                    time=time_stamp / 1000000000.0,
+                    line=line))
+
+            pos += length
+
+
+LxDmesg()
diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py
new file mode 100644 (file)
index 0000000..a1504c4
--- /dev/null
@@ -0,0 +1,103 @@
+#
+# gdb helper commands and functions for Linux kernel debugging
+#
+#  module tools
+#
+# Copyright (c) Siemens AG, 2013
+#
+# Authors:
+#  Jan Kiszka <jan.kiszka@siemens.com>
+#
+# This work is licensed under the terms of the GNU GPL version 2.
+#
+
+import gdb
+
+from linux import cpus, utils
+
+
+module_type = utils.CachedType("struct module")
+
+
+def module_list():
+    global module_type
+    module_ptr_type = module_type.get_type().pointer()
+    modules = gdb.parse_and_eval("modules")
+    entry = modules['next']
+    end_of_list = modules.address
+
+    while entry != end_of_list:
+        yield utils.container_of(entry, module_ptr_type, "list")
+        entry = entry['next']
+
+
+def find_module_by_name(name):
+    for module in module_list():
+        if module['name'].string() == name:
+            return module
+    return None
+
+
+class LxModule(gdb.Function):
+    """Find module by name and return the module variable.
+
+$lx_module("MODULE"): Given the name MODULE, iterate over all loaded modules
+of the target and return that module variable which MODULE matches."""
+
+    def __init__(self):
+        super(LxModule, self).__init__("lx_module")
+
+    def invoke(self, mod_name):
+        mod_name = mod_name.string()
+        module = find_module_by_name(mod_name)
+        if module:
+            return module.dereference()
+        else:
+            raise gdb.GdbError("Unable to find MODULE " + mod_name)
+
+
+LxModule()
+
+
+class LxLsmod(gdb.Command):
+    """List currently loaded modules."""
+
+    _module_use_type = utils.CachedType("struct module_use")
+
+    def __init__(self):
+        super(LxLsmod, self).__init__("lx-lsmod", gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        gdb.write(
+            "Address{0}    Module                  Size  Used by\n".format(
+                "        " if utils.get_long_type().sizeof == 8 else ""))
+
+        for module in module_list():
+            ref = 0
+            module_refptr = module['refptr']
+            for cpu in cpus.cpu_list("cpu_possible_mask"):
+                refptr = cpus.per_cpu(module_refptr, cpu)
+                ref += refptr['incs']
+                ref -= refptr['decs']
+
+            gdb.write("{address} {name:<19} {size:>8}  {ref}".format(
+                address=str(module['module_core']).split()[0],
+                name=module['name'].string(),
+                size=str(module['core_size']),
+                ref=str(ref)))
+
+            source_list = module['source_list']
+            t = self._module_use_type.get_type().pointer()
+            entry = source_list['next']
+            first = True
+            while entry != source_list.address:
+                use = utils.container_of(entry, t, "source_list")
+                gdb.write("{separator}{name}".format(
+                    separator=" " if first else ",",
+                    name=use['source']['name'].string()))
+                first = False
+                entry = entry['next']
+            gdb.write("\n")
+
+
+LxLsmod()
diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py
new file mode 100644 (file)
index 0000000..cd5bea9
--- /dev/null
@@ -0,0 +1,177 @@
+#
+# gdb helper commands and functions for Linux kernel debugging
+#
+#  load kernel and module symbols
+#
+# Copyright (c) Siemens AG, 2011-2013
+#
+# Authors:
+#  Jan Kiszka <jan.kiszka@siemens.com>
+#
+# This work is licensed under the terms of the GNU GPL version 2.
+#
+
+import gdb
+import os
+import re
+import string
+
+from linux import modules, utils
+
+
+if hasattr(gdb, 'Breakpoint'):
+    class LoadModuleBreakpoint(gdb.Breakpoint):
+        def __init__(self, spec, gdb_command):
+            super(LoadModuleBreakpoint, self).__init__(spec, internal=True)
+            self.silent = True
+            self.gdb_command = gdb_command
+
+        def stop(self):
+            module = gdb.parse_and_eval("mod")
+            module_name = module['name'].string()
+            cmd = self.gdb_command
+
+            # enforce update if object file is not found
+            cmd.module_files_updated = False
+
+            # Disable pagination while reporting symbol (re-)loading.
+            # The console input is blocked in this context so that we would
+            # get stuck waiting for the user to acknowledge paged output.
+            show_pagination = gdb.execute("show pagination", to_string=True)
+            pagination = show_pagination.endswith("on.\n")
+            gdb.execute("set pagination off")
+
+            if module_name in cmd.loaded_modules:
+                gdb.write("refreshing all symbols to reload module "
+                          "'{0}'\n".format(module_name))
+                cmd.load_all_symbols()
+            else:
+                cmd.load_module_symbols(module)
+
+            # restore pagination state
+            gdb.execute("set pagination %s" % ("on" if pagination else "off"))
+
+            return False
+
+
+class LxSymbols(gdb.Command):
+    """(Re-)load symbols of Linux kernel and currently loaded modules.
+
+The kernel (vmlinux) is taken from the current working directly. Modules (.ko)
+are scanned recursively, starting in the same directory. Optionally, the module
+search path can be extended by a space separated list of paths passed to the
+lx-symbols command."""
+
+    module_paths = []
+    module_files = []
+    module_files_updated = False
+    loaded_modules = []
+    breakpoint = None
+
+    def __init__(self):
+        super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
+                                        gdb.COMPLETE_FILENAME)
+
+    def _update_module_files(self):
+        self.module_files = []
+        for path in self.module_paths:
+            gdb.write("scanning for modules in {0}\n".format(path))
+            for root, dirs, files in os.walk(path):
+                for name in files:
+                    if name.endswith(".ko"):
+                        self.module_files.append(root + "/" + name)
+        self.module_files_updated = True
+
+    def _get_module_file(self, module_name):
+        module_pattern = ".*/{0}\.ko$".format(
+            module_name.replace("_", r"[_\-]"))
+        for name in self.module_files:
+            if re.match(module_pattern, name) and os.path.exists(name):
+                return name
+        return None
+
+    def _section_arguments(self, module):
+        try:
+            sect_attrs = module['sect_attrs'].dereference()
+        except gdb.error:
+            return ""
+        attrs = sect_attrs['attrs']
+        section_name_to_address = {
+            attrs[n]['name'].string() : attrs[n]['address']
+            for n in range(int(sect_attrs['nsections']))}
+        args = []
+        for section_name in [".data", ".data..read_mostly", ".rodata", ".bss"]:
+            address = section_name_to_address.get(section_name)
+            if address:
+                args.append(" -s {name} {addr}".format(
+                    name=section_name, addr=str(address)))
+        return "".join(args)
+
+    def load_module_symbols(self, module):
+        module_name = module['name'].string()
+        module_addr = str(module['module_core']).split()[0]
+
+        module_file = self._get_module_file(module_name)
+        if not module_file and not self.module_files_updated:
+            self._update_module_files()
+            module_file = self._get_module_file(module_name)
+
+        if module_file:
+            gdb.write("loading @{addr}: {filename}\n".format(
+                addr=module_addr, filename=module_file))
+            cmdline = "add-symbol-file {filename} {addr}{sections}".format(
+                filename=module_file,
+                addr=module_addr,
+                sections=self._section_arguments(module))
+            gdb.execute(cmdline, to_string=True)
+            if not module_name in self.loaded_modules:
+                self.loaded_modules.append(module_name)
+        else:
+            gdb.write("no module object found for '{0}'\n".format(module_name))
+
+    def load_all_symbols(self):
+        gdb.write("loading vmlinux\n")
+
+        # Dropping symbols will disable all breakpoints. So save their states
+        # and restore them afterward.
+        saved_states = []
+        if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None:
+            for bp in gdb.breakpoints():
+                saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
+
+        # drop all current symbols and reload vmlinux
+        gdb.execute("symbol-file", to_string=True)
+        gdb.execute("symbol-file vmlinux")
+
+        self.loaded_modules = []
+        module_list = modules.module_list()
+        if not module_list:
+            gdb.write("no modules found\n")
+        else:
+            [self.load_module_symbols(module) for module in module_list]
+
+        for saved_state in saved_states:
+            saved_state['breakpoint'].enabled = saved_state['enabled']
+
+    def invoke(self, arg, from_tty):
+        self.module_paths = arg.split()
+        self.module_paths.append(os.getcwd())
+
+        # enforce update
+        self.module_files = []
+        self.module_files_updated = False
+
+        self.load_all_symbols()
+
+        if hasattr(gdb, 'Breakpoint'):
+            if not self.breakpoint is None:
+                self.breakpoint.delete()
+                self.breakpoint = None
+            self.breakpoint = LoadModuleBreakpoint(
+                "kernel/module.c:do_init_module", self)
+        else:
+            gdb.write("Note: symbol update on module loading not supported "
+                      "with this gdb version\n")
+
+
+LxSymbols()
diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py
new file mode 100644 (file)
index 0000000..e2037d9
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# gdb helper commands and functions for Linux kernel debugging
+#
+#  task & thread tools
+#
+# Copyright (c) Siemens AG, 2011-2013
+#
+# Authors:
+#  Jan Kiszka <jan.kiszka@siemens.com>
+#
+# This work is licensed under the terms of the GNU GPL version 2.
+#
+
+import gdb
+
+from linux import utils
+
+
+task_type = utils.CachedType("struct task_struct")
+
+def task_lists():
+    global task_type
+    task_ptr_type = task_type.get_type().pointer()
+    init_task = gdb.parse_and_eval("init_task").address
+    t = g = init_task
+
+    while True:
+        while True:
+            yield t
+
+            t = utils.container_of(t['thread_group']['next'],
+                                   task_ptr_type, "thread_group")
+            if t == g:
+                break
+
+        t = g = utils.container_of(g['tasks']['next'],
+                                   task_ptr_type, "tasks")
+        if t == init_task:
+            return
+
+def get_task_by_pid(pid):
+    for task in task_lists():
+        if int(task['pid']) == pid:
+            return task
+    return None
+
+
+class LxTaskByPidFunc(gdb.Function):
+    """Find Linux task by PID and return the task_struct variable.
+
+$lx_task_by_pid(PID): Given PID, iterate over all tasks of the target and
+return that task_struct variable which PID matches."""
+
+    def __init__(self):
+        super(LxTaskByPidFunc, self).__init__("lx_task_by_pid")
+
+    def invoke(self, pid):
+        task = get_task_by_pid(pid)
+        if task:
+            return task.dereference()
+        else:
+            raise gdb.GdbError("No task of PID " + str(pid))
+
+
+LxTaskByPidFunc()
+
+
+thread_info_type = utils.CachedType("struct thread_info")
+
+ia64_task_size = None
+
+
+def get_thread_info(task):
+    global thread_info_type
+    thread_info_ptr_type = thread_info_type.get_type().pointer()
+    if utils.is_target_arch("ia64"):
+        global ia64_task_size
+        if ia64_task_size is None:
+            ia64_task_size = gdb.parse_and_eval("sizeof(struct task_struct)")
+        thread_info_addr = task.address + ia64_task_size
+        thread_info = thread_info_addr.cast(thread_info_ptr_type)
+    else:
+        thread_info = task['stack'].cast(thread_info_ptr_type)
+    return thread_info.dereference()
+
+
+class LxThreadInfoFunc (gdb.Function):
+    """Calculate Linux thread_info from task variable.
+
+$lx_thread_info(TASK): Given TASK, return the corresponding thread_info
+variable."""
+
+    def __init__(self):
+        super(LxThreadInfoFunc, self).__init__("lx_thread_info")
+
+    def invoke(self, task):
+        return get_thread_info(task)
+
+
+LxThreadInfoFunc()
diff --git a/scripts/gdb/linux/utils.py b/scripts/gdb/linux/utils.py
new file mode 100644 (file)
index 0000000..128c306
--- /dev/null
@@ -0,0 +1,156 @@
+#
+# gdb helper commands and functions for Linux kernel debugging
+#
+#  common utilities
+#
+# Copyright (c) Siemens AG, 2011-2013
+#
+# Authors:
+#  Jan Kiszka <jan.kiszka@siemens.com>
+#
+# This work is licensed under the terms of the GNU GPL version 2.
+#
+
+import gdb
+
+
+class CachedType:
+    def __init__(self, name):
+        self._type = None
+        self._name = name
+
+    def _new_objfile_handler(self, event):
+        self._type = None
+        gdb.events.new_objfile.disconnect(self._new_objfile_handler)
+
+    def get_type(self):
+        if self._type is None:
+            self._type = gdb.lookup_type(self._name)
+            if self._type is None:
+                raise gdb.GdbError(
+                    "cannot resolve type '{0}'".format(self._name))
+            if hasattr(gdb, 'events') and hasattr(gdb.events, 'new_objfile'):
+                gdb.events.new_objfile.connect(self._new_objfile_handler)
+        return self._type
+
+
+long_type = CachedType("long")
+
+
+def get_long_type():
+    global long_type
+    return long_type.get_type()
+
+
+def offset_of(typeobj, field):
+    element = gdb.Value(0).cast(typeobj)
+    return int(str(element[field].address).split()[0], 16)
+
+
+def container_of(ptr, typeobj, member):
+    return (ptr.cast(get_long_type()) -
+            offset_of(typeobj, member)).cast(typeobj)
+
+
+class ContainerOf(gdb.Function):
+    """Return pointer to containing data structure.
+
+$container_of(PTR, "TYPE", "ELEMENT"): Given PTR, return a pointer to the
+data structure of the type TYPE in which PTR is the address of ELEMENT.
+Note that TYPE and ELEMENT have to be quoted as strings."""
+
+    def __init__(self):
+        super(ContainerOf, self).__init__("container_of")
+
+    def invoke(self, ptr, typename, elementname):
+        return container_of(ptr, gdb.lookup_type(typename.string()).pointer(),
+                            elementname.string())
+
+ContainerOf()
+
+
+BIG_ENDIAN = 0
+LITTLE_ENDIAN = 1
+target_endianness = None
+
+
+def get_target_endianness():
+    global target_endianness
+    if target_endianness is None:
+        endian = gdb.execute("show endian", to_string=True)
+        if "little endian" in endian:
+            target_endianness = LITTLE_ENDIAN
+        elif "big endian" in endian:
+            target_endianness = BIG_ENDIAN
+        else:
+            raise gdb.GdgError("unknown endianness '{0}'".format(str(endian)))
+    return target_endianness
+
+
+def read_u16(buffer):
+    if get_target_endianness() == LITTLE_ENDIAN:
+        return ord(buffer[0]) + (ord(buffer[1]) << 8)
+    else:
+        return ord(buffer[1]) + (ord(buffer[0]) << 8)
+
+
+def read_u32(buffer):
+    if get_target_endianness() == LITTLE_ENDIAN:
+        return read_u16(buffer[0:2]) + (read_u16(buffer[2:4]) << 16)
+    else:
+        return read_u16(buffer[2:4]) + (read_u16(buffer[0:2]) << 16)
+
+
+def read_u64(buffer):
+    if get_target_endianness() == LITTLE_ENDIAN:
+        return read_u32(buffer[0:4]) + (read_u32(buffer[4:8]) << 32)
+    else:
+        return read_u32(buffer[4:8]) + (read_u32(buffer[0:4]) << 32)
+
+
+target_arch = None
+
+
+def is_target_arch(arch):
+    if hasattr(gdb.Frame, 'architecture'):
+        return arch in gdb.newest_frame().architecture().name()
+    else:
+        global target_arch
+        if target_arch is None:
+            target_arch = gdb.execute("show architecture", to_string=True)
+        return arch in target_arch
+
+
+GDBSERVER_QEMU = 0
+GDBSERVER_KGDB = 1
+gdbserver_type = None
+
+
+def get_gdbserver_type():
+    def exit_handler(event):
+        global gdbserver_type
+        gdbserver_type = None
+        gdb.events.exited.disconnect(exit_handler)
+
+    def probe_qemu():
+        try:
+            return gdb.execute("monitor info version", to_string=True) != ""
+        except:
+            return False
+
+    def probe_kgdb():
+        try:
+            thread_info = gdb.execute("info thread 2", to_string=True)
+            return "shadowCPU0" in thread_info
+        except:
+            return False
+
+    global gdbserver_type
+    if gdbserver_type is None:
+        if probe_qemu():
+            gdbserver_type = GDBSERVER_QEMU
+        elif probe_kgdb():
+            gdbserver_type = GDBSERVER_KGDB
+        if not gdbserver_type is None and hasattr(gdb, 'events'):
+            gdb.events.exited.connect(exit_handler)
+    return gdbserver_type
diff --git a/scripts/gdb/vmlinux-gdb.py b/scripts/gdb/vmlinux-gdb.py
new file mode 100644 (file)
index 0000000..4848928
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# gdb helper commands and functions for Linux kernel debugging
+#
+#  loader module
+#
+# Copyright (c) Siemens AG, 2012, 2013
+#
+# Authors:
+#  Jan Kiszka <jan.kiszka@siemens.com>
+#
+# This work is licensed under the terms of the GNU GPL version 2.
+#
+
+import os
+
+sys.path.insert(0, os.path.dirname(__file__) + "/scripts/gdb")
+
+try:
+    gdb.parse_and_eval("0")
+    gdb.execute("", to_string=True)
+except:
+    gdb.write("NOTE: gdb 7.2 or later required for Linux helper scripts to "
+              "work.\n")
+else:
+    import linux.utils
+    import linux.symbols
+    import linux.modules
+    import linux.dmesg
+    import linux.tasks
+    import linux.cpus