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 ...
Unified · Split
| @@ -43,6 +43,7 @@ Module.symvers · 42 unmodified lines | ||
| 43 | 43 | /TAGS |
| 44 | 44 | /linux |
| 45 | 45 | /vmlinux |
| 46 | +/vmlinux-gdb.py | |
| 46 | 47 | /vmlinuz |
| 47 | 48 | /System.map |
| 48 | 49 | /Module.markers |
| @@ -0,0 +1,160 @@ | ||
| 1 | +Debugging kernel and modules via gdb | |
| 2 | +==================================== | |
| 3 | + | |
| 4 | +The kernel debugger kgdb, hypervisors like QEMU or JTAG-based hardware | |
| 5 | +interfaces allow to debug the Linux kernel and its modules during runtime | |
| 6 | +using gdb. Gdb comes with a powerful scripting interface for python. The | |
| 7 | +kernel provides a collection of helper scripts that can simplify typical | |
| 8 | +kernel debugging steps. This is a short tutorial about how to enable and use | |
| 9 | +them. It focuses on QEMU/KVM virtual machines as target, but the examples can | |
| 10 | +be transferred to the other gdb stubs as well. | |
| 11 | + | |
| 12 | + | |
| 13 | +Requirements | |
| 14 | +------------ | |
| 15 | + | |
| 16 | + o gdb 7.2+ (recommended: 7.4+) with python support enabled (typically true | |
| 17 | + for distributions) | |
| 18 | + | |
| 19 | + | |
| 20 | +Setup | |
| 21 | +----- | |
| 22 | + | |
| 23 | + o Create a virtual Linux machine for QEMU/KVM (see www.linux-kvm.org and | |
| 24 | + www.qemu.org for more details). For cross-development, | |
| 25 | + http://landley.net/aboriginal/bin keeps a pool of machine images and | |
| 26 | + toolchains that can be helpful to start from. | |
| 27 | + | |
| 28 | + o Build the kernel with CONFIG_GDB_SCRIPTS enabled, but leave | |
| 29 | + CONFIG_DEBUG_INFO_REDUCED off. If your architecture supports | |
| 30 | + CONFIG_FRAME_POINTER, keep it enabled. | |
| 31 | + | |
| 32 | + o Install that kernel on the guest. | |
| 33 | + | |
| 34 | + Alternatively, QEMU allows to boot the kernel directly using -kernel, | |
| 35 | + -append, -initrd command line switches. This is generally only useful if | |
| 36 | + you do not depend on modules. See QEMU documentation for more details on | |
| 37 | + this mode. | |
| 38 | + | |
| 39 | + o Enable the gdb stub of QEMU/KVM, either | |
| 40 | + - at VM startup time by appending "-s" to the QEMU command line | |
| 41 | + or | |
| 42 | + - during runtime by issuing "gdbserver" from the QEMU monitor | |
| 43 | + console | |
| 44 | + | |
| 45 | + o cd /path/to/linux-build | |
| 46 | + | |
| 47 | + o Start gdb: gdb vmlinux | |
| 48 | + | |
| 49 | + Note: Some distros may restrict auto-loading of gdb scripts to known safe | |
| 50 | + directories. In case gdb reports to refuse loading vmlinux-gdb.py, add | |
| 51 | + | |
| 52 | + add-auto-load-safe-path /path/to/linux-build | |
| 53 | + | |
| 54 | + to ~/.gdbinit. See gdb help for more details. | |
| 55 | + | |
| 56 | + o Attach to the booted guest: | |
| 57 | + (gdb) target remote :1234 | |
| 58 | + | |
| 59 | + | |
| 60 | +Examples of using the Linux-provided gdb helpers | |
| 61 | +------------------------------------------------ | |
| 62 | + | |
| 63 | + o Load module (and main kernel) symbols: | |
| 64 | + (gdb) lx-symbols | |
| 65 | + loading vmlinux | |
| 66 | + scanning for modules in /home/user/linux/build | |
| 67 | + loading @0xffffffffa0020000: /home/user/linux/build/net/netfilter/xt_tcpudp.ko | |
| 68 | + loading @0xffffffffa0016000: /home/user/linux/build/net/netfilter/xt_pkttype.ko | |
| 69 | + loading @0xffffffffa0002000: /home/user/linux/build/net/netfilter/xt_limit.ko | |
| 70 | + loading @0xffffffffa00ca000: /home/user/linux/build/net/packet/af_packet.ko | |
| 71 | + loading @0xffffffffa003c000: /home/user/linux/build/fs/fuse/fuse.ko | |
| 72 | + ... | |
| 73 | + loading @0xffffffffa0000000: /home/user/linux/build/drivers/ata/ata_generic.ko | |
| 74 | + | |
| 75 | + o Set a breakpoint on some not yet loaded module function, e.g.: | |
| 76 | + (gdb) b btrfs_init_sysfs | |
| 77 | + Function "btrfs_init_sysfs" not defined. | |
| 78 | + Make breakpoint pending on future shared library load? (y or [n]) y | |
| 79 | + Breakpoint 1 (btrfs_init_sysfs) pending. | |
| 80 | + | |
| 81 | + o Continue the target | |
| 82 | + (gdb) c | |
| 83 | + | |
| 84 | + o Load the module on the target and watch the symbols being loaded as well as | |
| 85 | + the breakpoint hit: | |
| 86 | + loading @0xffffffffa0034000: /home/user/linux/build/lib/libcrc32c.ko | |
| 87 | + loading @0xffffffffa0050000: /home/user/linux/build/lib/lzo/lzo_compress.ko | |
| 88 | + loading @0xffffffffa006e000: /home/user/linux/build/lib/zlib_deflate/zlib_deflate.ko | |
| 89 | + loading @0xffffffffa01b1000: /home/user/linux/build/fs/btrfs/btrfs.ko | |
| 90 | + | |
| 91 | + Breakpoint 1, btrfs_init_sysfs () at /home/user/linux/fs/btrfs/sysfs.c:36 | |
| 92 | + 36 btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj); | |
| 93 | + | |
| 94 | + o Dump the log buffer of the target kernel: | |
| 95 | + (gdb) lx-dmesg | |
| 96 | + [ 0.000000] Initializing cgroup subsys cpuset | |
| 97 | + [ 0.000000] Initializing cgroup subsys cpu | |
| 98 | + [ 0.000000] Linux version 3.8.0-rc4-dbg+ (... | |
| 99 | + [ 0.000000] Command line: root=/dev/sda2 resume=/dev/sda1 vga=0x314 | |
| 100 | + [ 0.000000] e820: BIOS-provided physical RAM map: | |
| 101 | + [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable | |
| 102 | + [ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved | |
| 103 | + .... | |
| 104 | + | |
| 105 | + o Examine fields of the current task struct: | |
| 106 | + (gdb) p $lx_current().pid | |
| 107 | + $1 = 4998 | |
| 108 | + (gdb) p $lx_current().comm | |
| 109 | + $2 = "modprobe\000\000\000\000\000\000\000" | |
| 110 | + | |
| 111 | + o Make use of the per-cpu function for the current or a specified CPU: | |
| 112 | + (gdb) p $lx_per_cpu("runqueues").nr_running | |
| 113 | + $3 = 1 | |
| 114 | + (gdb) p $lx_per_cpu("runqueues", 2).nr_running | |
| 115 | + $4 = 0 | |
| 116 | + | |
| 117 | + o Dig into hrtimers using the container_of helper: | |
| 118 | + (gdb) set $next = $lx_per_cpu("hrtimer_bases").clock_base[0].active.next | |
| 119 | + (gdb) p *$container_of($next, "struct hrtimer", "node") | |
| 120 | + $5 = { | |
| 121 | + node = { | |
| 122 | + node = { | |
| 123 | + __rb_parent_color = 18446612133355256072, | |
| 124 | + rb_right = 0x0 <irq_stack_union>, | |
| 125 | + rb_left = 0x0 <irq_stack_union> | |
| 126 | + }, | |
| 127 | + expires = { | |
| 128 | + tv64 = 1835268000000 | |
| 129 | + } | |
| 130 | + }, | |
| 131 | + _softexpires = { | |
| 132 | + tv64 = 1835268000000 | |
| 133 | + }, | |
| 134 | + function = 0xffffffff81078232 <tick_sched_timer>, | |
| 135 | + base = 0xffff88003fd0d6f0, | |
| 136 | + state = 1, | |
| 137 | + start_pid = 0, | |
| 138 | + start_site = 0xffffffff81055c1f <hrtimer_start_range_ns+20>, | |
| 139 | + start_comm = "swapper/2\000\000\000\000\000\000" | |
| 140 | + } | |
| 141 | + | |
| 142 | + | |
| 143 | +List of commands and functions | |
| 144 | +------------------------------ | |
| 145 | + | |
| 146 | +The number of commands and convenience functions may evolve over the time, | |
| 147 | +this is just a snapshot of the initial version: | |
| 148 | + | |
| 149 | + (gdb) apropos lx | |
| 150 | + function lx_current -- Return current task | |
| 151 | + function lx_module -- Find module by name and return the module variable | |
| 152 | + function lx_per_cpu -- Return per-cpu variable | |
| 153 | + function lx_task_by_pid -- Find Linux task by PID and return the task_struct variable | |
| 154 | + function lx_thread_info -- Calculate Linux thread_info from task variable | |
| 155 | + lx-dmesg -- Print Linux kernel log buffer | |
| 156 | + lx-lsmod -- List currently loaded modules | |
| 157 | + lx-symbols -- (Re-)load symbols of Linux kernel and currently loaded modules | |
| 158 | + | |
| 159 | +Detailed help can be obtained via "help <command-name>" for commands and "help | |
| 160 | +function <function-name>" for convenience functions. | |
| @@ -4232,6 +4232,11 @@ W: http://www.icp-vortex.com/ · 4231 unmodified lines | ||
| 4232 | 4232 | S: Supported |
| 4233 | 4233 | F: drivers/scsi/gdt* |
| 4234 | 4234 | |
| 4235 | +GDB KERNEL DEBUGGING HELPER SCRIPTS | |
| 4236 | +M: Jan Kiszka <jan.kiszka@siemens.com> | |
| 4237 | +S: Supported | |
| 4238 | +F: scripts/gdb/ | |
| 4239 | + | |
| 4235 | 4240 | GEMTEK FM RADIO RECEIVER DRIVER |
| 4236 | 4241 | M: Hans Verkuil <hverkuil@xs4all.nl> |
| 4237 | 4242 | L: linux-media@vger.kernel.org |
| @@ -926,6 +926,9 @@ ifdef CONFIG_SAMPLES · 925 unmodified lines | ||
| 926 | 926 | endif |
| 927 | 927 | ifdef CONFIG_BUILD_DOCSRC |
| 928 | 928 | $(Q)$(MAKE) $(build)=Documentation |
| 929 | +endif | |
| 930 | +ifdef CONFIG_GDB_SCRIPTS | |
| 931 | + $(Q)ln -fsn `cd $(srctree) && /bin/pwd`/scripts/gdb/vmlinux-gdb.py | |
| 929 | 932 | endif |
| 930 | 933 | +$(call if_changed,link-vmlinux) |
| 931 | 934 | |
| @@ -1181,7 +1184,7 @@ MRPROPER_FILES += .config .config.old .version .old_version $(version_h) \ · 249 unmodified lines | ||
| 1181 | 1184 | Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \ |
| 1182 | 1185 | signing_key.priv signing_key.x509 x509.genkey \ |
| 1183 | 1186 | extra_certificates signing_key.x509.keyid \ |
| 1184 | − signing_key.x509.signer | |
| 1187 | + signing_key.x509.signer vmlinux-gdb.py | |
| 1185 | 1188 | |
| 1186 | 1189 | # clean - Delete most, but leave enough to build external modules |
| 1187 | 1190 | # |
| @@ -96,8 +96,6 @@ int default_machine_kexec_prepare(struct kimage *image) · 95 unmodified lines | ||
| 96 | 96 | return 0; |
| 97 | 97 | } |
| 98 | 98 | |
| 99 | −#define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE) | |
| 100 | − | |
| 101 | 99 | static void copy_segments(unsigned long ind) |
| 102 | 100 | { |
| 103 | 101 | unsigned long entry; |
| @@ -30,6 +30,8 @@ · 29 unmodified lines | ||
| 30 | 30 | #define AFFS_AC_SIZE (AFFS_CACHE_SIZE/sizeof(struct affs_ext_key)/2) |
| 31 | 31 | #define AFFS_AC_MASK (AFFS_AC_SIZE-1) |
| 32 | 32 | |
| 33 | +#define AFFSNAMEMAX 30U | |
| 34 | + | |
| 33 | 35 | struct affs_ext_key { |
| 34 | 36 | u32 ext; /* idx of the extended block */ |
| 35 | 37 | u32 key; /* block number */ |
| @@ -30,7 +30,7 @@ affs_insert_hash(struct inode *dir, struct buffer_head *bh) · 29 unmodified lines | ||
| 30 | 30 | ino = bh->b_blocknr; |
| 31 | 31 | offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]); |
| 32 | 32 | |
| 33 | − pr_debug("%s(dir=%u, ino=%d)\n", __func__, (u32)dir->i_ino, ino); | |
| 33 | + pr_debug("%s(dir=%lu, ino=%d)\n", __func__, dir->i_ino, ino); | |
| 34 | 34 | |
| 35 | 35 | dir_bh = affs_bread(sb, dir->i_ino); |
| 36 | 36 | if (!dir_bh) |
| @@ -80,8 +80,8 @@ affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh) · 43 unmodified lines | ||
| 80 | 80 | sb = dir->i_sb; |
| 81 | 81 | rem_ino = rem_bh->b_blocknr; |
| 82 | 82 | offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]); |
| 83 | − pr_debug("%s(dir=%d, ino=%d, hashval=%d)\n", | |
| 84 | − __func__, (u32)dir->i_ino, rem_ino, offset); | |
| 83 | + pr_debug("%s(dir=%lu, ino=%d, hashval=%d)\n", __func__, dir->i_ino, | |
| 84 | + rem_ino, offset); | |
| 85 | 85 | |
| 86 | 86 | bh = affs_bread(sb, dir->i_ino); |
| 87 | 87 | if (!bh) |
| @@ -483,11 +483,10 @@ affs_check_name(const unsigned char *name, int len, bool notruncate) · 395 unmodified lines | ||
| 483 | 483 | { |
| 484 | 484 | int i; |
| 485 | 485 | |
| 486 | − if (len > 30) { | |
| 486 | + if (len > AFFSNAMEMAX) { | |
| 487 | 487 | if (notruncate) |
| 488 | 488 | return -ENAMETOOLONG; |
| 489 | − else | |
| 490 | − len = 30; | |
| 489 | + len = AFFSNAMEMAX; | |
| 491 | 490 | } |
| 492 | 491 | for (i = 0; i < len; i++) { |
| 493 | 492 | if (name[i] < ' ' || name[i] == ':' |
| @@ -508,7 +507,7 @@ affs_check_name(const unsigned char *name, int len, bool notruncate) · 14 unmodified lines | ||
| 508 | 507 | int |
| 509 | 508 | affs_copy_name(unsigned char *bstr, struct dentry *dentry) |
| 510 | 509 | { |
| 511 | − int len = min(dentry->d_name.len, 30u); | |
| 510 | + u32 len = min(dentry->d_name.len, AFFSNAMEMAX); | |
| 512 | 511 | |
| 513 | 512 | *bstr++ = len; |
| 514 | 513 | memcpy(bstr, dentry->d_name.name, len); |
| @@ -99,7 +99,6 @@ err_bh_read: · 98 unmodified lines | ||
| 99 | 99 | |
| 100 | 100 | err_range: |
| 101 | 101 | affs_error(sb, "affs_free_block","Block %u outside partition", block); |
| 102 | − return; | |
| 103 | 102 | } |
| 104 | 103 | |
| 105 | 104 | /* |
| @@ -54,8 +54,7 @@ affs_readdir(struct file *file, struct dir_context *ctx) · 53 unmodified lines | ||
| 54 | 54 | u32 ino; |
| 55 | 55 | int error = 0; |
| 56 | 56 | |
| 57 | − pr_debug("%s(ino=%lu,f_pos=%lx)\n", | |
| 58 | − __func__, inode->i_ino, (unsigned long)ctx->pos); | |
| 57 | + pr_debug("%s(ino=%lu,f_pos=%llx)\n", __func__, inode->i_ino, ctx->pos); | |
| 59 | 58 | |
| 60 | 59 | if (ctx->pos < 2) { |
| 61 | 60 | file->private_data = (void *)0; |
| @@ -115,11 +114,11 @@ inside: · 53 unmodified lines | ||
| 115 | 114 | break; |
| 116 | 115 | } |
| 117 | 116 | |
| 118 | − namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], (u8)30); | |
| 117 | + namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], | |
| 118 | + (u8)AFFSNAMEMAX); | |
| 119 | 119 | name = AFFS_TAIL(sb, fh_bh)->name + 1; |
| 120 | − pr_debug("readdir(): dir_emit(\"%.*s\", " | |
| 121 | − "ino=%u), hash=%d, f_pos=%x\n", | |
| 122 | − namelen, name, ino, hash_pos, (u32)ctx->pos); | |
| 120 | + pr_debug("readdir(): dir_emit(\"%.*s\", ino=%u), hash=%d, f_pos=%llx\n", | |
| 121 | + namelen, name, ino, hash_pos, ctx->pos); | |
| 123 | 122 | |
| 124 | 123 | if (!dir_emit(ctx, name, namelen, ino, DT_UNKNOWN)) |
| 125 | 124 | goto done; |
| @@ -180,8 +180,7 @@ affs_get_extblock_slow(struct inode *inode, u32 ext) · 179 unmodified lines | ||
| 180 | 180 | ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); |
| 181 | 181 | if (ext < AFFS_I(inode)->i_extcnt) |
| 182 | 182 | goto read_ext; |
| 183 | − if (ext > AFFS_I(inode)->i_extcnt) | |
| 184 | − BUG(); | |
| 183 | + BUG_ON(ext > AFFS_I(inode)->i_extcnt); | |
| 185 | 184 | bh = affs_alloc_extblock(inode, bh, ext); |
| 186 | 185 | if (IS_ERR(bh)) |
| 187 | 186 | return bh; |
| @@ -198,8 +197,7 @@ affs_get_extblock_slow(struct inode *inode, u32 ext) · 10 unmodified lines | ||
| 198 | 197 | struct buffer_head *prev_bh; |
| 199 | 198 | |
| 200 | 199 | /* allocate a new extended block */ |
| 201 | − if (ext > AFFS_I(inode)->i_extcnt) | |
| 202 | − BUG(); | |
| 200 | + BUG_ON(ext > AFFS_I(inode)->i_extcnt); | |
| 203 | 201 | |
| 204 | 202 | /* get previous extended block */ |
| 205 | 203 | 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 · 93 unmodified lines | ||
| 299 | 297 | struct buffer_head *ext_bh; |
| 300 | 298 | u32 ext; |
| 301 | 299 | |
| 302 | − pr_debug("%s(%u, %lu)\n", | |
| 303 | − __func__, (u32)inode->i_ino, (unsigned long)block); | |
| 300 | + pr_debug("%s(%lu, %llu)\n", __func__, inode->i_ino, | |
| 301 | + (unsigned long long)block); | |
| 304 | 302 | |
| 305 | 303 | BUG_ON(block > (sector_t)0x7fffffffUL); |
| 306 | 304 | |
| @@ -330,8 +328,9 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul · 23 unmodified lines | ||
| 330 | 328 | |
| 331 | 329 | /* store new block */ |
| 332 | 330 | if (bh_result->b_blocknr) |
| 333 | − affs_warning(sb, "get_block", "block already set (%lx)", | |
| 334 | − (unsigned long)bh_result->b_blocknr); | |
| 331 | + affs_warning(sb, "get_block", | |
| 332 | + "block already set (%llx)", | |
| 333 | + (unsigned long long)bh_result->b_blocknr); | |
| 335 | 334 | AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr); |
| 336 | 335 | AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1); |
| 337 | 336 | 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 · 15 unmodified lines | ||
| 353 | 352 | return 0; |
| 354 | 353 | |
| 355 | 354 | err_big: |
| 356 | − affs_error(inode->i_sb, "get_block", "strange block request %d", | |
| 357 | − (int)block); | |
| 355 | + affs_error(inode->i_sb, "get_block", "strange block request %llu", | |
| 356 | + (unsigned long long)block); | |
| 358 | 357 | return -EIO; |
| 359 | 358 | err_ext: |
| 360 | 359 | // unlock cache |
| @@ -399,6 +398,13 @@ affs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, · 38 unmodified lines | ||
| 399 | 398 | size_t count = iov_iter_count(iter); |
| 400 | 399 | ssize_t ret; |
| 401 | 400 | |
| 401 | + if (rw == WRITE) { | |
| 402 | + loff_t size = offset + count; | |
| 403 | + | |
| 404 | + if (AFFS_I(inode)->mmu_private < size) | |
| 405 | + return 0; | |
| 406 | + } | |
| 407 | + | |
| 402 | 408 | ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, affs_get_block); |
| 403 | 409 | if (ret < 0 && (rw & WRITE)) |
| 404 | 410 | affs_write_failed(mapping, offset + count); |
| @@ -503,7 +509,7 @@ affs_do_readpage_ofs(struct page *page, unsigned to) · 98 unmodified lines | ||
| 503 | 509 | u32 bidx, boff, bsize; |
| 504 | 510 | u32 tmp; |
| 505 | 511 | |
| 506 | − pr_debug("%s(%u, %ld, 0, %d)\n", __func__, (u32)inode->i_ino, | |
| 512 | + pr_debug("%s(%lu, %ld, 0, %d)\n", __func__, inode->i_ino, | |
| 507 | 513 | page->index, to); |
| 508 | 514 | BUG_ON(to > PAGE_CACHE_SIZE); |
| 509 | 515 | kmap(page); |
| @@ -539,7 +545,7 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize) · 29 unmodified lines | ||
| 539 | 545 | u32 size, bsize; |
| 540 | 546 | u32 tmp; |
| 541 | 547 | |
| 542 | − pr_debug("%s(%u, %d)\n", __func__, (u32)inode->i_ino, newsize); | |
| 548 | + pr_debug("%s(%lu, %d)\n", __func__, inode->i_ino, newsize); | |
| 543 | 549 | bsize = AFFS_SB(sb)->s_data_blksize; |
| 544 | 550 | bh = NULL; |
| 545 | 551 | size = AFFS_I(inode)->mmu_private; |
| @@ -608,7 +614,7 @@ affs_readpage_ofs(struct file *file, struct page *page) · 62 unmodified lines | ||
| 608 | 614 | u32 to; |
| 609 | 615 | int err; |
| 610 | 616 | |
| 611 | − pr_debug("%s(%u, %ld)\n", __func__, (u32)inode->i_ino, page->index); | |
| 617 | + pr_debug("%s(%lu, %ld)\n", __func__, inode->i_ino, page->index); | |
| 612 | 618 | to = PAGE_CACHE_SIZE; |
| 613 | 619 | if (((page->index + 1) << PAGE_CACHE_SHIFT) > inode->i_size) { |
| 614 | 620 | to = inode->i_size & ~PAGE_CACHE_MASK; |
| @@ -631,8 +637,8 @@ static int affs_write_begin_ofs(struct file *file, struct address_space *mapping · 16 unmodified lines | ||
| 631 | 637 | pgoff_t index; |
| 632 | 638 | int err = 0; |
| 633 | 639 | |
| 634 | − pr_debug("%s(%u, %llu, %llu)\n", __func__, (u32)inode->i_ino, | |
| 635 | − (unsigned long long)pos, (unsigned long long)pos + len); | |
| 640 | + pr_debug("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos, | |
| 641 | + pos + len); | |
| 636 | 642 | if (pos > AFFS_I(inode)->mmu_private) { |
| 637 | 643 | /* XXX: this probably leaves a too-big i_size in case of |
| 638 | 644 | * 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, · 42 unmodified lines | ||
| 681 | 687 | * due to write_begin. |
| 682 | 688 | */ |
| 683 | 689 | |
| 684 | − pr_debug("%s(%u, %llu, %llu)\n", | |
| 685 | − __func__, (u32)inode->i_ino, (unsigned long long)pos, | |
| 686 | − (unsigned long long)pos + len); | |
| 690 | + pr_debug("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos, | |
| 691 | + pos + len); | |
| 687 | 692 | bsize = AFFS_SB(sb)->s_data_blksize; |
| 688 | 693 | data = page_address(page); |
| 689 | 694 | |
| @@ -831,8 +836,8 @@ affs_truncate(struct inode *inode) · 141 unmodified lines | ||
| 831 | 836 | struct buffer_head *ext_bh; |
| 832 | 837 | int i; |
| 833 | 838 | |
| 834 | − pr_debug("truncate(inode=%d, oldsize=%u, newsize=%u)\n", | |
| 835 | − (u32)inode->i_ino, (u32)AFFS_I(inode)->mmu_private, (u32)inode->i_size); | |
| 839 | + pr_debug("truncate(inode=%lu, oldsize=%llu, newsize=%llu)\n", | |
| 840 | + inode->i_ino, AFFS_I(inode)->mmu_private, inode->i_size); | |
| 836 | 841 | |
| 837 | 842 | last_blk = 0; |
| 838 | 843 | ext = 0; |
| @@ -863,7 +868,7 @@ affs_truncate(struct inode *inode) · 24 unmodified lines | ||
| 863 | 868 | if (IS_ERR(ext_bh)) { |
| 864 | 869 | affs_warning(sb, "truncate", |
| 865 | 870 | "unexpected read error for ext block %u (%ld)", |
| 866 | − (unsigned int)ext, PTR_ERR(ext_bh)); | |
| 871 | + ext, PTR_ERR(ext_bh)); | |
| 867 | 872 | return; |
| 868 | 873 | } |
| 869 | 874 | if (AFFS_I(inode)->i_lc) { |
| @@ -911,7 +916,7 @@ affs_truncate(struct inode *inode) · 41 unmodified lines | ||
| 911 | 916 | if (IS_ERR(bh)) { |
| 912 | 917 | affs_warning(sb, "truncate", |
| 913 | 918 | "unexpected read error for last block %u (%ld)", |
| 914 | − (unsigned int)ext, PTR_ERR(bh)); | |
| 919 | + ext, PTR_ERR(bh)); | |
| 915 | 920 | return; |
| 916 | 921 | } |
| 917 | 922 | tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next); |
| @@ -13,8 +13,6 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <linux/gfp.h> |
| 14 | 14 | #include "affs.h" |
| 15 | 15 | |
| 16 | −extern const struct inode_operations affs_symlink_inode_operations; | |
| 17 | − | |
| 18 | 16 | struct inode *affs_iget(struct super_block *sb, unsigned long ino) |
| 19 | 17 | { |
| 20 | 18 | 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 · 327 unmodified lines | ||
| 348 | 346 | u32 block = 0; |
| 349 | 347 | int retval; |
| 350 | 348 | |
| 351 | − pr_debug("%s(dir=%u, inode=%u, \"%pd\", type=%d)\n", | |
| 352 | − __func__, (u32)dir->i_ino, | |
| 353 | − (u32)inode->i_ino, dentry, type); | |
| 349 | + pr_debug("%s(dir=%lu, inode=%lu, \"%pd\", type=%d)\n", __func__, | |
| 350 | + dir->i_ino, inode->i_ino, dentry, type); | |
| 354 | 351 | |
| 355 | 352 | retval = -EIO; |
| 356 | 353 | bh = affs_bread(sb, inode->i_ino); |
| @@ -64,15 +64,16 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate) · 63 unmodified lines | ||
| 64 | 64 | { |
| 65 | 65 | const u8 *name = qstr->name; |
| 66 | 66 | unsigned long hash; |
| 67 | − int i; | |
| 67 | + int retval; | |
| 68 | + u32 len; | |
| 68 | 69 | |
| 69 | − i = affs_check_name(qstr->name, qstr->len, notruncate); | |
| 70 | − if (i) | |
| 71 | − return i; | |
| 70 | + retval = affs_check_name(qstr->name, qstr->len, notruncate); | |
| 71 | + if (retval) | |
| 72 | + return retval; | |
| 72 | 73 | |
| 73 | 74 | hash = init_name_hash(); |
| 74 | − i = min(qstr->len, 30u); | |
| 75 | − for (; i > 0; name++, i--) | |
| 75 | + len = min(qstr->len, AFFSNAMEMAX); | |
| 76 | + for (; len > 0; name++, len--) | |
| 76 | 77 | hash = partial_name_hash(toupper(*name), hash); |
| 77 | 78 | qstr->hash = end_name_hash(hash); |
| 78 | 79 | |
| @@ -114,10 +115,10 @@ static inline int __affs_compare_dentry(unsigned int len, · 35 unmodified lines | ||
| 114 | 115 | * If the names are longer than the allowed 30 chars, |
| 115 | 116 | * the excess is ignored, so their length may differ. |
| 116 | 117 | */ |
| 117 | − if (len >= 30) { | |
| 118 | − if (name->len < 30) | |
| 118 | + if (len >= AFFSNAMEMAX) { | |
| 119 | + if (name->len < AFFSNAMEMAX) | |
| 119 | 120 | return 1; |
| 120 | − len = 30; | |
| 121 | + len = AFFSNAMEMAX; | |
| 121 | 122 | } else if (len != name->len) |
| 122 | 123 | return 1; |
| 123 | 124 | |
| @@ -156,10 +157,10 @@ affs_match(struct dentry *dentry, const u8 *name2, toupper_t toupper) · 32 unmodified lines | ||
| 156 | 157 | const u8 *name = dentry->d_name.name; |
| 157 | 158 | int len = dentry->d_name.len; |
| 158 | 159 | |
| 159 | − if (len >= 30) { | |
| 160 | − if (*name2 < 30) | |
| 160 | + if (len >= AFFSNAMEMAX) { | |
| 161 | + if (*name2 < AFFSNAMEMAX) | |
| 161 | 162 | return 0; |
| 162 | − len = 30; | |
| 163 | + len = AFFSNAMEMAX; | |
| 163 | 164 | } else if (len != *name2) |
| 164 | 165 | return 0; |
| 165 | 166 | |
| @@ -173,9 +174,9 @@ int · 7 unmodified lines | ||
| 173 | 174 | affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len) |
| 174 | 175 | { |
| 175 | 176 | toupper_t toupper = affs_get_toupper(sb); |
| 176 | − int hash; | |
| 177 | + u32 hash; | |
| 177 | 178 | |
| 178 | − hash = len = min(len, 30u); | |
| 179 | + hash = len = min(len, AFFSNAMEMAX); | |
| 179 | 180 | for (; len > 0; len--) |
| 180 | 181 | hash = (hash * 13 + toupper(*name++)) & 0x7ff; |
| 181 | 182 | |
| @@ -248,9 +249,8 @@ affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) · 66 unmodified lines | ||
| 248 | 249 | int |
| 249 | 250 | affs_unlink(struct inode *dir, struct dentry *dentry) |
| 250 | 251 | { |
| 251 | − pr_debug("%s(dir=%d, %lu \"%pd\")\n", | |
| 252 | − __func__, (u32)dir->i_ino, dentry->d_inode->i_ino, | |
| 253 | − dentry); | |
| 252 | + pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino, | |
| 253 | + dentry->d_inode->i_ino, dentry); | |
| 254 | 254 | |
| 255 | 255 | return affs_remove_header(dentry); |
| 256 | 256 | } |
| @@ -317,9 +317,8 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) · 60 unmodified lines | ||
| 317 | 317 | int |
| 318 | 318 | affs_rmdir(struct inode *dir, struct dentry *dentry) |
| 319 | 319 | { |
| 320 | − pr_debug("%s(dir=%u, %lu \"%pd\")\n", | |
| 321 | − __func__, (u32)dir->i_ino, dentry->d_inode->i_ino, | |
| 322 | − dentry); | |
| 320 | + pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino, | |
| 321 | + dentry->d_inode->i_ino, dentry); | |
| 323 | 322 | |
| 324 | 323 | return affs_remove_header(dentry); |
| 325 | 324 | } |
| @@ -404,8 +403,7 @@ affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) · 78 unmodified lines | ||
| 404 | 403 | { |
| 405 | 404 | struct inode *inode = old_dentry->d_inode; |
| 406 | 405 | |
| 407 | − pr_debug("%s(%u, %u, \"%pd\")\n", | |
| 408 | − __func__, (u32)inode->i_ino, (u32)dir->i_ino, | |
| 406 | + pr_debug("%s(%lu, %lu, \"%pd\")\n", __func__, inode->i_ino, dir->i_ino, | |
| 409 | 407 | dentry); |
| 410 | 408 | |
| 411 | 409 | return affs_add_entry(dir, inode, dentry, ST_LINKFILE); |
| @@ -419,9 +417,8 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry, · 7 unmodified lines | ||
| 419 | 417 | struct buffer_head *bh = NULL; |
| 420 | 418 | int retval; |
| 421 | 419 | |
| 422 | − pr_debug("%s(old=%u,\"%pd\" to new=%u,\"%pd\")\n", | |
| 423 | − __func__, (u32)old_dir->i_ino, old_dentry, | |
| 424 | − (u32)new_dir->i_ino, new_dentry); | |
| 420 | + pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__, | |
| 421 | + old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry); | |
| 425 | 422 | |
| 426 | 423 | retval = affs_check_name(new_dentry->d_name.name, |
| 427 | 424 | new_dentry->d_name.len, |
| @@ -432,39 +432,39 @@ got_root: · 431 unmodified lines | ||
| 432 | 432 | sb->s_flags |= MS_RDONLY; |
| 433 | 433 | } |
| 434 | 434 | switch (chksum) { |
| 435 | − case MUFS_FS: | |
| 436 | − case MUFS_INTLFFS: | |
| 437 | − case MUFS_DCFFS: | |
| 438 | − sbi->s_flags |= SF_MUFS; | |
| 439 | − /* fall thru */ | |
| 440 | − case FS_INTLFFS: | |
| 441 | − case FS_DCFFS: | |
| 442 | − sbi->s_flags |= SF_INTL; | |
| 443 | − break; | |
| 444 | − case MUFS_FFS: | |
| 445 | − sbi->s_flags |= SF_MUFS; | |
| 446 | − break; | |
| 447 | − case FS_FFS: | |
| 448 | − break; | |
| 449 | − case MUFS_OFS: | |
| 450 | − sbi->s_flags |= SF_MUFS; | |
| 451 | − /* fall thru */ | |
| 452 | − case FS_OFS: | |
| 453 | − sbi->s_flags |= SF_OFS; | |
| 454 | − sb->s_flags |= MS_NOEXEC; | |
| 455 | − break; | |
| 456 | − case MUFS_DCOFS: | |
| 457 | − case MUFS_INTLOFS: | |
| 458 | − sbi->s_flags |= SF_MUFS; | |
| 459 | − case FS_DCOFS: | |
| 460 | − case FS_INTLOFS: | |
| 461 | − sbi->s_flags |= SF_INTL | SF_OFS; | |
| 462 | − sb->s_flags |= MS_NOEXEC; | |
| 463 | − break; | |
| 464 | − default: | |
| 465 | − pr_err("Unknown filesystem on device %s: %08X\n", | |
| 466 | − sb->s_id, chksum); | |
| 467 | − return -EINVAL; | |
| 435 | + case MUFS_FS: | |
| 436 | + case MUFS_INTLFFS: | |
| 437 | + case MUFS_DCFFS: | |
| 438 | + sbi->s_flags |= SF_MUFS; | |
| 439 | + /* fall thru */ | |
| 440 | + case FS_INTLFFS: | |
| 441 | + case FS_DCFFS: | |
| 442 | + sbi->s_flags |= SF_INTL; | |
| 443 | + break; | |
| 444 | + case MUFS_FFS: | |
| 445 | + sbi->s_flags |= SF_MUFS; | |
| 446 | + break; | |
| 447 | + case FS_FFS: | |
| 448 | + break; | |
| 449 | + case MUFS_OFS: | |
| 450 | + sbi->s_flags |= SF_MUFS; | |
| 451 | + /* fall thru */ | |
| 452 | + case FS_OFS: | |
| 453 | + sbi->s_flags |= SF_OFS; | |
| 454 | + sb->s_flags |= MS_NOEXEC; | |
| 455 | + break; | |
| 456 | + case MUFS_DCOFS: | |
| 457 | + case MUFS_INTLOFS: | |
| 458 | + sbi->s_flags |= SF_MUFS; | |
| 459 | + case FS_DCOFS: | |
| 460 | + case FS_INTLOFS: | |
| 461 | + sbi->s_flags |= SF_INTL | SF_OFS; | |
| 462 | + sb->s_flags |= MS_NOEXEC; | |
| 463 | + break; | |
| 464 | + default: | |
| 465 | + pr_err("Unknown filesystem on device %s: %08X\n", | |
| 466 | + sb->s_id, chksum); | |
| 467 | + return -EINVAL; | |
| 468 | 468 | } |
| 469 | 469 | |
| 470 | 470 | if (mount_flags & SF_VERBOSE) { |
| @@ -584,7 +584,7 @@ affs_statfs(struct dentry *dentry, struct kstatfs *buf) · 113 unmodified lines | ||
| 584 | 584 | buf->f_bavail = free; |
| 585 | 585 | buf->f_fsid.val[0] = (u32)id; |
| 586 | 586 | buf->f_fsid.val[1] = (u32)(id >> 32); |
| 587 | − buf->f_namelen = 30; | |
| 587 | + buf->f_namelen = AFFSNAMEMAX; | |
| 588 | 588 | return 0; |
| 589 | 589 | } |
| 590 | 590 | |
| @@ -602,6 +602,7 @@ static void affs_kill_sb(struct super_block *sb) · 11 unmodified lines | ||
| 602 | 602 | affs_free_bitmap(sb); |
| 603 | 603 | affs_brelse(sbi->s_root_bh); |
| 604 | 604 | kfree(sbi->s_prefix); |
| 605 | + mutex_destroy(&sbi->s_bmlock); | |
| 605 | 606 | kfree(sbi); |
| 606 | 607 | } |
| 607 | 608 | } |
| @@ -274,9 +274,9 @@ more: · 273 unmodified lines | ||
| 274 | 274 | static struct inode * |
| 275 | 275 | befs_alloc_inode(struct super_block *sb) |
| 276 | 276 | { |
| 277 | − struct befs_inode_info *bi; | |
| 278 | − bi = (struct befs_inode_info *)kmem_cache_alloc(befs_inode_cachep, | |
| 279 | − GFP_KERNEL); | |
| 277 | + struct befs_inode_info *bi; | |
| 278 | + | |
| 279 | + bi = kmem_cache_alloc(befs_inode_cachep, GFP_KERNEL); | |
| 280 | 280 | if (!bi) |
| 281 | 281 | return NULL; |
| 282 | 282 | return &bi->vfs_inode; |
| @@ -28,29 +28,6 @@ · 27 unmodified lines | ||
| 28 | 28 | |
| 29 | 29 | #include "coda_int.h" |
| 30 | 30 | |
| 31 | −/* dir inode-ops */ | |
| 32 | −static int coda_create(struct inode *dir, struct dentry *new, umode_t mode, bool excl); | |
| 33 | −static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, unsigned int flags); | |
| 34 | −static int coda_link(struct dentry *old_dentry, struct inode *dir_inode, | |
| 35 | − struct dentry *entry); | |
| 36 | −static int coda_unlink(struct inode *dir_inode, struct dentry *entry); | |
| 37 | −static int coda_symlink(struct inode *dir_inode, struct dentry *entry, | |
| 38 | − const char *symname); | |
| 39 | −static int coda_mkdir(struct inode *dir_inode, struct dentry *entry, umode_t mode); | |
| 40 | −static int coda_rmdir(struct inode *dir_inode, struct dentry *entry); | |
| 41 | −static int coda_rename(struct inode *old_inode, struct dentry *old_dentry, | |
| 42 | − struct inode *new_inode, struct dentry *new_dentry); | |
| 43 | − | |
| 44 | −/* dir file-ops */ | |
| 45 | −static int coda_readdir(struct file *file, struct dir_context *ctx); | |
| 46 | − | |
| 47 | −/* dentry ops */ | |
| 48 | −static int coda_dentry_revalidate(struct dentry *de, unsigned int flags); | |
| 49 | −static int coda_dentry_delete(const struct dentry *); | |
| 50 | − | |
| 51 | −/* support routines */ | |
| 52 | −static int coda_venus_readdir(struct file *, struct dir_context *); | |
| 53 | − | |
| 54 | 31 | /* same as fs/bad_inode.c */ |
| 55 | 32 | static int coda_return_EIO(void) |
| 56 | 33 | { |
| @@ -58,38 +35,6 @@ static int coda_return_EIO(void) · 1 unmodified line | ||
| 58 | 35 | } |
| 59 | 36 | #define CODA_EIO_ERROR ((void *) (coda_return_EIO)) |
| 60 | 37 | |
| 61 | −const struct dentry_operations coda_dentry_operations = | |
| 62 | −{ | |
| 63 | − .d_revalidate = coda_dentry_revalidate, | |
| 64 | − .d_delete = coda_dentry_delete, | |
| 65 | −}; | |
| 66 | − | |
| 67 | −const struct inode_operations coda_dir_inode_operations = | |
| 68 | −{ | |
| 69 | − .create = coda_create, | |
| 70 | − .lookup = coda_lookup, | |
| 71 | − .link = coda_link, | |
| 72 | − .unlink = coda_unlink, | |
| 73 | − .symlink = coda_symlink, | |
| 74 | − .mkdir = coda_mkdir, | |
| 75 | − .rmdir = coda_rmdir, | |
| 76 | − .mknod = CODA_EIO_ERROR, | |
| 77 | − .rename = coda_rename, | |
| 78 | − .permission = coda_permission, | |
| 79 | − .getattr = coda_getattr, | |
| 80 | − .setattr = coda_setattr, | |
| 81 | −}; | |
| 82 | − | |
| 83 | −const struct file_operations coda_dir_operations = { | |
| 84 | − .llseek = generic_file_llseek, | |
| 85 | − .read = generic_read_dir, | |
| 86 | − .iterate = coda_readdir, | |
| 87 | − .open = coda_open, | |
| 88 | − .release = coda_release, | |
| 89 | − .fsync = coda_fsync, | |
| 90 | −}; | |
| 91 | − | |
| 92 | − | |
| 93 | 38 | /* inode operations for directories */ |
| 94 | 39 | /* access routines: lookup, readlink, permission */ |
| 95 | 40 | 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, · 278 unmodified lines | ||
| 374 | 319 | return error; |
| 375 | 320 | } |
| 376 | 321 | |
| 377 | − | |
| 378 | −/* file operations for directories */ | |
| 379 | −static int coda_readdir(struct file *coda_file, struct dir_context *ctx) | |
| 380 | −{ | |
| 381 | − struct coda_file_info *cfi; | |
| 382 | − struct file *host_file; | |
| 383 | − int ret; | |
| 384 | − | |
| 385 | − cfi = CODA_FTOC(coda_file); | |
| 386 | − BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); | |
| 387 | − host_file = cfi->cfi_container; | |
| 388 | − | |
| 389 | − if (host_file->f_op->iterate) { | |
| 390 | − struct inode *host_inode = file_inode(host_file); | |
| 391 | − mutex_lock(&host_inode->i_mutex); | |
| 392 | − ret = -ENOENT; | |
| 393 | − if (!IS_DEADDIR(host_inode)) { | |
| 394 | − ret = host_file->f_op->iterate(host_file, ctx); | |
| 395 | − file_accessed(host_file); | |
| 396 | − } | |
| 397 | − mutex_unlock(&host_inode->i_mutex); | |
| 398 | − return ret; | |
| 399 | − } | |
| 400 | − /* Venus: we must read Venus dirents from a file */ | |
| 401 | − return coda_venus_readdir(coda_file, ctx); | |
| 402 | −} | |
| 403 | − | |
| 404 | 322 | static inline unsigned int CDT2DT(unsigned char cdt) |
| 405 | 323 | { |
| 406 | 324 | unsigned int dt; |
| @@ -495,6 +413,33 @@ out: · 88 unmodified lines | ||
| 495 | 413 | return 0; |
| 496 | 414 | } |
| 497 | 415 | |
| 416 | +/* file operations for directories */ | |
| 417 | +static int coda_readdir(struct file *coda_file, struct dir_context *ctx) | |
| 418 | +{ | |
| 419 | + struct coda_file_info *cfi; | |
| 420 | + struct file *host_file; | |
| 421 | + int ret; | |
| 422 | + | |
| 423 | + cfi = CODA_FTOC(coda_file); | |
| 424 | + BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); | |
| 425 | + host_file = cfi->cfi_container; | |
| 426 | + | |
| 427 | + if (host_file->f_op->iterate) { | |
| 428 | + struct inode *host_inode = file_inode(host_file); | |
| 429 | + | |
| 430 | + mutex_lock(&host_inode->i_mutex); | |
| 431 | + ret = -ENOENT; | |
| 432 | + if (!IS_DEADDIR(host_inode)) { | |
| 433 | + ret = host_file->f_op->iterate(host_file, ctx); | |
| 434 | + file_accessed(host_file); | |
| 435 | + } | |
| 436 | + mutex_unlock(&host_inode->i_mutex); | |
| 437 | + return ret; | |
| 438 | + } | |
| 439 | + /* Venus: we must read Venus dirents from a file */ | |
| 440 | + return coda_venus_readdir(coda_file, ctx); | |
| 441 | +} | |
| 442 | + | |
| 498 | 443 | /* called when a cache lookup succeeds */ |
| 499 | 444 | static int coda_dentry_revalidate(struct dentry *de, unsigned int flags) |
| 500 | 445 | { |
| @@ -603,3 +548,32 @@ int coda_revalidate_inode(struct inode *inode) · 102 unmodified lines | ||
| 603 | 548 | } |
| 604 | 549 | return 0; |
| 605 | 550 | } |
| 551 | + | |
| 552 | +const struct dentry_operations coda_dentry_operations = { | |
| 553 | + .d_revalidate = coda_dentry_revalidate, | |
| 554 | + .d_delete = coda_dentry_delete, | |
| 555 | +}; | |
| 556 | + | |
| 557 | +const struct inode_operations coda_dir_inode_operations = { | |
| 558 | + .create = coda_create, | |
| 559 | + .lookup = coda_lookup, | |
| 560 | + .link = coda_link, | |
| 561 | + .unlink = coda_unlink, | |
| 562 | + .symlink = coda_symlink, | |
| 563 | + .mkdir = coda_mkdir, | |
| 564 | + .rmdir = coda_rmdir, | |
| 565 | + .mknod = CODA_EIO_ERROR, | |
| 566 | + .rename = coda_rename, | |
| 567 | + .permission = coda_permission, | |
| 568 | + .getattr = coda_getattr, | |
| 569 | + .setattr = coda_setattr, | |
| 570 | +}; | |
| 571 | + | |
| 572 | +const struct file_operations coda_dir_operations = { | |
| 573 | + .llseek = generic_file_llseek, | |
| 574 | + .read = generic_read_dir, | |
| 575 | + .iterate = coda_readdir, | |
| 576 | + .open = coda_open, | |
| 577 | + .release = coda_release, | |
| 578 | + .fsync = coda_fsync, | |
| 579 | +}; | |
| @@ -118,18 +118,18 @@ static unsigned int eventfd_poll(struct file *file, poll_table *wait) · 117 unmodified lines | ||
| 118 | 118 | { |
| 119 | 119 | struct eventfd_ctx *ctx = file->private_data; |
| 120 | 120 | unsigned int events = 0; |
| 121 | − unsigned long flags; | |
| 121 | + u64 count; | |
| 122 | 122 | |
| 123 | 123 | poll_wait(file, &ctx->wqh, wait); |
| 124 | + smp_rmb(); | |
| 125 | + count = ctx->count; | |
| 124 | 126 | |
| 125 | − spin_lock_irqsave(&ctx->wqh.lock, flags); | |
| 126 | − if (ctx->count > 0) | |
| 127 | + if (count > 0) | |
| 127 | 128 | events |= POLLIN; |
| 128 | − if (ctx->count == ULLONG_MAX) | |
| 129 | + if (count == ULLONG_MAX) | |
| 129 | 130 | events |= POLLERR; |
| 130 | − if (ULLONG_MAX - 1 > ctx->count) | |
| 131 | + if (ULLONG_MAX - 1 > count) | |
| 131 | 132 | events |= POLLOUT; |
| 132 | − spin_unlock_irqrestore(&ctx->wqh.lock, flags); | |
| 133 | 133 | |
| 134 | 134 | return events; |
| 135 | 135 | } |
| @@ -580,7 +580,7 @@ static void fat_set_state(struct super_block *sb, · 579 unmodified lines | ||
| 580 | 580 | { |
| 581 | 581 | struct buffer_head *bh; |
| 582 | 582 | struct fat_boot_sector *b; |
| 583 | − struct msdos_sb_info *sbi = sb->s_fs_info; | |
| 583 | + struct msdos_sb_info *sbi = MSDOS_SB(sb); | |
| 584 | 584 | |
| 585 | 585 | /* do not change any thing if mounted read only */ |
| 586 | 586 | if ((sb->s_flags & MS_RDONLY) && !force) |
| @@ -546,8 +546,8 @@ static int __init update_note_header_size_elf64(const Elf64_Ehdr *ehdr_ptr) · 545 unmodified lines | ||
| 546 | 546 | nhdr_ptr = notes_section; |
| 547 | 547 | while (nhdr_ptr->n_namesz != 0) { |
| 548 | 548 | sz = sizeof(Elf64_Nhdr) + |
| 549 | − ((nhdr_ptr->n_namesz + 3) & ~3) + | |
| 550 | − ((nhdr_ptr->n_descsz + 3) & ~3); | |
| 549 | + (((u64)nhdr_ptr->n_namesz + 3) & ~3) + | |
| 550 | + (((u64)nhdr_ptr->n_descsz + 3) & ~3); | |
| 551 | 551 | if ((real_sz + sz) > max_sz) { |
| 552 | 552 | pr_warn("Warning: Exceeded p_memsz, dropping PT_NOTE entry n_namesz=0x%x, n_descsz=0x%x\n", |
| 553 | 553 | 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) · 178 unmodified lines | ||
| 732 | 732 | nhdr_ptr = notes_section; |
| 733 | 733 | while (nhdr_ptr->n_namesz != 0) { |
| 734 | 734 | sz = sizeof(Elf32_Nhdr) + |
| 735 | − ((nhdr_ptr->n_namesz + 3) & ~3) + | |
| 736 | − ((nhdr_ptr->n_descsz + 3) & ~3); | |
| 735 | + (((u64)nhdr_ptr->n_namesz + 3) & ~3) + | |
| 736 | + (((u64)nhdr_ptr->n_descsz + 3) & ~3); | |
| 737 | 737 | if ((real_sz + sz) > max_sz) { |
| 738 | 738 | pr_warn("Warning: Exceeded p_memsz, dropping PT_NOTE entry n_namesz=0x%x, n_descsz=0x%x\n", |
| 739 | 739 | nhdr_ptr->n_namesz, nhdr_ptr->n_descsz); |
| @@ -2766,7 +2766,7 @@ static int reiserfs_write_begin(struct file *file, · 2765 unmodified lines | ||
| 2766 | 2766 | int old_ref = 0; |
| 2767 | 2767 | |
| 2768 | 2768 | inode = mapping->host; |
| 2769 | − *fsdata = 0; | |
| 2769 | + *fsdata = NULL; | |
| 2770 | 2770 | if (flags & AOP_FLAG_CONT_EXPAND && |
| 2771 | 2771 | (pos & (inode->i_sb->s_blocksize - 1)) == 0) { |
| 2772 | 2772 | pos ++; |
| @@ -95,22 +95,18 @@ · 94 unmodified lines | ||
| 95 | 95 | |
| 96 | 96 | void lock_ufs(struct super_block *sb) |
| 97 | 97 | { |
| 98 | −#if defined(CONFIG_SMP) || defined (CONFIG_PREEMPT) | |
| 99 | 98 | struct ufs_sb_info *sbi = UFS_SB(sb); |
| 100 | 99 | |
| 101 | 100 | mutex_lock(&sbi->mutex); |
| 102 | 101 | sbi->mutex_owner = current; |
| 103 | −#endif | |
| 104 | 102 | } |
| 105 | 103 | |
| 106 | 104 | void unlock_ufs(struct super_block *sb) |
| 107 | 105 | { |
| 108 | −#if defined(CONFIG_SMP) || defined (CONFIG_PREEMPT) | |
| 109 | 106 | struct ufs_sb_info *sbi = UFS_SB(sb); |
| 110 | 107 | |
| 111 | 108 | sbi->mutex_owner = NULL; |
| 112 | 109 | mutex_unlock(&sbi->mutex); |
| 113 | −#endif | |
| 114 | 110 | } |
| 115 | 111 | |
| 116 | 112 | 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; · 1298 unmodified lines | ||
| 1415 | 1411 | static struct inode *ufs_alloc_inode(struct super_block *sb) |
| 1416 | 1412 | { |
| 1417 | 1413 | struct ufs_inode_info *ei; |
| 1418 | − ei = (struct ufs_inode_info *)kmem_cache_alloc(ufs_inode_cachep, GFP_NOFS); | |
| 1414 | + | |
| 1415 | + ei = kmem_cache_alloc(ufs_inode_cachep, GFP_NOFS); | |
| 1419 | 1416 | if (!ei) |
| 1420 | 1417 | return NULL; |
| 1418 | + | |
| 1421 | 1419 | ei->vfs_inode.i_version = 1; |
| 1422 | 1420 | return &ei->vfs_inode; |
| 1423 | 1421 | } |
| @@ -1,6 +1,19 @@ | ||
| 1 | 1 | #ifndef LINUX_KEXEC_H |
| 2 | 2 | #define LINUX_KEXEC_H |
| 3 | 3 | |
| 4 | +#define IND_DESTINATION_BIT 0 | |
| 5 | +#define IND_INDIRECTION_BIT 1 | |
| 6 | +#define IND_DONE_BIT 2 | |
| 7 | +#define IND_SOURCE_BIT 3 | |
| 8 | + | |
| 9 | +#define IND_DESTINATION (1 << IND_DESTINATION_BIT) | |
| 10 | +#define IND_INDIRECTION (1 << IND_INDIRECTION_BIT) | |
| 11 | +#define IND_DONE (1 << IND_DONE_BIT) | |
| 12 | +#define IND_SOURCE (1 << IND_SOURCE_BIT) | |
| 13 | +#define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE) | |
| 14 | + | |
| 15 | +#if !defined(__ASSEMBLY__) | |
| 16 | + | |
| 4 | 17 | #include <uapi/linux/kexec.h> |
| 5 | 18 | |
| 6 | 19 | #ifdef CONFIG_KEXEC |
| @@ -64,10 +77,6 @@ · 57 unmodified lines | ||
| 64 | 77 | */ |
| 65 | 78 | |
| 66 | 79 | typedef unsigned long kimage_entry_t; |
| 67 | −#define IND_DESTINATION 0x1 | |
| 68 | −#define IND_INDIRECTION 0x2 | |
| 69 | −#define IND_DONE 0x4 | |
| 70 | −#define IND_SOURCE 0x8 | |
| 71 | 80 | |
| 72 | 81 | struct kexec_segment { |
| 73 | 82 | /* |
| @@ -122,8 +131,6 @@ struct kimage { · 48 unmodified lines | ||
| 122 | 131 | kimage_entry_t *entry; |
| 123 | 132 | kimage_entry_t *last_entry; |
| 124 | 133 | |
| 125 | − unsigned long destination; | |
| 126 | − | |
| 127 | 134 | unsigned long start; |
| 128 | 135 | struct page *control_code_page; |
| 129 | 136 | struct page *swap_page; |
| @@ -313,4 +320,7 @@ struct task_struct; · 183 unmodified lines | ||
| 313 | 320 | static inline void crash_kexec(struct pt_regs *regs) { } |
| 314 | 321 | static inline int kexec_should_crash(struct task_struct *p) { return 0; } |
| 315 | 322 | #endif /* CONFIG_KEXEC */ |
| 323 | + | |
| 324 | +#endif /* !defined(__ASSEBMLY__) */ | |
| 325 | + | |
| 316 | 326 | #endif /* LINUX_KEXEC_H */ |
| @@ -51,7 +51,7 @@ struct rb_root { · 50 unmodified lines | ||
| 51 | 51 | |
| 52 | 52 | #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) |
| 53 | 53 | |
| 54 | −/* 'empty' nodes are nodes that are known not to be inserted in an rbree */ | |
| 54 | +/* 'empty' nodes are nodes that are known not to be inserted in an rbtree */ | |
| 55 | 55 | #define RB_EMPTY_NODE(node) \ |
| 56 | 56 | ((node)->__rb_parent_color == (unsigned long)(node)) |
| 57 | 57 | #define RB_CLEAR_NODE(node) \ |
| @@ -55,12 +55,6 @@ struct kexec_segment { · 54 unmodified lines | ||
| 55 | 55 | size_t memsz; |
| 56 | 56 | }; |
| 57 | 57 | |
| 58 | −/* Load a new kernel image as described by the kexec_segment array | |
| 59 | − * consisting of passed number of segments at the entry-point address. | |
| 60 | − * The flags allow different useage types. | |
| 61 | − */ | |
| 62 | −extern int kexec_load(void *, size_t, struct kexec_segment *, | |
| 63 | − unsigned long int); | |
| 64 | 58 | #endif /* __KERNEL__ */ |
| 65 | 59 | |
| 66 | 60 | #endif /* _UAPILINUX_KEXEC_H */ |
| @@ -1941,7 +1941,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, · 1940 unmodified lines | ||
| 1941 | 1941 | queue.sleeper = current; |
| 1942 | 1942 | |
| 1943 | 1943 | sleep_again: |
| 1944 | − current->state = TASK_INTERRUPTIBLE; | |
| 1944 | + __set_current_state(TASK_INTERRUPTIBLE); | |
| 1945 | 1945 | sem_unlock(sma, locknum); |
| 1946 | 1946 | rcu_read_unlock(); |
| 1947 | 1947 | |
| @@ -444,7 +444,7 @@ arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, · 443 unmodified lines | ||
| 444 | 444 | } |
| 445 | 445 | |
| 446 | 446 | /* |
| 447 | − * Free up memory used by kernel, initrd, and comand line. This is temporary | |
| 447 | + * Free up memory used by kernel, initrd, and command line. This is temporary | |
| 448 | 448 | * memory allocation which is not needed any more after these buffers have |
| 449 | 449 | * been loaded into separate segments and have been copied elsewhere. |
| 450 | 450 | */ |
| @@ -856,8 +856,6 @@ static int kimage_set_destination(struct kimage *image, · 405 unmodified lines | ||
| 856 | 856 | |
| 857 | 857 | destination &= PAGE_MASK; |
| 858 | 858 | result = kimage_add_entry(image, destination | IND_DESTINATION); |
| 859 | − if (result == 0) | |
| 860 | − image->destination = destination; | |
| 861 | 859 | |
| 862 | 860 | return result; |
| 863 | 861 | } |
| @@ -869,8 +867,6 @@ static int kimage_add_page(struct kimage *image, unsigned long page) · 5 unmodified lines | ||
| 869 | 867 | |
| 870 | 868 | page &= PAGE_MASK; |
| 871 | 869 | result = kimage_add_entry(image, page | IND_SOURCE); |
| 872 | − if (result == 0) | |
| 873 | − image->destination += PAGE_SIZE; | |
| 874 | 870 | |
| 875 | 871 | return result; |
| 876 | 872 | } |
| @@ -1288,19 +1284,22 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, · 411 unmodified lines | ||
| 1288 | 1284 | if (nr_segments > 0) { |
| 1289 | 1285 | unsigned long i; |
| 1290 | 1286 | |
| 1291 | − /* Loading another kernel to reboot into */ | |
| 1292 | − if ((flags & KEXEC_ON_CRASH) == 0) | |
| 1293 | − result = kimage_alloc_init(&image, entry, nr_segments, | |
| 1294 | − segments, flags); | |
| 1295 | − /* Loading another kernel to switch to if this one crashes */ | |
| 1296 | − else if (flags & KEXEC_ON_CRASH) { | |
| 1297 | − /* Free any current crash dump kernel before | |
| 1287 | + if (flags & KEXEC_ON_CRASH) { | |
| 1288 | + /* | |
| 1289 | + * Loading another kernel to switch to if this one | |
| 1290 | + * crashes. Free any current crash dump kernel before | |
| 1298 | 1291 | * we corrupt it. |
| 1299 | 1292 | */ |
| 1293 | + | |
| 1300 | 1294 | kimage_free(xchg(&kexec_crash_image, NULL)); |
| 1301 | 1295 | result = kimage_alloc_init(&image, entry, nr_segments, |
| 1302 | 1296 | segments, flags); |
| 1303 | 1297 | crash_map_reserved_pages(); |
| 1298 | + } else { | |
| 1299 | + /* Loading another kernel to reboot into. */ | |
| 1300 | + | |
| 1301 | + result = kimage_alloc_init(&image, entry, nr_segments, | |
| 1302 | + segments, flags); | |
| 1304 | 1303 | } |
| 1305 | 1304 | if (result) |
| 1306 | 1305 | goto out; |
| @@ -3025,8 +3025,13 @@ static void do_free_init(struct rcu_head *head) · 3024 unmodified lines | ||
| 3025 | 3025 | kfree(m); |
| 3026 | 3026 | } |
| 3027 | 3027 | |
| 3028 | −/* This is where the real work happens */ | |
| 3029 | −static int do_init_module(struct module *mod) | |
| 3028 | +/* | |
| 3029 | + * This is where the real work happens. | |
| 3030 | + * | |
| 3031 | + * Keep it uninlined to provide a reliable breakpoint target, e.g. for the gdb | |
| 3032 | + * helper command 'lx-symbols'. | |
| 3033 | + */ | |
| 3034 | +static noinline int do_init_module(struct module *mod) | |
| 3030 | 3035 | { |
| 3031 | 3036 | int ret = 0; |
| 3032 | 3037 | struct mod_initfree *freeinit; |
| @@ -1077,7 +1077,6 @@ int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, · 1076 unmodified lines | ||
| 1077 | 1077 | } |
| 1078 | 1078 | |
| 1079 | 1079 | #if defined CONFIG_COMPAT |
| 1080 | −#include <linux/compat.h> | |
| 1081 | 1080 | |
| 1082 | 1081 | int compat_ptrace_request(struct task_struct *child, compat_long_t request, |
| 1083 | 1082 | compat_ulong_t addr, compat_ulong_t data) |
| @@ -629,7 +629,9 @@ static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd) · 628 unmodified lines | ||
| 629 | 629 | |
| 630 | 630 | switch (action) { |
| 631 | 631 | case SECCOMP_RET_ERRNO: |
| 632 | − /* Set the low-order 16-bits as a errno. */ | |
| 632 | + /* Set low-order bits as an errno, capped at MAX_ERRNO. */ | |
| 633 | + if (data > MAX_ERRNO) | |
| 634 | + data = MAX_ERRNO; | |
| 633 | 635 | syscall_set_return_value(current, task_pt_regs(current), |
| 634 | 636 | -data, 0); |
| 635 | 637 | goto skip; |
| @@ -3550,7 +3550,7 @@ SYSCALL_DEFINE2(signal, int, sig, __sighandler_t, handler) · 3549 unmodified lines | ||
| 3550 | 3550 | SYSCALL_DEFINE0(pause) |
| 3551 | 3551 | { |
| 3552 | 3552 | while (!signal_pending(current)) { |
| 3553 | − current->state = TASK_INTERRUPTIBLE; | |
| 3553 | + __set_current_state(TASK_INTERRUPTIBLE); | |
| 3554 | 3554 | schedule(); |
| 3555 | 3555 | } |
| 3556 | 3556 | return -ERESTARTNOHAND; |
| @@ -3563,7 +3563,7 @@ int sigsuspend(sigset_t *set) · 6 unmodified lines | ||
| 3563 | 3563 | current->saved_sigmask = current->blocked; |
| 3564 | 3564 | set_current_blocked(set); |
| 3565 | 3565 | |
| 3566 | − current->state = TASK_INTERRUPTIBLE; | |
| 3566 | + __set_current_state(TASK_INTERRUPTIBLE); | |
| 3567 | 3567 | schedule(); |
| 3568 | 3568 | set_restore_sigmask(); |
| 3569 | 3569 | return -ERESTARTNOHAND; |
| @@ -167,6 +167,17 @@ config DEBUG_INFO_DWARF4 · 166 unmodified lines | ||
| 167 | 167 | But it significantly improves the success of resolving |
| 168 | 168 | variables in gdb on optimized code. |
| 169 | 169 | |
| 170 | +config GDB_SCRIPTS | |
| 171 | + bool "Provide GDB scripts for kernel debugging" | |
| 172 | + depends on DEBUG_INFO | |
| 173 | + help | |
| 174 | + This creates the required links to GDB helper scripts in the | |
| 175 | + build directory. If you load vmlinux into gdb, the helper | |
| 176 | + scripts will be automatically imported by gdb as well, and | |
| 177 | + additional functions are available to analyze a Linux kernel | |
| 178 | + instance. See Documentation/gdb-kernel-debugging.txt for further | |
| 179 | + details. | |
| 180 | + | |
| 170 | 181 | config ENABLE_WARN_DEPRECATED |
| 171 | 182 | bool "Enable __deprecated logic" |
| 172 | 183 | default y |
| @@ -25,7 +25,9 @@ · 24 unmodified lines | ||
| 25 | 25 | |
| 26 | 26 | int main(int argc, char **argv) |
| 27 | 27 | { |
| 28 | − struct bpf_labels l; | |
| 28 | + struct bpf_labels l = { | |
| 29 | + .count = 0, | |
| 30 | + }; | |
| 29 | 31 | static const char msg1[] = "Please type something: "; |
| 30 | 32 | static const char msg2[] = "You typed: "; |
| 31 | 33 | char buf[256]; |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | 12 | #include <stdio.h> |
| 13 | +#include <stdlib.h> | |
| 13 | 14 | #include <string.h> |
| 14 | 15 | |
| 15 | 16 | #include "bpf-helper.h" |
| @@ -63,6 +64,11 @@ __u32 seccomp_bpf_label(struct bpf_labels *labels, const char *label) · 47 unmodified lines | ||
| 63 | 64 | { |
| 64 | 65 | struct __bpf_label *begin = labels->labels, *end; |
| 65 | 66 | int id; |
| 67 | + | |
| 68 | + if (labels->count == BPF_LABELS_MAX) { | |
| 69 | + fprintf(stderr, "Too many labels\n"); | |
| 70 | + exit(1); | |
| 71 | + } | |
| 66 | 72 | if (labels->count == 0) { |
| 67 | 73 | begin->label = label; |
| 68 | 74 | begin->location = 0xffffffff; |
| @@ -36,6 +36,7 @@ subdir-$(CONFIG_MODVERSIONS) += genksyms · 35 unmodified lines | ||
| 36 | 36 | subdir-y += mod |
| 37 | 37 | subdir-$(CONFIG_SECURITY_SELINUX) += selinux |
| 38 | 38 | subdir-$(CONFIG_DTC) += dtc |
| 39 | +subdir-$(CONFIG_GDB_SCRIPTS) += gdb | |
| 39 | 40 | |
| 40 | 41 | # Let clean descend into subdirs |
| 41 | 42 | subdir- += basic kconfig package |
| @@ -0,0 +1 @@ | ||
| 1 | +subdir-y := linux | |
| @@ -0,0 +1,2 @@ | ||
| 1 | +*.pyc | |
| 2 | +*.pyo | |
| @@ -0,0 +1,11 @@ | ||
| 1 | +always := gdb-scripts | |
| 2 | + | |
| 3 | +SRCTREE := $(shell cd $(srctree) && /bin/pwd) | |
| 4 | + | |
| 5 | +$(obj)/gdb-scripts: | |
| 6 | +ifneq ($(KBUILD_SRC),) | |
| 7 | + $(Q)ln -fsn $(SRCTREE)/$(obj)/*.py $(objtree)/$(obj) | |
| 8 | +endif | |
| 9 | + @: | |
| 10 | + | |
| 11 | +clean-files := *.pyc *.pyo $(if $(KBUILD_SRC),*.py) | |
| @@ -0,0 +1,135 @@ | ||
| 1 | +# | |
| 2 | +# gdb helper commands and functions for Linux kernel debugging | |
| 3 | +# | |
| 4 | +# per-cpu tools | |
| 5 | +# | |
| 6 | +# Copyright (c) Siemens AG, 2011-2013 | |
| 7 | +# | |
| 8 | +# Authors: | |
| 9 | +# Jan Kiszka <jan.kiszka@siemens.com> | |
| 10 | +# | |
| 11 | +# This work is licensed under the terms of the GNU GPL version 2. | |
| 12 | +# | |
| 13 | + | |
| 14 | +import gdb | |
| 15 | + | |
| 16 | +from linux import tasks, utils | |
| 17 | + | |
| 18 | + | |
| 19 | +MAX_CPUS = 4096 | |
| 20 | + | |
| 21 | + | |
| 22 | +def get_current_cpu(): | |
| 23 | + if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU: | |
| 24 | + return gdb.selected_thread().num - 1 | |
| 25 | + elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB: | |
| 26 | + tid = gdb.selected_thread().ptid[2] | |
| 27 | + if tid > (0x100000000 - MAX_CPUS - 2): | |
| 28 | + return 0x100000000 - tid - 2 | |
| 29 | + else: | |
| 30 | + return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu'] | |
| 31 | + else: | |
| 32 | + raise gdb.GdbError("Sorry, obtaining the current CPU is not yet " | |
| 33 | + "supported with this gdb server.") | |
| 34 | + | |
| 35 | + | |
| 36 | +def per_cpu(var_ptr, cpu): | |
| 37 | + if cpu == -1: | |
| 38 | + cpu = get_current_cpu() | |
| 39 | + if utils.is_target_arch("sparc:v9"): | |
| 40 | + offset = gdb.parse_and_eval( | |
| 41 | + "trap_block[{0}].__per_cpu_base".format(str(cpu))) | |
| 42 | + else: | |
| 43 | + try: | |
| 44 | + offset = gdb.parse_and_eval( | |
| 45 | + "__per_cpu_offset[{0}]".format(str(cpu))) | |
| 46 | + except gdb.error: | |
| 47 | + # !CONFIG_SMP case | |
| 48 | + offset = 0 | |
| 49 | + pointer = var_ptr.cast(utils.get_long_type()) + offset | |
| 50 | + return pointer.cast(var_ptr.type).dereference() | |
| 51 | + | |
| 52 | + | |
| 53 | +cpu_mask = {} | |
| 54 | + | |
| 55 | + | |
| 56 | +def cpu_mask_invalidate(event): | |
| 57 | + global cpu_mask | |
| 58 | + cpu_mask = {} | |
| 59 | + gdb.events.stop.disconnect(cpu_mask_invalidate) | |
| 60 | + if hasattr(gdb.events, 'new_objfile'): | |
| 61 | + gdb.events.new_objfile.disconnect(cpu_mask_invalidate) | |
| 62 | + | |
| 63 | + | |
| 64 | +def cpu_list(mask_name): | |
| 65 | + global cpu_mask | |
| 66 | + mask = None | |
| 67 | + if mask_name in cpu_mask: | |
| 68 | + mask = cpu_mask[mask_name] | |
| 69 | + if mask is None: | |
| 70 | + mask = gdb.parse_and_eval(mask_name + ".bits") | |
| 71 | + if hasattr(gdb, 'events'): | |
| 72 | + cpu_mask[mask_name] = mask | |
| 73 | + gdb.events.stop.connect(cpu_mask_invalidate) | |
| 74 | + if hasattr(gdb.events, 'new_objfile'): | |
| 75 | + gdb.events.new_objfile.connect(cpu_mask_invalidate) | |
| 76 | + bits_per_entry = mask[0].type.sizeof * 8 | |
| 77 | + num_entries = mask.type.sizeof * 8 / bits_per_entry | |
| 78 | + entry = -1 | |
| 79 | + bits = 0 | |
| 80 | + | |
| 81 | + while True: | |
| 82 | + while bits == 0: | |
| 83 | + entry += 1 | |
| 84 | + if entry == num_entries: | |
| 85 | + return | |
| 86 | + bits = mask[entry] | |
| 87 | + if bits != 0: | |
| 88 | + bit = 0 | |
| 89 | + break | |
| 90 | + | |
| 91 | + while bits & 1 == 0: | |
| 92 | + bits >>= 1 | |
| 93 | + bit += 1 | |
| 94 | + | |
| 95 | + cpu = entry * bits_per_entry + bit | |
| 96 | + | |
| 97 | + bits >>= 1 | |
| 98 | + bit += 1 | |
| 99 | + | |
| 100 | + yield cpu | |
| 101 | + | |
| 102 | + | |
| 103 | +class PerCpu(gdb.Function): | |
| 104 | + """Return per-cpu variable. | |
| 105 | + | |
| 106 | +$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the | |
| 107 | +given CPU number. If CPU is omitted, the CPU of the current context is used. | |
| 108 | +Note that VAR has to be quoted as string.""" | |
| 109 | + | |
| 110 | + def __init__(self): | |
| 111 | + super(PerCpu, self).__init__("lx_per_cpu") | |
| 112 | + | |
| 113 | + def invoke(self, var_name, cpu=-1): | |
| 114 | + var_ptr = gdb.parse_and_eval("&" + var_name.string()) | |
| 115 | + return per_cpu(var_ptr, cpu) | |
| 116 | + | |
| 117 | + | |
| 118 | +PerCpu() | |
| 119 | + | |
| 120 | + | |
| 121 | +class LxCurrentFunc(gdb.Function): | |
| 122 | + """Return current task. | |
| 123 | + | |
| 124 | +$lx_current([CPU]): Return the per-cpu task variable for the given CPU | |
| 125 | +number. If CPU is omitted, the CPU of the current context is used.""" | |
| 126 | + | |
| 127 | + def __init__(self): | |
| 128 | + super(LxCurrentFunc, self).__init__("lx_current") | |
| 129 | + | |
| 130 | + def invoke(self, cpu=-1): | |
| 131 | + var_ptr = gdb.parse_and_eval("¤t_task") | |
| 132 | + return per_cpu(var_ptr, cpu).dereference() | |
| 133 | + | |
| 134 | + | |
| 135 | +LxCurrentFunc() | |
| @@ -0,0 +1,65 @@ | ||
| 1 | +# | |
| 2 | +# gdb helper commands and functions for Linux kernel debugging | |
| 3 | +# | |
| 4 | +# kernel log buffer dump | |
| 5 | +# | |
| 6 | +# Copyright (c) Siemens AG, 2011, 2012 | |
| 7 | +# | |
| 8 | +# Authors: | |
| 9 | +# Jan Kiszka <jan.kiszka@siemens.com> | |
| 10 | +# | |
| 11 | +# This work is licensed under the terms of the GNU GPL version 2. | |
| 12 | +# | |
| 13 | + | |
| 14 | +import gdb | |
| 15 | +import string | |
| 16 | + | |
| 17 | +from linux import utils | |
| 18 | + | |
| 19 | + | |
| 20 | +class LxDmesg(gdb.Command): | |
| 21 | + """Print Linux kernel log buffer.""" | |
| 22 | + | |
| 23 | + def __init__(self): | |
| 24 | + super(LxDmesg, self).__init__("lx-dmesg", gdb.COMMAND_DATA) | |
| 25 | + | |
| 26 | + def invoke(self, arg, from_tty): | |
| 27 | + log_buf_addr = int(str(gdb.parse_and_eval("log_buf")).split()[0], 16) | |
| 28 | + log_first_idx = int(gdb.parse_and_eval("log_first_idx")) | |
| 29 | + log_next_idx = int(gdb.parse_and_eval("log_next_idx")) | |
| 30 | + log_buf_len = int(gdb.parse_and_eval("log_buf_len")) | |
| 31 | + | |
| 32 | + inf = gdb.inferiors()[0] | |
| 33 | + start = log_buf_addr + log_first_idx | |
| 34 | + if log_first_idx < log_next_idx: | |
| 35 | + log_buf_2nd_half = -1 | |
| 36 | + length = log_next_idx - log_first_idx | |
| 37 | + log_buf = inf.read_memory(start, length) | |
| 38 | + else: | |
| 39 | + log_buf_2nd_half = log_buf_len - log_first_idx | |
| 40 | + log_buf = inf.read_memory(start, log_buf_2nd_half) + \ | |
| 41 | + inf.read_memory(log_buf_addr, log_next_idx) | |
| 42 | + | |
| 43 | + pos = 0 | |
| 44 | + while pos < log_buf.__len__(): | |
| 45 | + length = utils.read_u16(log_buf[pos + 8:pos + 10]) | |
| 46 | + if length == 0: | |
| 47 | + if log_buf_2nd_half == -1: | |
| 48 | + gdb.write("Corrupted log buffer!\n") | |
| 49 | + break | |
| 50 | + pos = log_buf_2nd_half | |
| 51 | + continue | |
| 52 | + | |
| 53 | + text_len = utils.read_u16(log_buf[pos + 10:pos + 12]) | |
| 54 | + text = log_buf[pos + 16:pos + 16 + text_len] | |
| 55 | + time_stamp = utils.read_u64(log_buf[pos:pos + 8]) | |
| 56 | + | |
| 57 | + for line in memoryview(text).tobytes().splitlines(): | |
| 58 | + gdb.write("[{time:12.6f}] {line}\n".format( | |
| 59 | + time=time_stamp / 1000000000.0, | |
| 60 | + line=line)) | |
| 61 | + | |
| 62 | + pos += length | |
| 63 | + | |
| 64 | + | |
| 65 | +LxDmesg() | |
| @@ -0,0 +1,103 @@ | ||
| 1 | +# | |
| 2 | +# gdb helper commands and functions for Linux kernel debugging | |
| 3 | +# | |
| 4 | +# module tools | |
| 5 | +# | |
| 6 | +# Copyright (c) Siemens AG, 2013 | |
| 7 | +# | |
| 8 | +# Authors: | |
| 9 | +# Jan Kiszka <jan.kiszka@siemens.com> | |
| 10 | +# | |
| 11 | +# This work is licensed under the terms of the GNU GPL version 2. | |
| 12 | +# | |
| 13 | + | |
| 14 | +import gdb | |
| 15 | + | |
| 16 | +from linux import cpus, utils | |
| 17 | + | |
| 18 | + | |
| 19 | +module_type = utils.CachedType("struct module") | |
| 20 | + | |
| 21 | + | |
| 22 | +def module_list(): | |
| 23 | + global module_type | |
| 24 | + module_ptr_type = module_type.get_type().pointer() | |
| 25 | + modules = gdb.parse_and_eval("modules") | |
| 26 | + entry = modules['next'] | |
| 27 | + end_of_list = modules.address | |
| 28 | + | |
| 29 | + while entry != end_of_list: | |
| 30 | + yield utils.container_of(entry, module_ptr_type, "list") | |
| 31 | + entry = entry['next'] | |
| 32 | + | |
| 33 | + | |
| 34 | +def find_module_by_name(name): | |
| 35 | + for module in module_list(): | |
| 36 | + if module['name'].string() == name: | |
| 37 | + return module | |
| 38 | + return None | |
| 39 | + | |
| 40 | + | |
| 41 | +class LxModule(gdb.Function): | |
| 42 | + """Find module by name and return the module variable. | |
| 43 | + | |
| 44 | +$lx_module("MODULE"): Given the name MODULE, iterate over all loaded modules | |
| 45 | +of the target and return that module variable which MODULE matches.""" | |
| 46 | + | |
| 47 | + def __init__(self): | |
| 48 | + super(LxModule, self).__init__("lx_module") | |
| 49 | + | |
| 50 | + def invoke(self, mod_name): | |
| 51 | + mod_name = mod_name.string() | |
| 52 | + module = find_module_by_name(mod_name) | |
| 53 | + if module: | |
| 54 | + return module.dereference() | |
| 55 | + else: | |
| 56 | + raise gdb.GdbError("Unable to find MODULE " + mod_name) | |
| 57 | + | |
| 58 | + | |
| 59 | +LxModule() | |
| 60 | + | |
| 61 | + | |
| 62 | +class LxLsmod(gdb.Command): | |
| 63 | + """List currently loaded modules.""" | |
| 64 | + | |
| 65 | + _module_use_type = utils.CachedType("struct module_use") | |
| 66 | + | |
| 67 | + def __init__(self): | |
| 68 | + super(LxLsmod, self).__init__("lx-lsmod", gdb.COMMAND_DATA) | |
| 69 | + | |
| 70 | + def invoke(self, arg, from_tty): | |
| 71 | + gdb.write( | |
| 72 | + "Address{0} Module Size Used by\n".format( | |
| 73 | + " " if utils.get_long_type().sizeof == 8 else "")) | |
| 74 | + | |
| 75 | + for module in module_list(): | |
| 76 | + ref = 0 | |
| 77 | + module_refptr = module['refptr'] | |
| 78 | + for cpu in cpus.cpu_list("cpu_possible_mask"): | |
| 79 | + refptr = cpus.per_cpu(module_refptr, cpu) | |
| 80 | + ref += refptr['incs'] | |
| 81 | + ref -= refptr['decs'] | |
| 82 | + | |
| 83 | + gdb.write("{address} {name:<19} {size:>8} {ref}".format( | |
| 84 | + address=str(module['module_core']).split()[0], | |
| 85 | + name=module['name'].string(), | |
| 86 | + size=str(module['core_size']), | |
| 87 | + ref=str(ref))) | |
| 88 | + | |
| 89 | + source_list = module['source_list'] | |
| 90 | + t = self._module_use_type.get_type().pointer() | |
| 91 | + entry = source_list['next'] | |
| 92 | + first = True | |
| 93 | + while entry != source_list.address: | |
| 94 | + use = utils.container_of(entry, t, "source_list") | |
| 95 | + gdb.write("{separator}{name}".format( | |
| 96 | + separator=" " if first else ",", | |
| 97 | + name=use['source']['name'].string())) | |
| 98 | + first = False | |
| 99 | + entry = entry['next'] | |
| 100 | + gdb.write("\n") | |
| 101 | + | |
| 102 | + | |
| 103 | +LxLsmod() | |
| @@ -0,0 +1,177 @@ | ||
| 1 | +# | |
| 2 | +# gdb helper commands and functions for Linux kernel debugging | |
| 3 | +# | |
| 4 | +# load kernel and module symbols | |
| 5 | +# | |
| 6 | +# Copyright (c) Siemens AG, 2011-2013 | |
| 7 | +# | |
| 8 | +# Authors: | |
| 9 | +# Jan Kiszka <jan.kiszka@siemens.com> | |
| 10 | +# | |
| 11 | +# This work is licensed under the terms of the GNU GPL version 2. | |
| 12 | +# | |
| 13 | + | |
| 14 | +import gdb | |
| 15 | +import os | |
| 16 | +import re | |
| 17 | +import string | |
| 18 | + | |
| 19 | +from linux import modules, utils | |
| 20 | + | |
| 21 | + | |
| 22 | +if hasattr(gdb, 'Breakpoint'): | |
| 23 | + class LoadModuleBreakpoint(gdb.Breakpoint): | |
| 24 | + def __init__(self, spec, gdb_command): | |
| 25 | + super(LoadModuleBreakpoint, self).__init__(spec, internal=True) | |
| 26 | + self.silent = True | |
| 27 | + self.gdb_command = gdb_command | |
| 28 | + | |
| 29 | + def stop(self): | |
| 30 | + module = gdb.parse_and_eval("mod") | |
| 31 | + module_name = module['name'].string() | |
| 32 | + cmd = self.gdb_command | |
| 33 | + | |
| 34 | + # enforce update if object file is not found | |
| 35 | + cmd.module_files_updated = False | |
| 36 | + | |
| 37 | + # Disable pagination while reporting symbol (re-)loading. | |
| 38 | + # The console input is blocked in this context so that we would | |
| 39 | + # get stuck waiting for the user to acknowledge paged output. | |
| 40 | + show_pagination = gdb.execute("show pagination", to_string=True) | |
| 41 | + pagination = show_pagination.endswith("on.\n") | |
| 42 | + gdb.execute("set pagination off") | |
| 43 | + | |
| 44 | + if module_name in cmd.loaded_modules: | |
| 45 | + gdb.write("refreshing all symbols to reload module " | |
| 46 | + "'{0}'\n".format(module_name)) | |
| 47 | + cmd.load_all_symbols() | |
| 48 | + else: | |
| 49 | + cmd.load_module_symbols(module) | |
| 50 | + | |
| 51 | + # restore pagination state | |
| 52 | + gdb.execute("set pagination %s" % ("on" if pagination else "off")) | |
| 53 | + | |
| 54 | + return False | |
| 55 | + | |
| 56 | + | |
| 57 | +class LxSymbols(gdb.Command): | |
| 58 | + """(Re-)load symbols of Linux kernel and currently loaded modules. | |
| 59 | + | |
| 60 | +The kernel (vmlinux) is taken from the current working directly. Modules (.ko) | |
| 61 | +are scanned recursively, starting in the same directory. Optionally, the module | |
| 62 | +search path can be extended by a space separated list of paths passed to the | |
| 63 | +lx-symbols command.""" | |
| 64 | + | |
| 65 | + module_paths = [] | |
| 66 | + module_files = [] | |
| 67 | + module_files_updated = False | |
| 68 | + loaded_modules = [] | |
| 69 | + breakpoint = None | |
| 70 | + | |
| 71 | + def __init__(self): | |
| 72 | + super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES, | |
| 73 | + gdb.COMPLETE_FILENAME) | |
| 74 | + | |
| 75 | + def _update_module_files(self): | |
| 76 | + self.module_files = [] | |
| 77 | + for path in self.module_paths: | |
| 78 | + gdb.write("scanning for modules in {0}\n".format(path)) | |
| 79 | + for root, dirs, files in os.walk(path): | |
| 80 | + for name in files: | |
| 81 | + if name.endswith(".ko"): | |
| 82 | + self.module_files.append(root + "/" + name) | |
| 83 | + self.module_files_updated = True | |
| 84 | + | |
| 85 | + def _get_module_file(self, module_name): | |
| 86 | + module_pattern = ".*/{0}\.ko$".format( | |
| 87 | + module_name.replace("_", r"[_\-]")) | |
| 88 | + for name in self.module_files: | |
| 89 | + if re.match(module_pattern, name) and os.path.exists(name): | |
| 90 | + return name | |
| 91 | + return None | |
| 92 | + | |
| 93 | + def _section_arguments(self, module): | |
| 94 | + try: | |
| 95 | + sect_attrs = module['sect_attrs'].dereference() | |
| 96 | + except gdb.error: | |
| 97 | + return "" | |
| 98 | + attrs = sect_attrs['attrs'] | |
| 99 | + section_name_to_address = { | |
| 100 | + attrs[n]['name'].string() : attrs[n]['address'] | |
| 101 | + for n in range(int(sect_attrs['nsections']))} | |
| 102 | + args = [] | |
| 103 | + for section_name in [".data", ".data..read_mostly", ".rodata", ".bss"]: | |
| 104 | + address = section_name_to_address.get(section_name) | |
| 105 | + if address: | |
| 106 | + args.append(" -s {name} {addr}".format( | |
| 107 | + name=section_name, addr=str(address))) | |
| 108 | + return "".join(args) | |
| 109 | + | |
| 110 | + def load_module_symbols(self, module): | |
| 111 | + module_name = module['name'].string() | |
| 112 | + module_addr = str(module['module_core']).split()[0] | |
| 113 | + | |
| 114 | + module_file = self._get_module_file(module_name) | |
| 115 | + if not module_file and not self.module_files_updated: | |
| 116 | + self._update_module_files() | |
| 117 | + module_file = self._get_module_file(module_name) | |
| 118 | + | |
| 119 | + if module_file: | |
| 120 | + gdb.write("loading @{addr}: {filename}\n".format( | |
| 121 | + addr=module_addr, filename=module_file)) | |
| 122 | + cmdline = "add-symbol-file {filename} {addr}{sections}".format( | |
| 123 | + filename=module_file, | |
| 124 | + addr=module_addr, | |
| 125 | + sections=self._section_arguments(module)) | |
| 126 | + gdb.execute(cmdline, to_string=True) | |
| 127 | + if not module_name in self.loaded_modules: | |
| 128 | + self.loaded_modules.append(module_name) | |
| 129 | + else: | |
| 130 | + gdb.write("no module object found for '{0}'\n".format(module_name)) | |
| 131 | + | |
| 132 | + def load_all_symbols(self): | |
| 133 | + gdb.write("loading vmlinux\n") | |
| 134 | + | |
| 135 | + # Dropping symbols will disable all breakpoints. So save their states | |
| 136 | + # and restore them afterward. | |
| 137 | + saved_states = [] | |
| 138 | + if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None: | |
| 139 | + for bp in gdb.breakpoints(): | |
| 140 | + saved_states.append({'breakpoint': bp, 'enabled': bp.enabled}) | |
| 141 | + | |
| 142 | + # drop all current symbols and reload vmlinux | |
| 143 | + gdb.execute("symbol-file", to_string=True) | |
| 144 | + gdb.execute("symbol-file vmlinux") | |
| 145 | + | |
| 146 | + self.loaded_modules = [] | |
| 147 | + module_list = modules.module_list() | |
| 148 | + if not module_list: | |
| 149 | + gdb.write("no modules found\n") | |
| 150 | + else: | |
| 151 | + [self.load_module_symbols(module) for module in module_list] | |
| 152 | + | |
| 153 | + for saved_state in saved_states: | |
| 154 | + saved_state['breakpoint'].enabled = saved_state['enabled'] | |
| 155 | + | |
| 156 | + def invoke(self, arg, from_tty): | |
| 157 | + self.module_paths = arg.split() | |
| 158 | + self.module_paths.append(os.getcwd()) | |
| 159 | + | |
| 160 | + # enforce update | |
| 161 | + self.module_files = [] | |
| 162 | + self.module_files_updated = False | |
| 163 | + | |
| 164 | + self.load_all_symbols() | |
| 165 | + | |
| 166 | + if hasattr(gdb, 'Breakpoint'): | |
| 167 | + if not self.breakpoint is None: | |
| 168 | + self.breakpoint.delete() | |
| 169 | + self.breakpoint = None | |
| 170 | + self.breakpoint = LoadModuleBreakpoint( | |
| 171 | + "kernel/module.c:do_init_module", self) | |
| 172 | + else: | |
| 173 | + gdb.write("Note: symbol update on module loading not supported " | |
| 174 | + "with this gdb version\n") | |
| 175 | + | |
| 176 | + | |
| 177 | +LxSymbols() | |
| @@ -0,0 +1,100 @@ | ||
| 1 | +# | |
| 2 | +# gdb helper commands and functions for Linux kernel debugging | |
| 3 | +# | |
| 4 | +# task & thread tools | |
| 5 | +# | |
| 6 | +# Copyright (c) Siemens AG, 2011-2013 | |
| 7 | +# | |
| 8 | +# Authors: | |
| 9 | +# Jan Kiszka <jan.kiszka@siemens.com> | |
| 10 | +# | |
| 11 | +# This work is licensed under the terms of the GNU GPL version 2. | |
| 12 | +# | |
| 13 | + | |
| 14 | +import gdb | |
| 15 | + | |
| 16 | +from linux import utils | |
| 17 | + | |
| 18 | + | |
| 19 | +task_type = utils.CachedType("struct task_struct") | |
| 20 | + | |
| 21 | +def task_lists(): | |
| 22 | + global task_type | |
| 23 | + task_ptr_type = task_type.get_type().pointer() | |
| 24 | + init_task = gdb.parse_and_eval("init_task").address | |
| 25 | + t = g = init_task | |
| 26 | + | |
| 27 | + while True: | |
| 28 | + while True: | |
| 29 | + yield t | |
| 30 | + | |
| 31 | + t = utils.container_of(t['thread_group']['next'], | |
| 32 | + task_ptr_type, "thread_group") | |
| 33 | + if t == g: | |
| 34 | + break | |
| 35 | + | |
| 36 | + t = g = utils.container_of(g['tasks']['next'], | |
| 37 | + task_ptr_type, "tasks") | |
| 38 | + if t == init_task: | |
| 39 | + return | |
| 40 | + | |
| 41 | +def get_task_by_pid(pid): | |
| 42 | + for task in task_lists(): | |
| 43 | + if int(task['pid']) == pid: | |
| 44 | + return task | |
| 45 | + return None | |
| 46 | + | |
| 47 | + | |
| 48 | +class LxTaskByPidFunc(gdb.Function): | |
| 49 | + """Find Linux task by PID and return the task_struct variable. | |
| 50 | + | |
| 51 | +$lx_task_by_pid(PID): Given PID, iterate over all tasks of the target and | |
| 52 | +return that task_struct variable which PID matches.""" | |
| 53 | + | |
| 54 | + def __init__(self): | |
| 55 | + super(LxTaskByPidFunc, self).__init__("lx_task_by_pid") | |
| 56 | + | |
| 57 | + def invoke(self, pid): | |
| 58 | + task = get_task_by_pid(pid) | |
| 59 | + if task: | |
| 60 | + return task.dereference() | |
| 61 | + else: | |
| 62 | + raise gdb.GdbError("No task of PID " + str(pid)) | |
| 63 | + | |
| 64 | + | |
| 65 | +LxTaskByPidFunc() | |
| 66 | + | |
| 67 | + | |
| 68 | +thread_info_type = utils.CachedType("struct thread_info") | |
| 69 | + | |
| 70 | +ia64_task_size = None | |
| 71 | + | |
| 72 | + | |
| 73 | +def get_thread_info(task): | |
| 74 | + global thread_info_type | |
| 75 | + thread_info_ptr_type = thread_info_type.get_type().pointer() | |
| 76 | + if utils.is_target_arch("ia64"): | |
| 77 | + global ia64_task_size | |
| 78 | + if ia64_task_size is None: | |
| 79 | + ia64_task_size = gdb.parse_and_eval("sizeof(struct task_struct)") | |
| 80 | + thread_info_addr = task.address + ia64_task_size | |
| 81 | + thread_info = thread_info_addr.cast(thread_info_ptr_type) | |
| 82 | + else: | |
| 83 | + thread_info = task['stack'].cast(thread_info_ptr_type) | |
| 84 | + return thread_info.dereference() | |
| 85 | + | |
| 86 | + | |
| 87 | +class LxThreadInfoFunc (gdb.Function): | |
| 88 | + """Calculate Linux thread_info from task variable. | |
| 89 | + | |
| 90 | +$lx_thread_info(TASK): Given TASK, return the corresponding thread_info | |
| 91 | +variable.""" | |
| 92 | + | |
| 93 | + def __init__(self): | |
| 94 | + super(LxThreadInfoFunc, self).__init__("lx_thread_info") | |
| 95 | + | |
| 96 | + def invoke(self, task): | |
| 97 | + return get_thread_info(task) | |
| 98 | + | |
| 99 | + | |
| 100 | +LxThreadInfoFunc() | |
| @@ -0,0 +1,156 @@ | ||
| 1 | +# | |
| 2 | +# gdb helper commands and functions for Linux kernel debugging | |
| 3 | +# | |
| 4 | +# common utilities | |
| 5 | +# | |
| 6 | +# Copyright (c) Siemens AG, 2011-2013 | |
| 7 | +# | |
| 8 | +# Authors: | |
| 9 | +# Jan Kiszka <jan.kiszka@siemens.com> | |
| 10 | +# | |
| 11 | +# This work is licensed under the terms of the GNU GPL version 2. | |
| 12 | +# | |
| 13 | + | |
| 14 | +import gdb | |
| 15 | + | |
| 16 | + | |
| 17 | +class CachedType: | |
| 18 | + def __init__(self, name): | |
| 19 | + self._type = None | |
| 20 | + self._name = name | |
| 21 | + | |
| 22 | + def _new_objfile_handler(self, event): | |
| 23 | + self._type = None | |
| 24 | + gdb.events.new_objfile.disconnect(self._new_objfile_handler) | |
| 25 | + | |
| 26 | + def get_type(self): | |
| 27 | + if self._type is None: | |
| 28 | + self._type = gdb.lookup_type(self._name) | |
| 29 | + if self._type is None: | |
| 30 | + raise gdb.GdbError( | |
| 31 | + "cannot resolve type '{0}'".format(self._name)) | |
| 32 | + if hasattr(gdb, 'events') and hasattr(gdb.events, 'new_objfile'): | |
| 33 | + gdb.events.new_objfile.connect(self._new_objfile_handler) | |
| 34 | + return self._type | |
| 35 | + | |
| 36 | + | |
| 37 | +long_type = CachedType("long") | |
| 38 | + | |
| 39 | + | |
| 40 | +def get_long_type(): | |
| 41 | + global long_type | |
| 42 | + return long_type.get_type() | |
| 43 | + | |
| 44 | + | |
| 45 | +def offset_of(typeobj, field): | |
| 46 | + element = gdb.Value(0).cast(typeobj) | |
| 47 | + return int(str(element[field].address).split()[0], 16) | |
| 48 | + | |
| 49 | + | |
| 50 | +def container_of(ptr, typeobj, member): | |
| 51 | + return (ptr.cast(get_long_type()) - | |
| 52 | + offset_of(typeobj, member)).cast(typeobj) | |
| 53 | + | |
| 54 | + | |
| 55 | +class ContainerOf(gdb.Function): | |
| 56 | + """Return pointer to containing data structure. | |
| 57 | + | |
| 58 | +$container_of(PTR, "TYPE", "ELEMENT"): Given PTR, return a pointer to the | |
| 59 | +data structure of the type TYPE in which PTR is the address of ELEMENT. | |
| 60 | +Note that TYPE and ELEMENT have to be quoted as strings.""" | |
| 61 | + | |
| 62 | + def __init__(self): | |
| 63 | + super(ContainerOf, self).__init__("container_of") | |
| 64 | + | |
| 65 | + def invoke(self, ptr, typename, elementname): | |
| 66 | + return container_of(ptr, gdb.lookup_type(typename.string()).pointer(), | |
| 67 | + elementname.string()) | |
| 68 | + | |
| 69 | +ContainerOf() | |
| 70 | + | |
| 71 | + | |
| 72 | +BIG_ENDIAN = 0 | |
| 73 | +LITTLE_ENDIAN = 1 | |
| 74 | +target_endianness = None | |
| 75 | + | |
| 76 | + | |
| 77 | +def get_target_endianness(): | |
| 78 | + global target_endianness | |
| 79 | + if target_endianness is None: | |
| 80 | + endian = gdb.execute("show endian", to_string=True) | |
| 81 | + if "little endian" in endian: | |
| 82 | + target_endianness = LITTLE_ENDIAN | |
| 83 | + elif "big endian" in endian: | |
| 84 | + target_endianness = BIG_ENDIAN | |
| 85 | + else: | |
| 86 | + raise gdb.GdgError("unknown endianness '{0}'".format(str(endian))) | |
| 87 | + return target_endianness | |
| 88 | + | |
| 89 | + | |
| 90 | +def read_u16(buffer): | |
| 91 | + if get_target_endianness() == LITTLE_ENDIAN: | |
| 92 | + return ord(buffer[0]) + (ord(buffer[1]) << 8) | |
| 93 | + else: | |
| 94 | + return ord(buffer[1]) + (ord(buffer[0]) << 8) | |
| 95 | + | |
| 96 | + | |
| 97 | +def read_u32(buffer): | |
| 98 | + if get_target_endianness() == LITTLE_ENDIAN: | |
| 99 | + return read_u16(buffer[0:2]) + (read_u16(buffer[2:4]) << 16) | |
| 100 | + else: | |
| 101 | + return read_u16(buffer[2:4]) + (read_u16(buffer[0:2]) << 16) | |
| 102 | + | |
| 103 | + | |
| 104 | +def read_u64(buffer): | |
| 105 | + if get_target_endianness() == LITTLE_ENDIAN: | |
| 106 | + return read_u32(buffer[0:4]) + (read_u32(buffer[4:8]) << 32) | |
| 107 | + else: | |
| 108 | + return read_u32(buffer[4:8]) + (read_u32(buffer[0:4]) << 32) | |
| 109 | + | |
| 110 | + | |
| 111 | +target_arch = None | |
| 112 | + | |
| 113 | + | |
| 114 | +def is_target_arch(arch): | |
| 115 | + if hasattr(gdb.Frame, 'architecture'): | |
| 116 | + return arch in gdb.newest_frame().architecture().name() | |
| 117 | + else: | |
| 118 | + global target_arch | |
| 119 | + if target_arch is None: | |
| 120 | + target_arch = gdb.execute("show architecture", to_string=True) | |
| 121 | + return arch in target_arch | |
| 122 | + | |
| 123 | + | |
| 124 | +GDBSERVER_QEMU = 0 | |
| 125 | +GDBSERVER_KGDB = 1 | |
| 126 | +gdbserver_type = None | |
| 127 | + | |
| 128 | + | |
| 129 | +def get_gdbserver_type(): | |
| 130 | + def exit_handler(event): | |
| 131 | + global gdbserver_type | |
| 132 | + gdbserver_type = None | |
| 133 | + gdb.events.exited.disconnect(exit_handler) | |
| 134 | + | |
| 135 | + def probe_qemu(): | |
| 136 | + try: | |
| 137 | + return gdb.execute("monitor info version", to_string=True) != "" | |
| 138 | + except: | |
| 139 | + return False | |
| 140 | + | |
| 141 | + def probe_kgdb(): | |
| 142 | + try: | |
| 143 | + thread_info = gdb.execute("info thread 2", to_string=True) | |
| 144 | + return "shadowCPU0" in thread_info | |
| 145 | + except: | |
| 146 | + return False | |
| 147 | + | |
| 148 | + global gdbserver_type | |
| 149 | + if gdbserver_type is None: | |
| 150 | + if probe_qemu(): | |
| 151 | + gdbserver_type = GDBSERVER_QEMU | |
| 152 | + elif probe_kgdb(): | |
| 153 | + gdbserver_type = GDBSERVER_KGDB | |
| 154 | + if not gdbserver_type is None and hasattr(gdb, 'events'): | |
| 155 | + gdb.events.exited.connect(exit_handler) | |
| 156 | + return gdbserver_type | |
| @@ -0,0 +1,30 @@ | ||
| 1 | +# | |
| 2 | +# gdb helper commands and functions for Linux kernel debugging | |
| 3 | +# | |
| 4 | +# loader module | |
| 5 | +# | |
| 6 | +# Copyright (c) Siemens AG, 2012, 2013 | |
| 7 | +# | |
| 8 | +# Authors: | |
| 9 | +# Jan Kiszka <jan.kiszka@siemens.com> | |
| 10 | +# | |
| 11 | +# This work is licensed under the terms of the GNU GPL version 2. | |
| 12 | +# | |
| 13 | + | |
| 14 | +import os | |
| 15 | + | |
| 16 | +sys.path.insert(0, os.path.dirname(__file__) + "/scripts/gdb") | |
| 17 | + | |
| 18 | +try: | |
| 19 | + gdb.parse_and_eval("0") | |
| 20 | + gdb.execute("", to_string=True) | |
| 21 | +except: | |
| 22 | + gdb.write("NOTE: gdb 7.2 or later required for Linux helper scripts to " | |
| 23 | + "work.\n") | |
| 24 | +else: | |
| 25 | + import linux.utils | |
| 26 | + import linux.symbols | |
| 27 | + import linux.modules | |
| 28 | + import linux.dmesg | |
| 29 | + import linux.tasks | |
| 30 | + import linux.cpus | |