0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/elf.h>
0011 #include <linux/file.h>
0012 #include <linux/fdtable.h>
0013 #include <linux/fs.h>
0014 #include <linux/gfp.h>
0015 #include <linux/list.h>
0016 #include <linux/syscalls.h>
0017 #include <linux/coredump.h>
0018 #include <linux/binfmts.h>
0019
0020 #include <linux/uaccess.h>
0021
0022 #include "spufs.h"
0023
0024 static int spufs_ctx_note_size(struct spu_context *ctx, int dfd)
0025 {
0026 int i, sz, total = 0;
0027 char *name;
0028 char fullname[80];
0029
0030 for (i = 0; spufs_coredump_read[i].name != NULL; i++) {
0031 name = spufs_coredump_read[i].name;
0032 sz = spufs_coredump_read[i].size;
0033
0034 sprintf(fullname, "SPU/%d/%s", dfd, name);
0035
0036 total += sizeof(struct elf_note);
0037 total += roundup(strlen(fullname) + 1, 4);
0038 total += roundup(sz, 4);
0039 }
0040
0041 return total;
0042 }
0043
0044 static int match_context(const void *v, struct file *file, unsigned fd)
0045 {
0046 struct spu_context *ctx;
0047 if (file->f_op != &spufs_context_fops)
0048 return 0;
0049 ctx = SPUFS_I(file_inode(file))->i_ctx;
0050 if (ctx->flags & SPU_CREATE_NOSCHED)
0051 return 0;
0052 return fd + 1;
0053 }
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 static struct spu_context *coredump_next_context(int *fd)
0068 {
0069 struct spu_context *ctx;
0070 struct file *file;
0071 int n = iterate_fd(current->files, *fd, match_context, NULL);
0072 if (!n)
0073 return NULL;
0074 *fd = n - 1;
0075
0076 rcu_read_lock();
0077 file = lookup_fd_rcu(*fd);
0078 ctx = SPUFS_I(file_inode(file))->i_ctx;
0079 get_spu_context(ctx);
0080 rcu_read_unlock();
0081
0082 return ctx;
0083 }
0084
0085 int spufs_coredump_extra_notes_size(void)
0086 {
0087 struct spu_context *ctx;
0088 int size = 0, rc, fd;
0089
0090 fd = 0;
0091 while ((ctx = coredump_next_context(&fd)) != NULL) {
0092 rc = spu_acquire_saved(ctx);
0093 if (rc) {
0094 put_spu_context(ctx);
0095 break;
0096 }
0097
0098 rc = spufs_ctx_note_size(ctx, fd);
0099 spu_release_saved(ctx);
0100 if (rc < 0) {
0101 put_spu_context(ctx);
0102 break;
0103 }
0104
0105 size += rc;
0106
0107
0108 fd++;
0109 put_spu_context(ctx);
0110 }
0111
0112 return size;
0113 }
0114
0115 static int spufs_arch_write_note(struct spu_context *ctx, int i,
0116 struct coredump_params *cprm, int dfd)
0117 {
0118 size_t sz = spufs_coredump_read[i].size;
0119 char fullname[80];
0120 struct elf_note en;
0121 int ret;
0122
0123 sprintf(fullname, "SPU/%d/%s", dfd, spufs_coredump_read[i].name);
0124 en.n_namesz = strlen(fullname) + 1;
0125 en.n_descsz = sz;
0126 en.n_type = NT_SPU;
0127
0128 if (!dump_emit(cprm, &en, sizeof(en)))
0129 return -EIO;
0130 if (!dump_emit(cprm, fullname, en.n_namesz))
0131 return -EIO;
0132 if (!dump_align(cprm, 4))
0133 return -EIO;
0134
0135 if (spufs_coredump_read[i].dump) {
0136 ret = spufs_coredump_read[i].dump(ctx, cprm);
0137 if (ret < 0)
0138 return ret;
0139 } else {
0140 char buf[32];
0141
0142 ret = snprintf(buf, sizeof(buf), "0x%.16llx",
0143 spufs_coredump_read[i].get(ctx));
0144 if (ret >= sizeof(buf))
0145 return sizeof(buf);
0146
0147
0148 if (!dump_emit(cprm, buf, ret + 1))
0149 return -EIO;
0150 }
0151
0152 dump_skip_to(cprm, roundup(cprm->pos - ret + sz, 4));
0153 return 0;
0154 }
0155
0156 int spufs_coredump_extra_notes_write(struct coredump_params *cprm)
0157 {
0158 struct spu_context *ctx;
0159 int fd, j, rc;
0160
0161 fd = 0;
0162 while ((ctx = coredump_next_context(&fd)) != NULL) {
0163 rc = spu_acquire_saved(ctx);
0164 if (rc)
0165 return rc;
0166
0167 for (j = 0; spufs_coredump_read[j].name != NULL; j++) {
0168 rc = spufs_arch_write_note(ctx, j, cprm, fd);
0169 if (rc) {
0170 spu_release_saved(ctx);
0171 return rc;
0172 }
0173 }
0174
0175 spu_release_saved(ctx);
0176
0177
0178 fd++;
0179 }
0180
0181 return 0;
0182 }