12 #ifndef ZPMOD_ANALYSIS
23 #include <sys/types.h>
25 #if defined(__has_include)
26 #if __has_include(<sys/mman.h>)
60 enum source_return ret;
68 enam = arg0 =
ztrdup(*argv);
75 ret = SOURCE_NOT_FOUND;
76 if (*name !=
'.' && access(s, F_OK) == 0 && stat(s, &st) >= 0 &&
77 !S_ISDIR(st.st_mode)) {
81 if (ret == SOURCE_NOT_FOUND) {
82 for (s = arg0; *s; s++) {
87 }
else if (arg0[1] ==
'.' && arg0 + 2 == s) {
96 diddot < 2 && dotdot == 0)) {
98 for (t =
path; *t; t++) {
99 if (!(*t)[0] || ((*t)[0] ==
'.' && !(*t)[1])) {
109 if (access(s, F_OK) == 0 && stat(s, &st) >= 0 && !S_ISDIR(st.st_mode)) {
121 if (ret == SOURCE_NOT_FOUND) {
123 zerrnam(name,
"%e: %s", errno, enam);
125 zwarnnam(name,
"%e: %s", errno, enam);
133 return ret == SOURCE_OK ?
lastval : 128 - ret;
137 #define FD_EXT ".zwc"
139 #define FD_MAGIC 0x04050607
140 #define FD_OMAGIC 0x07060504
153 #define FDHEADERLEN(f) (((Wordcode)(f))[FD_PRELEN])
154 #define FDMAGIC(f) (((Wordcode)(f))[0])
155 #define FDSETBYTE(f, i, v) \
156 ((((unsigned char *)(((Wordcode)(f)) + 1))[i]) = ((unsigned char)(v)))
157 #define fdbyte(f, i) ((wordcode)(((unsigned char *)(((Wordcode)(f)) + 1))[i]))
158 #define FDFLAGS(f) fdbyte(f, 0)
159 #define FDOTHER(f) (fdbyte(f, 1) + (fdbyte(f, 2) << 8) + (fdbyte(f, 3) << 16))
160 #define FDVERSION(f) ((char *)((f) + 2))
161 #define FIRSTFDHEAD(f) ((FDHead)(((Wordcode)(f)) + FD_PRELEN))
162 #define NEXTFDHEAD(f) ((FDHead)(((Wordcode)(f)) + (f)->hlen))
163 #define FDHFLAGS(f) (((FDHead)(f))->flags)
164 #define FDHTAIL(f) (((FDHead)(f))->flags >> 2)
165 #define FDHF_KSHLOAD 1
166 #define FDHF_ZSHLOAD 2
167 #define FDNAME(f) ((char *)(((FDHead)(f)) + 1))
170 static FuncDump dumps;
172 if (stat(filename, buf)) {
174 for (FuncDump fdump_iter = dumps; fdump_iter;
175 fdump_iter = fdump_iter->next) {
176 if (!strncmp(filename, fdump_iter->filename,
177 strlen(fdump_iter->filename)) &&
178 !fstat(fdump_iter->fd, buf)) {
188 #define custom_zwcstat(f, b) (!!stat(f, b))
206 if ((fd = open(name, O_RDONLY)) < 0) {
208 zwarnnam(nam,
"%d: can't open zwc file: %s", __LINE__, name);
212 if (read(fd, buf, (
FD_PRELEN + 1) *
sizeof(wordcode)) !=
218 zwarnnam(nam,
"%d: zwc file has wrong version (zsh-%s): %s", __LINE__,
221 zwarnnam(nam,
"%d: invalid zwc file: %s", __LINE__, name);
234 if (lseek(fd, o, 0) == -1 ||
235 read(fd, buf, (
FD_PRELEN + 1) *
sizeof(wordcode)) !=
237 zwarnnam(nam,
"%d: invalid zwc file: %s", __LINE__, name);
244 memcpy(head, buf, (
FD_PRELEN + 1) *
sizeof(wordcode));
245 len -= (
FD_PRELEN + 1) *
sizeof(wordcode);
246 if (read(fd, head + (
FD_PRELEN + 1), len) != len) {
248 zwarnnam(nam,
"%d: invalid zwc file: %s", __LINE__, name);
256 static void custom_load_dump_file(
char *dump,
struct stat *sbuf,
int other,
264 static size_t pgsz = 0;
267 pgsz = sysconf(_SC_PAGESIZE);
270 pgsz = sysconf(_SC_PAGE_SIZE);
272 pgsz = getpagesize();
278 mlen = len + (len - off);
283 if ((fd = open(dump, O_RDONLY)) < 0) {
290 if ((addr = (Wordcode)mmap(NULL, mlen, PROT_READ, MAP_SHARED, fd, off)) ==
295 d = (FuncDump)
zalloc(
sizeof(*d));
298 d->dev = sbuf->st_dev;
299 d->ino = sbuf->st_ino;
302 fcntl(fd, F_SETFD, FD_CLOEXEC);
304 d->map = addr + (other ? (len - off) /
sizeof(wordcode) : 0);
308 d->filename =
ztrdup(dump);
314 int *ksh,
int test_only);
333 char *zi_mod_debug =
getsparam(
"ZI_MOD_DEBUG");
334 int debug_enabled = (zi_mod_debug && !strcmp(zi_mod_debug,
"1"));
335 if ((tail = strrchr(file,
'/'))) {
348 rn = stat(file, &stn);
358 if ((!rn && (rc || (stc.st_mtime < stn.st_mtime))) &&
359 (access(file_dup, W_OK) == 0 || debug_enabled)) {
360 char *args[] = {file, NULL};
362 memset(ops.ind, 0, MAX_OPS *
sizeof(
unsigned char));
364 ops.argscount = ops.argsalloc = 0;
366 if (access(file, R_OK) == 0 && access(file, F_OK) == 0 &&
367 0 != strcmp(file,
"/dev/null") && 0 != strcmp(file,
"./")) {
369 }
else if (debug_enabled) {
371 "%d: Couldn't read the script: `%s', compilation skipped",
376 zfree(file_dup, flen);
378 if (!rc && (rn || stc.st_mtime >= stn.st_mtime) &&
388 int *ksh,
int test_only) {
405 for (f = dumps; f; f = f->next) {
406 if (f->dev == sbuf->st_dev && f->ino == sbuf->st_ino) {
426 prog->flags = EF_MAP;
428 prog->npats = np = h->
npats;
431 prog->prog = f->map + h->
start;
432 prog->strs = ((
char *)prog->prog) + h->
strs;
437 *pp++ = dummy_patprog1;
458 if ((fd = open(file, O_RDONLY)) < 0 ||
460 ((h->
start *
sizeof(wordcode)) +
469 if (read(fd, ((
char *)d) + po, h->
len) != (int)h->
len) {
476 prog->flags = EF_REAL;
477 prog->len = h->
len + po;
478 prog->npats = np = h->
npats;
480 prog->pats = pp = (
Patprog *)d;
481 prog->prog = (Wordcode)(((
char *)d) + po);
482 prog->strs = ((
char *)prog->prog) + h->
strs;
486 *pp++ = dummy_patprog1;
523 enum source_return ret = SOURCE_OK;
525 struct timeval zp_tv;
526 struct timezone zp_dummy_tz;
528 zp_tv.tv_sec = zp_tv.tv_usec = 0;
529 gettimeofday(&zp_tv, &zp_dummy_tz);
531 ((((double)zp_tv.tv_sec) * 1000.0) + (((
double)zp_tv.tv_usec) / 1000.0));
533 (tempfd =
movefd(open(us, O_RDONLY | O_NOCTTY))) == -1)) {
534 return SOURCE_NOT_FOUND;
565 :
dupstring(old_scriptfilename ? old_scriptfilename :
"zsh");
567 fstack.lineno = oldlineno;
570 fstack.tp = FS_SOURCE;
575 execode(prog, 1, 0,
"filecode");
581 switch (
loop(0, 0)) {
619 zp_tv.tv_sec = zp_tv.tv_usec = 0;
620 gettimeofday(&zp_tv, &zp_dummy_tz);
635 is_dot_slash = (s[0] ==
'.' && s[1] ==
'/');
636 pwd_len = strlen(
pwd);
637 off = is_dot_slash ? 2U : 0U;
638 rel_len = strlen(s) - off;
639 full_path = (
char *)
zalloc(
sizeof(
char) * (pwd_len + rel_len + 2U));
640 int n1 = snprintf(full_path, pwd_len + 1,
"%s",
pwd);
642 snprintf(full_path + pwd_len, rel_len + 2U,
"/%s", s + off);
644 slash = strrchr(full_path,
'/');
645 file_name =
ztrdup(slash + 1);
648 dir_path =
ztrdup(full_path);
652 zp_node->
event.
ts = (long)zp_prev_tv;
656 zp_node->
event.
duration = ((((double)zp_tv.tv_sec) * 1000.0) +
657 (((
double)zp_tv.tv_usec) / 1000.0)) -
661 snprintf(zp_tmp,
sizeof(zp_tmp),
"%d", zp_node->
event.
id);
662 zp_tmp[
sizeof(zp_tmp) - 1] =
'\0';
681 report = (
char *)
zalloc(
sizeof(
char) * (current_size + 1));
684 return ztrdup(
"ERROR: couldn't allocate initial buffer, aborted\n");
687 report[current_end] =
'\0';
688 *rep_size = current_size + 1;
690 snprintf(zp_tmp,
sizeof(zp_tmp),
"%d", idx);
691 zp_tmp[
sizeof(zp_tmp) - 1] =
'\0';
696 const char *pfx =
zp_icon(
"⏱️ ");
698 snprintf(NULL, 0,
"%s%4.0lf ms %s\n", pfx, node->
event.
duration,
701 if (space_left < printed) {
702 current_size += printed - space_left + 25;
703 space_left += printed - space_left + 25;
705 (
char *)
zrealloc(report,
sizeof(
char) * (current_size + 1));
707 zfree(report, *rep_size);
709 return ztrdup(
"ERROR: Couldn't realloc buffer, aborted\n");
712 *rep_size = current_size + 1;
715 const char *pfx =
zp_icon(
"⏱️ ");
717 snprintf(report + current_end, space_left + 1,
"%s%4.0lf ms %s\n",
721 current_end += printed;
722 space_left -= printed;
749 zwarn(
"Cannot create the hash table");
const char * zp_icon(const char *s)
Return icon string if enabled, empty string otherwise.
int zp_conv_opt(int zp_opt_num)
Convert a stable option enum to a runtime option index (sign-preserving).
Eprog custom_try_source_file(char *file)
Try to locate or build a ZWC dump for the script and return Eprog.
void zp_source_restore_overrides(void)
static int zp_sevent_count
void zp_source_setup_overrides(void)
static FDHead custom_dump_find_func(Wordcode h, char *name)
static HandlerFunc original_source
static HandlerFunc original_dot
mod_export enum source_return custom_source(char *s)
Execute a sourced script and record a timing event for reporting.
static Wordcode custom_load_dump_header(char *nam, char *name, int err)
int bin_custom_dot(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
Replacement handler for '.
void zp_free_sevent_node(HashNode hn)
Hash lifecycle.
#define custom_zwcstat(f, b)
char * zp_build_source_report(int no_paths, int *rep_size)
static HashTable zp_source_events
static Eprog custom_check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh, int test_only)
struct source_event event
Module declaration header (mdh) for zpmod.
Prototype stub for zpmod when building out-of-tree.
Optional terminal/locale detection for emoji support in messages.
void * zalloc(size_t size)
char * dupstring(const char *s)
void zfree(void *ptr, size_t size)
void * zrealloc(void *ptr, size_t size)
char * getsparam(const char *name)
void emptyhashtable(HashTable)
void deletehashtable(HashTable)
void execode(Eprog, int, int, char *)
void zwarnnam(const char *, const char *,...)
struct hashtable * HashTable
void zwarn(const char *,...)
void unqueue_signals(void)
void shinbufrestore(void)
char * zhtricat(const char *, const char *, const char *)
HashNode gethashnode2(HashTable, const char *)
HashTable newhashtable(int, char *, PrintTableStats)
int bin_zcompile(char *, char **, void *, int)
struct hashnode * HashNode
int strsfx(const char *, const char *)
HashNode removehashnode(HashTable, const char *)
void incrdumpcount(void *)
unsigned int hasher(const char *)
int dosetopt(int, int, int, unsigned char *)
void zerrnam(const char *, const char *,...)
volatile int exit_pending
void addhashnode(HashTable, char *, void *)
char * dyncat(const char *, const char *)
char * ztrdup(const char *)
Public interfaces for source-study and source overrides.
struct zp_sevent_node * SEventNode
Utility helpers shared across module components.
Local, non-invasive shims to suppress benign vendor header warnings.