xref: /linux-tools/drivers/mremap/extract.cpp (revision 74ce4ce33d5b8318cee71b38976a25818e666ff3)
1*74ce4ce3SDavid Wang #include <stdio.h>
2*74ce4ce3SDavid Wang #include <stdlib.h>
3*74ce4ce3SDavid Wang #include <unistd.h>
4*74ce4ce3SDavid Wang #include <sys/types.h>
5*74ce4ce3SDavid Wang #include <sys/wait.h>
6*74ce4ce3SDavid Wang #include <sys/ptrace.h>
7*74ce4ce3SDavid Wang #include <sys/user.h>
8*74ce4ce3SDavid Wang #include <sys/syscall.h>
9*74ce4ce3SDavid Wang #include <netinet/in.h>
10*74ce4ce3SDavid Wang #include <netinet/ip.h>
11*74ce4ce3SDavid Wang #include <errno.h>
12*74ce4ce3SDavid Wang #include <linux/elf.h>
13*74ce4ce3SDavid Wang #include <sys/user.h>
14*74ce4ce3SDavid Wang #include <string.h>
15*74ce4ce3SDavid Wang 
16*74ce4ce3SDavid Wang #include <set>
17*74ce4ce3SDavid Wang #include <vector>
18*74ce4ce3SDavid Wang #include <string>
19*74ce4ce3SDavid Wang using namespace std;
20*74ce4ce3SDavid Wang 
21*74ce4ce3SDavid Wang #define exiterr(err, msg) do{ if(err<0) { perror(msg); exit(1); }} while(0)
22*74ce4ce3SDavid Wang 
23*74ce4ce3SDavid Wang 
24*74ce4ce3SDavid Wang char ibuf[1024*8];
25*74ce4ce3SDavid Wang typedef struct {
26*74ce4ce3SDavid Wang     unsigned long long start, end, offset;
27*74ce4ce3SDavid Wang     char mode;
28*74ce4ce3SDavid Wang     string name;
29*74ce4ce3SDavid Wang } MNode;
30*74ce4ce3SDavid Wang char ns[1024*8];
31*74ce4ce3SDavid Wang char vmk[128];
load_maps(int pid)32*74ce4ce3SDavid Wang vector<MNode>* load_maps(int pid) {
33*74ce4ce3SDavid Wang     sprintf(ibuf, "/proc/%d/maps", pid);
34*74ce4ce3SDavid Wang     FILE *fp = fopen(ibuf, "r");
35*74ce4ce3SDavid Wang     char addrs[64], mode[8], offs[16], dev[16];
36*74ce4ce3SDavid Wang     long long inode;
37*74ce4ce3SDavid Wang     unsigned long long start, end, offset;
38*74ce4ce3SDavid Wang     MNode nn;
39*74ce4ce3SDavid Wang     int i, j, k;
40*74ce4ce3SDavid Wang     char m, *p;
41*74ce4ce3SDavid Wang     if (fp==NULL) return NULL;
42*74ce4ce3SDavid Wang     vector<MNode>* ms = new vector<MNode>();
43*74ce4ce3SDavid Wang     while(1) {
44*74ce4ce3SDavid Wang         p = fgets(ibuf, sizeof(ibuf), fp); if (p==NULL) break;
45*74ce4ce3SDavid Wang         k = sscanf(p, "%s %s %s %s %lld %s", addrs, mode, offs, dev, &inode, ns);
46*74ce4ce3SDavid Wang         if (k<5) continue;
47*74ce4ce3SDavid Wang         start=end=offset=0;
48*74ce4ce3SDavid Wang         i=0; while(addrs[i]&&addrs[i]!='-') {
49*74ce4ce3SDavid Wang             if (vmk[addrs[i]]==-1) break;
50*74ce4ce3SDavid Wang             start=start*16+vmk[addrs[i]];
51*74ce4ce3SDavid Wang             i++;
52*74ce4ce3SDavid Wang         } if (i==0||addrs[i]!='-') continue;
53*74ce4ce3SDavid Wang         j=i+1; while(addrs[j]) {
54*74ce4ce3SDavid Wang             if (vmk[addrs[j]]==-1) break;
55*74ce4ce3SDavid Wang             end = end*16+vmk[addrs[j]];
56*74ce4ce3SDavid Wang             j++;
57*74ce4ce3SDavid Wang         } if (j==i+1||addrs[j]!=0) continue;
58*74ce4ce3SDavid Wang         i=0; while(offs[i]) {
59*74ce4ce3SDavid Wang             if (vmk[offs[i]]==-1) break;
60*74ce4ce3SDavid Wang             offset = offset*16+vmk[offs[i]];
61*74ce4ce3SDavid Wang             i++;
62*74ce4ce3SDavid Wang         } if (i==0||offs[i]!=0) continue;
63*74ce4ce3SDavid Wang         m=0; for (i=0; i<4; i++) if (mode[i]!='-') m|=(1<<i);
64*74ce4ce3SDavid Wang         nn.start=start;
65*74ce4ce3SDavid Wang         nn.end = end;
66*74ce4ce3SDavid Wang         nn.mode=m;
67*74ce4ce3SDavid Wang         nn.offset = offset;
68*74ce4ce3SDavid Wang         if (k==5) {
69*74ce4ce3SDavid Wang             nn.name = string();
70*74ce4ce3SDavid Wang         } else if (k==6) {
71*74ce4ce3SDavid Wang             // skip [vvar]
72*74ce4ce3SDavid Wang             i=0; while(ns[i]) i++;
73*74ce4ce3SDavid Wang             while(i>0&&ns[i-1]!='/') i--;
74*74ce4ce3SDavid Wang             nn.name = string(ns+i);
75*74ce4ce3SDavid Wang         }
76*74ce4ce3SDavid Wang         ms->push_back(nn);
77*74ce4ce3SDavid Wang     }
78*74ce4ce3SDavid Wang     fclose(fp);
79*74ce4ce3SDavid Wang     return ms;
80*74ce4ce3SDavid Wang }
81*74ce4ce3SDavid Wang 
82*74ce4ce3SDavid Wang char buf[1024*1024];
83*74ce4ce3SDavid Wang typedef struct {
84*74ce4ce3SDavid Wang     int regset;
85*74ce4ce3SDavid Wang     size_t size;
86*74ce4ce3SDavid Wang     unsigned long offset;
87*74ce4ce3SDavid Wang } RegHNode;
88*74ce4ce3SDavid Wang typedef struct {
89*74ce4ce3SDavid Wang     unsigned long start, end, offset;
90*74ce4ce3SDavid Wang     unsigned long noffset, doffset;
91*74ce4ce3SDavid Wang     size_t nlen, dsize;
92*74ce4ce3SDavid Wang     unsigned int mode;
93*74ce4ce3SDavid Wang } MapHNode;
94*74ce4ce3SDavid Wang 
95*74ce4ce3SDavid Wang int regset_ids[] = { NT_PRSTATUS, NT_PRFPREG, NT_PRPSINFO, NT_TASKSTRUCT, NT_AUXV, -1 };
96*74ce4ce3SDavid Wang 
map_copy(FILE * out,FILE * mem,unsigned long long start,unsigned long long size)97*74ce4ce3SDavid Wang int map_copy(FILE* out, FILE* mem, unsigned long long start, unsigned long long size) {
98*74ce4ce3SDavid Wang     int r;
99*74ce4ce3SDavid Wang     size_t n, rn=0;
100*74ce4ce3SDavid Wang     r = fseek(mem, start, SEEK_SET);
101*74ce4ce3SDavid Wang     if (r!=0) return r;
102*74ce4ce3SDavid Wang     while(size) {
103*74ce4ce3SDavid Wang         n = fread(ibuf, 1, sizeof(ibuf), mem); if (n==0) {
104*74ce4ce3SDavid Wang             printf("not enough file to read, left %d/%lld\n", n, size);
105*74ce4ce3SDavid Wang             break;
106*74ce4ce3SDavid Wang         }
107*74ce4ce3SDavid Wang         if (n>size) n=size;
108*74ce4ce3SDavid Wang         fwrite(ibuf, 1, n, out);
109*74ce4ce3SDavid Wang         size-=n;
110*74ce4ce3SDavid Wang         rn+=n;
111*74ce4ce3SDavid Wang     }
112*74ce4ce3SDavid Wang     return rn;
113*74ce4ce3SDavid Wang }
114*74ce4ce3SDavid Wang 
main(int argc,char * argv[])115*74ce4ce3SDavid Wang int main(int argc, char *argv[]) {
116*74ce4ce3SDavid Wang     int pid, err, status, x, i, z, n;
117*74ce4ce3SDavid Wang     unsigned long offset, hlen, dlen;
118*74ce4ce3SDavid Wang     // struct user_regs_struct regs;
119*74ce4ce3SDavid Wang     struct iovec regset;
120*74ce4ce3SDavid Wang     struct user userinfo;
121*74ce4ce3SDavid Wang     unsigned long *tp, vw, rn;
122*74ce4ce3SDavid Wang     if (argc<2) { printf("need pid\n"); return 1; }
123*74ce4ce3SDavid Wang     pid = atoi(argv[1]);
124*74ce4ce3SDavid Wang     if (pid<=0) { printf("invalid pid %s\n", argv[1]); return 1; }
125*74ce4ce3SDavid Wang     err = ptrace(PTRACE_ATTACH, pid, 0, 0);
126*74ce4ce3SDavid Wang     exiterr(err, "fail to attach");
127*74ce4ce3SDavid Wang     printf("attached with %d\n", pid);
128*74ce4ce3SDavid Wang     x = waitpid(-1, &status, __WALL);
129*74ce4ce3SDavid Wang     if (x != pid) {
130*74ce4ce3SDavid Wang         printf("expect pid %d, got %d\n", pid, x);
131*74ce4ce3SDavid Wang         return 1;
132*74ce4ce3SDavid Wang     }
133*74ce4ce3SDavid Wang     FILE *fp_header=NULL, *fp_binary=NULL, *fp_mem=NULL;
134*74ce4ce3SDavid Wang     RegHNode regset_header;
135*74ce4ce3SDavid Wang     vector<MNode>* mp = NULL;
136*74ce4ce3SDavid Wang     sprintf(ibuf, "/proc/%d/mem", pid);
137*74ce4ce3SDavid Wang     fp_mem = fopen(ibuf, "rb"); if (fp_mem==NULL) goto out;
138*74ce4ce3SDavid Wang     fp_header = fopen("./spirity.header", "wb"); if (fp_header==NULL) goto out;
139*74ce4ce3SDavid Wang     fp_binary = fopen("./spirity.binary", "wb"); if (fp_binary==NULL) goto out;
140*74ce4ce3SDavid Wang     // load user
141*74ce4ce3SDavid Wang     tp = (unsigned long*)&userinfo;
142*74ce4ce3SDavid Wang     for (i=0; i<sizeof(userinfo); i+=8) {
143*74ce4ce3SDavid Wang         errno = 0;
144*74ce4ce3SDavid Wang         vw = ptrace(PTRACE_PEEKUSER, pid, i, 0);
145*74ce4ce3SDavid Wang         if (errno) {
146*74ce4ce3SDavid Wang             printf("only read %d userinfo --> %ld\n", i, vw);
147*74ce4ce3SDavid Wang             perror("error");
148*74ce4ce3SDavid Wang             break;
149*74ce4ce3SDavid Wang         }
150*74ce4ce3SDavid Wang         *tp=vw; tp++;
151*74ce4ce3SDavid Wang     }
152*74ce4ce3SDavid Wang     offset=0; hlen=0;
153*74ce4ce3SDavid Wang     fwrite(&userinfo, sizeof(userinfo), 1, fp_header);
154*74ce4ce3SDavid Wang     hlen += sizeof(userinfo);
155*74ce4ce3SDavid Wang     // get register
156*74ce4ce3SDavid Wang     regset.iov_base = (void*)buf;
157*74ce4ce3SDavid Wang     for (i=0; ; i++) {
158*74ce4ce3SDavid Wang         z = regset_ids[i];
159*74ce4ce3SDavid Wang         if (z==-1) break;
160*74ce4ce3SDavid Wang         regset.iov_len = sizeof(buf);
161*74ce4ce3SDavid Wang         x = ptrace(PTRACE_GETREGSET, pid, z, &regset);
162*74ce4ce3SDavid Wang         if (x>=0) {
163*74ce4ce3SDavid Wang             printf("saving register set %d, length %d\n", z, regset.iov_len);
164*74ce4ce3SDavid Wang             regset_header.regset = z;
165*74ce4ce3SDavid Wang             regset_header.offset = offset;
166*74ce4ce3SDavid Wang             regset_header.size = regset.iov_len;
167*74ce4ce3SDavid Wang             n = fwrite(&regset_header, sizeof(regset_header), 1, fp_header);
168*74ce4ce3SDavid Wang             fwrite(&regset.iov_base, 1, regset.iov_len, fp_binary);
169*74ce4ce3SDavid Wang             offset += regset.iov_len;
170*74ce4ce3SDavid Wang             hlen+=sizeof(regset_header);
171*74ce4ce3SDavid Wang         }
172*74ce4ce3SDavid Wang     }
173*74ce4ce3SDavid Wang     regset_header.regset = -1;
174*74ce4ce3SDavid Wang     fwrite(&regset_header, sizeof(regset_header), 1, fp_header);
175*74ce4ce3SDavid Wang     hlen+=sizeof(regset_header);
176*74ce4ce3SDavid Wang     // get maps
177*74ce4ce3SDavid Wang     memset(vmk, 0xff, sizeof(vmk));
178*74ce4ce3SDavid Wang     for (i='0'; i<='9'; i++) vmk[i]=i-'0';
179*74ce4ce3SDavid Wang     for (i='a'; i<='f'; i++) vmk[i]=i-'a'+10;
180*74ce4ce3SDavid Wang     for (i='A'; i<='F'; i++) vmk[i]=i-'A'+10;
181*74ce4ce3SDavid Wang     mp = load_maps(pid);
182*74ce4ce3SDavid Wang     MapHNode mheader;
183*74ce4ce3SDavid Wang     if (mp) {
184*74ce4ce3SDavid Wang         for (auto m: *mp) {
185*74ce4ce3SDavid Wang             mheader.start = m.start;
186*74ce4ce3SDavid Wang             mheader.end = m.end;
187*74ce4ce3SDavid Wang             mheader.offset = m.offset;
188*74ce4ce3SDavid Wang             mheader.mode = m.mode;
189*74ce4ce3SDavid Wang             n = m.name.length();
190*74ce4ce3SDavid Wang             mheader.nlen = n;
191*74ce4ce3SDavid Wang             if (n) {
192*74ce4ce3SDavid Wang                 strcpy(ns, m.name.c_str());
193*74ce4ce3SDavid Wang                 mheader.noffset = offset;
194*74ce4ce3SDavid Wang                 n = (n+16)/8*8;
195*74ce4ce3SDavid Wang                 fwrite(ns, 1, n, fp_binary);
196*74ce4ce3SDavid Wang                 offset+=n;
197*74ce4ce3SDavid Wang             }
198*74ce4ce3SDavid Wang             // read maps if the map is writable
199*74ce4ce3SDavid Wang             //if (mheader.mode&(1<<1)) {
200*74ce4ce3SDavid Wang                 dlen = m.end-m.start;
201*74ce4ce3SDavid Wang                 mheader.doffset = offset;
202*74ce4ce3SDavid Wang                 if (n)
203*74ce4ce3SDavid Wang                     printf("try copy from memory address 0x%llx, sizeof %lld [%s]\n", m.start, dlen, m.name.c_str());
204*74ce4ce3SDavid Wang                 else
205*74ce4ce3SDavid Wang                     printf("try copy from memory address 0x%llx, sizeof %lld []\n", m.start, dlen);
206*74ce4ce3SDavid Wang                 rn = map_copy(fp_binary, fp_mem, m.start, dlen);
207*74ce4ce3SDavid Wang                 mheader.dsize = rn;
208*74ce4ce3SDavid Wang                 offset+=rn;
209*74ce4ce3SDavid Wang             // }
210*74ce4ce3SDavid Wang             fwrite(&mheader, sizeof(mheader), 1, fp_header);
211*74ce4ce3SDavid Wang             hlen += sizeof(mheader);
212*74ce4ce3SDavid Wang         }
213*74ce4ce3SDavid Wang         delete mp;
214*74ce4ce3SDavid Wang     }
215*74ce4ce3SDavid Wang     // mark the end
216*74ce4ce3SDavid Wang     mheader.start = -1;
217*74ce4ce3SDavid Wang     fwrite(&mheader, sizeof(mheader), 1, fp_header);
218*74ce4ce3SDavid Wang     hlen += sizeof(mheader);
219*74ce4ce3SDavid Wang     // ptrace(PTRACE_CONT, pid, 0, 0);
220*74ce4ce3SDavid Wang     ptrace(PTRACE_KILL, pid, 0, 0);
221*74ce4ce3SDavid Wang 
222*74ce4ce3SDavid Wang out:
223*74ce4ce3SDavid Wang     if (fp_header) fclose(fp_header);
224*74ce4ce3SDavid Wang     if (fp_binary) fclose(fp_binary);
225*74ce4ce3SDavid Wang     if (fp_mem) fclose(fp_mem);
226*74ce4ce3SDavid Wang     return 0;
227*74ce4ce3SDavid Wang }
228