1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <dlfcn.h>
17#include <stdio.h>
18#include <unistd.h>
19#include <stdlib.h>
20#include <sys/wait.h>
21#include <string.h>
22#include <errno.h>
23#include "test.h"
24
25typedef void (* ATEXIT_CB)();
26
27#define TEST_DSO "/data/tests/libc-test/src/libatexit_dlclose_dso.so"
28#define ATEXIT_CB_NAME "atexit_cb"
29#define ATEXIT_WATCHPOINT_NAME "g_watchpoint"
30#define LIBATEXIT_DLCLOSE_DSO_ABSOLUTE_PATH "/data/tests/libc-test/src/libatexit_dlclose_dso.so"
31
32int fork_main(char *exe)
33{
34	char buf[512];
35	void *handler = NULL;
36	ATEXIT_CB cb = NULL;
37	unsigned int *wp_ptr = NULL;
38	unsigned int wp = 0;
39
40	int err = 0;
41
42	if(!t_pathrel(buf, sizeof(buf), exe, TEST_DSO)) {
43		t_error("failed to obtain relative path to " TEST_DSO "\n");
44		return 1;
45	}
46
47	handler = dlopen(LIBATEXIT_DLCLOSE_DSO_ABSOLUTE_PATH, RTLD_LAZY|RTLD_LOCAL);
48	if(!handler) {
49		t_error("dlopen %s failed: %s\n", buf, dlerror());
50		return 2;
51	}
52
53	cb = (ATEXIT_CB)dlsym(handler, ATEXIT_CB_NAME);
54	if (!cb) {
55		t_error("dlsym %s failed: %s\n", ATEXIT_CB_NAME, dlerror());
56		return 3;
57	}
58
59	wp_ptr = (unsigned int *)dlsym(handler, ATEXIT_WATCHPOINT_NAME);
60	if (!wp_ptr) {
61		t_error("dlsym %s failed: %s\n", ATEXIT_WATCHPOINT_NAME, dlerror());
62		return 3;
63	}
64
65	wp_ptr = &wp;
66
67	err = atexit(cb);
68
69	if(dlclose( handler)) {
70		t_error("dlclose failed: %s\n", dlerror());
71		return 4;
72	}
73
74	if (wp == 0xFFFF) {
75		t_error("error, atexit callback called");
76		return 5;
77	}
78
79	return 0;
80}
81
82int main(int argc, char *argv[])
83{
84	pid_t pid, w;
85	int err;
86	int wstatus;
87
88	pid = fork();
89	if (pid == 0) { // child process
90		return fork_main(argv[0]);
91	} else if (pid > 0) { // parent process
92		w = waitpid(pid, &wstatus, 0);
93		if (w == -1) {
94			t_error("wait for child process failed");
95			return 1;
96		}
97
98		if (WIFEXITED(wstatus)) {
99			err = WEXITSTATUS(wstatus);
100			t_error("exited with status=%d\n", err);
101			return err;
102		} else if (WIFSIGNALED(wstatus)) {
103			t_error("killed by signal %d\n", WTERMSIG(wstatus));
104			return 9;
105		} else if (WIFSTOPPED(wstatus)) {
106			t_error("stopped by signal %d\n", WSTOPSIG(wstatus));
107			return 9;
108		} else {
109			t_error("stopped by signal %d\n", WSTOPSIG(wstatus));
110			return 9;
111		}
112	} else {
113		t_error("fork failed: %s\n", strerror(errno));
114		return 1;
115	}
116}
117
118