1/*
2 * Copyright (C) 2019 Alyssa Rosenzweig
3 * Copyright (C) 2017-2018 Lyude Paul
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <assert.h>
28#include <stdint.h>
29#include <string.h>
30
31#include "mmap.h"
32int pandecode_replay_jc(mali_ptr jc_gpu_va, bool bifrost);
33
34/* Memory handling */
35
36static struct pandecode_mapped_memory mmaps;
37
38struct pandecode_mapped_memory *
39pandecode_find_mapped_gpu_mem_containing(mali_ptr addr)
40{
41        list_for_each_entry(struct pandecode_mapped_memory, pos, &mmaps.node, node) {
42                if (addr >= pos->gpu_va && addr < pos->gpu_va + pos->length)
43                        return pos;
44        }
45
46        return NULL;
47}
48
49char *
50pointer_as_memory_reference(mali_ptr ptr)
51{
52        struct pandecode_mapped_memory *mapped;
53        char *out = malloc(128);
54
55        /* Try to find the corresponding mapped zone */
56
57        mapped = pandecode_find_mapped_gpu_mem_containing(ptr);
58
59        if (mapped) {
60                snprintf(out, 128, "%s + %d", mapped->name, (int) (ptr - mapped->gpu_va));
61                return out;
62        }
63
64        /* Just use the raw address if other options are exhausted */
65
66        snprintf(out, 128, MALI_PTR_FMT, ptr);
67        return out;
68
69}
70
71/* Parsing */
72
73static FILE *
74pandecode_read_filename(const char *base, const char *name)
75{
76        char *fn = NULL;
77        asprintf(&fn, "%s/%s", base, name);
78
79        FILE *fp = fopen(fn, "rb");
80        free(fn);
81
82        return fp;
83}
84
85static void
86pandecode_read_memory(const char *base, const char *name, mali_ptr gpu_va)
87{
88        FILE *fp = pandecode_read_filename(base, name);
89
90        if (!fp) {
91                fprintf(stderr, "Warning: missing %s\n", name);
92                return;
93        }
94
95        fseek(fp, 0, SEEK_END);
96        long sz = ftell(fp);
97        fseek(fp, 0, SEEK_SET);
98
99        char *buf = malloc(sz);
100        assert(buf);
101        fread(buf, 1, sz, fp);
102        fclose(fp);
103
104        /* Now that we have the memory loaded in, create a mmap entry for it so
105         * we remember it later */
106
107        struct pandecode_mapped_memory *mapped_mem = NULL;
108
109        mapped_mem = malloc(sizeof(*mapped_mem));
110        list_inithead(&mapped_mem->node);
111
112        mapped_mem->gpu_va = gpu_va;
113        mapped_mem->length = sz;
114        mapped_mem->addr = buf;
115
116        memcpy(mapped_mem->name, name, strlen(name));
117
118        list_add(&mapped_mem->node, &mmaps.node);
119}
120
121static void
122pandecode_read_mmap(const char *base, const char *line)
123{
124        assert(strlen(line) < 500);
125
126        mali_ptr addr;
127        char name[512];
128
129        sscanf(line, "MMAP %" PRIx64 " %s", &addr, name);
130        pandecode_read_memory(base, name, addr);
131}
132
133static void
134pandecode_read_job_submit(const char *base, const char *line)
135{
136        mali_ptr addr;
137        unsigned core_req;
138        unsigned is_bifrost;
139
140        sscanf(line, "JS %" PRIx64 " %x %x", &addr, &core_req, &is_bifrost);
141        pandecode_replay_jc(addr, is_bifrost);
142}
143
144/* Reads the control file, processing as it goes. */
145
146static void
147pandecode_read_control(const char *base)
148{
149        FILE *fp = pandecode_read_filename(base, "control.log");
150
151        if (!fp) {
152                fprintf(stderr, "Invalid directory path\n");
153                return;
154        }
155
156        char *line = NULL;
157        size_t len = 0;
158
159        while (getline(&line, &len, fp) != -1) {
160                switch (line[0]) {
161                        case 'M':
162                                pandecode_read_mmap(base, line);
163                                break;
164
165                        case 'J':
166                                pandecode_read_job_submit(base, line);
167                                break;
168
169                        default:
170                                assert(0);
171                                break;
172                }
173        }
174}
175
176int
177main(int argc, char **argv)
178{
179        if (argc < 2) {
180                fprintf(stderr, "Usage: pandecode [directory]\n");
181                exit(1);
182        }
183
184        /* Initialize */
185        list_inithead(&mmaps.node);
186
187        /* Let's go! */
188        pandecode_read_control(argv[1]);
189}
190