mem: Check if phys-mem is within the range of McKernel memory

Fujitsu: POSTK_DEBUG_TEMP_FIX_52
Refs: #1164
Change-Id: Idb9a6eac1d2e1df4c663c3171925c774421177fd
This commit is contained in:
Ken Sato
2018-08-08 09:40:05 +09:00
committed by Masamichi Takagi
parent f57b0c5d4f
commit 9a20cfaefb
11 changed files with 436 additions and 53 deletions

View File

@ -2922,12 +2922,7 @@ int read_process_vm(struct process_vm *vm, void *kdst, const void *usrc, size_t
return error;
}
#ifdef POSTK_DEBUG_TEMP_FIX_52 /* NUMA support(memory area determination) */
if (!is_mckernel_memory(pa)) {
#else
if (pa < ihk_mc_get_memory_address(IHK_MC_GMA_MAP_START, 0) ||
pa >= ihk_mc_get_memory_address(IHK_MC_GMA_MAP_END, 0)) {
#endif /* POSTK_DEBUG_TEMP_FIX_52 */
if (!is_mckernel_memory(pa, pa + cpsize)) {
dkprintf("%s: pa is outside of LWK memory, to: %p, pa: %p,"
"cpsize: %d\n", __FUNCTION__, to, pa, cpsize);
va = ihk_mc_map_virtual(pa, 1, PTATTR_ACTIVE);
@ -3005,12 +3000,7 @@ int write_process_vm(struct process_vm *vm, void *udst, const void *ksrc, size_t
return error;
}
#ifdef POSTK_DEBUG_TEMP_FIX_52 /* NUMA support(memory area determination) */
if (!is_mckernel_memory(pa)) {
#else
if (pa < ihk_mc_get_memory_address(IHK_MC_GMA_MAP_START, 0) ||
pa >= ihk_mc_get_memory_address(IHK_MC_GMA_MAP_END, 0)) {
#endif /* POSTK_DEBUG_TEMP_FIX_52 */
if (!is_mckernel_memory(pa, pa + cpsize)) {
dkprintf("%s: pa is outside of LWK memory, from: %p,"
"pa: %p, cpsize: %d\n", __FUNCTION__, from, pa, cpsize);
va = ihk_mc_map_virtual(pa, 1, PTATTR_WRITABLE|PTATTR_ACTIVE);
@ -3076,12 +3066,7 @@ int patch_process_vm(struct process_vm *vm, void *udst, const void *ksrc, size_t
return error;
}
#ifdef POSTK_DEBUG_TEMP_FIX_52 /* NUMA support(memory area determination) */
if (!is_mckernel_memory(pa)) {
#else
if (pa < ihk_mc_get_memory_address(IHK_MC_GMA_MAP_START, 0) ||
pa >= ihk_mc_get_memory_address(IHK_MC_GMA_MAP_END, 0)) {
#endif /* POSTK_DEBUG_TEMP_FIX_52 */
if (!is_mckernel_memory(pa, pa + cpsize)) {
dkprintf("%s: pa is outside of LWK memory, from: %p,"
"pa: %p, cpsize: %d\n", __FUNCTION__, from, pa, cpsize);
va = ihk_mc_map_virtual(pa, 1, PTATTR_WRITABLE|PTATTR_ACTIVE);

View File

@ -2839,12 +2839,7 @@ int read_process_vm(struct process_vm *vm, void *kdst, const void *usrc, size_t
return error;
}
#ifdef POSTK_DEBUG_TEMP_FIX_52 /* NUMA support(memory area determination) */
if (!is_mckernel_memory(pa)) {
#else
if (pa < ihk_mc_get_memory_address(IHK_MC_GMA_MAP_START, 0) ||
pa >= ihk_mc_get_memory_address(IHK_MC_GMA_MAP_END, 0)) {
#endif /* POSTK_DEBUG_TEMP_FIX_52 */
if (!is_mckernel_memory(pa, pa + cpsize)) {
dkprintf("%s: pa is outside of LWK memory, to: %p, pa: %p,"
"cpsize: %d\n", __FUNCTION__, to, pa, cpsize);
va = ihk_mc_map_virtual(pa, 1, PTATTR_ACTIVE);
@ -2923,12 +2918,7 @@ int write_process_vm(struct process_vm *vm, void *udst, const void *ksrc, size_t
return error;
}
#ifdef POSTK_DEBUG_TEMP_FIX_52 /* NUMA support(memory area determination) */
if (!is_mckernel_memory(pa)) {
#else
if (pa < ihk_mc_get_memory_address(IHK_MC_GMA_MAP_START, 0) ||
pa >= ihk_mc_get_memory_address(IHK_MC_GMA_MAP_END, 0)) {
#endif /* POSTK_DEBUG_TEMP_FIX_52 */
if (!is_mckernel_memory(pa, pa + cpsize)) {
dkprintf("%s: pa is outside of LWK memory, from: %p,"
"pa: %p, cpsize: %d\n", __FUNCTION__, from, pa, cpsize);
va = ihk_mc_map_virtual(pa, 1, PTATTR_ACTIVE);
@ -2994,12 +2984,7 @@ int patch_process_vm(struct process_vm *vm, void *udst, const void *ksrc, size_t
return error;
}
#ifdef POSTK_DEBUG_TEMP_FIX_52 /* NUMA support(memory area determination) */
if (!is_mckernel_memory(pa)) {
#else
if (pa < ihk_mc_get_memory_address(IHK_MC_GMA_MAP_START, 0) ||
pa >= ihk_mc_get_memory_address(IHK_MC_GMA_MAP_END, 0)) {
#endif /* POSTK_DEBUG_TEMP_FIX_52 */
if (!is_mckernel_memory(pa, pa + cpsize)) {
dkprintf("%s: pa is outside of LWK memory, from: %p,"
"pa: %p, cpsize: %d\n", __FUNCTION__, from, pa, cpsize);
va = ihk_mc_map_virtual(pa, 1, PTATTR_ACTIVE);

View File

@ -2296,34 +2296,37 @@ void ___kmalloc_print_free_list(struct list_head *list)
kprintf_unlock(irqflags);
}
#ifdef POSTK_DEBUG_TEMP_FIX_52 /* supports NUMA for memory area determination */
#ifdef IHK_RBTREE_ALLOCATOR
int is_mckernel_memory(unsigned long phys)
int is_mckernel_memory(unsigned long start, unsigned long end)
{
int i;
for (i = 0; i < ihk_mc_get_nr_memory_chunks(); ++i) {
unsigned long start, end;
unsigned long chunk_start, chunk_end;
int numa_id;
ihk_mc_get_memory_chunk(i, &start, &end, &numa_id);
if (start <= phys && phys < end) {
ihk_mc_get_memory_chunk(i, &chunk_start, &chunk_end, &numa_id);
if ((chunk_start <= start && start < chunk_end) &&
(chunk_start <= end && end < chunk_end)) {
return 1;
}
}
return 0;
}
#else /* IHK_RBTREE_ALLOCATOR */
int is_mckernel_memory(unsigned long phys)
int is_mckernel_memory(unsigned long start, unsigned long end)
{
int i;
for (i = 0; i < ihk_mc_get_nr_numa_nodes(); ++i) {
struct ihk_page_allocator_desc *pa_allocator;
unsigned long area_start = pa_allocator->start;
unsigned long area_end = pa_allocator->end;
list_for_each_entry(pa_allocator,
&memory_nodes[i].allocators, list) {
if (pa_allocator->start <= phys && phys < pa_allocator->end) {
if ((area_start <= start && start < area_end) &&
(area_start <= end && end < area_end)) {
return 1;
}
}
@ -2331,7 +2334,6 @@ int is_mckernel_memory(unsigned long phys)
return 0;
}
#endif /* IHK_RBTREE_ALLOCATOR */
#endif /* POSTK_DEBUG_TEMP_FIX_52 */
void ihk_mc_query_mem_areas(void){

View File

@ -379,12 +379,7 @@ int process_procfs_request(struct ikc_scd_packet *rpacket)
goto end;
}
#ifdef POSTK_DEBUG_TEMP_FIX_52 /* NUMA support(memory area determination) */
if (!is_mckernel_memory(pa)) {
#else
if (pa < ihk_mc_get_memory_address(IHK_MC_GMA_MAP_START, 0) ||
pa >= ihk_mc_get_memory_address(IHK_MC_GMA_MAP_END, 0)) {
#endif /* POSTK_DEBUG_TEMP_FIX_52 */
if (!is_mckernel_memory(pa, pa + size)) {
ans = -EIO;
goto end;
}

View File

@ -47,9 +47,7 @@ int setint_user(int *dst, int data);
int write_process_vm(struct process_vm *vm, void *udst, const void *ksrc, size_t siz);
int patch_process_vm(struct process_vm *vm, void *udst, const void *ksrc, size_t siz);
#ifdef POSTK_DEBUG_TEMP_FIX_52 /* supports NUMA for memory area determination */
int is_mckernel_memory(unsigned long phys);
#endif /* POSTK_DEBUG_TEMP_FIX_52 */
int is_mckernel_memory(unsigned long start, unsigned long end);
#endif

93
test/issues/1164/C1164.sh Normal file
View File

@ -0,0 +1,93 @@
#!/bin/sh
if [ -f $HOME/mck_test_config ]; then
. $HOME/mck_test_config
else
BIN=
SBIN=
OSTEST=
LTP=
fi
BOOTPARAM="-c 1-7,9-15,17-23,25-31 -m 10G@0,10G@1 -r 1-7:0+9-15:8+17-23:16+25-31:24"
if [ "x$BINDIR" = x ];then
BINDIR="$BIN"
fi
if [ "x$SBINDIR" = x ];then
SBINDIR="$SBIN"
fi
if [ "x$OSTESTDIR" = x ]; then
OSTESTDIR="$OSTEST"
fi
if [ "x$LTPDIR" = x ]; then
LTPDIR="$LTP"
fi
if [ ! -x $SBINDIR/mcstop+release.sh ]; then
echo mcstop+release: not found >&2
exit 1
fi
echo -n "mcstop+release.sh ... "
sudo $SBINDIR/mcstop+release.sh
echo "done"
if [ ! -x $SBINDIR/mcreboot.sh ]; then
echo mcreboot: not found >&2
exit 1
fi
echo -n "mcreboot.sh $BOOTPARAM ... "
sudo $SBINDIR/mcreboot.sh $BOOTPARAM
echo "done"
if [ ! -x $BINDIR/mcexec ]; then
echo mcexec: not found >&2
exit 1
fi
sudo /bin/sh ${OSTESTDIR}/util/insmod_test_drv.sh
$BINDIR/mcexec ./CT_001
sudo /bin/sh ${OSTESTDIR}/util/rmmod_test_drv.sh
tid=001
echo "*** RT_$tid start *******************************"
sudo $BINDIR/mcexec $OSTESTDIR/bin/test_mck -s procfs -n 0 2>&1 | tee ./RT_${tid}.txt
if grep -v "RESULT: TP failed" ./RT_${tid}.txt > /dev/null 2>&1 ; then
echo "*** RT_$tid: PASSED"
else
echo "*** RT_$tid: FAILED"
fi
echo ""
tid=002
echo "*** RT_$tid start *******************************"
sudo $BINDIR/mcexec $OSTESTDIR/bin/test_mck -s procfs -n 1 2>&1 | tee ./RT_${tid}.txt
if grep -v "RESULT: TP failed" ./RT_${tid}.txt > /dev/null 2>&1 ; then
echo "*** RT_$tid: PASSED"
else
echo "*** RT_$tid: FAILED"
fi
echo ""
tid=003
echo "*** RT_$tid start *******************************"
sudo $BINDIR/mcexec $OSTESTDIR/bin/test_mck -s procfs -n 3 2>&1 | tee ./RT_${tid}.txt
if grep -v "RESULT: TP failed" ./RT_${tid}.txt > /dev/null 2>&1 ; then
echo "*** RT_$tid: PASSED"
else
echo "*** RT_$tid: FAILED"
fi
echo ""
tid=004
echo "*** RT_$tid start *******************************"
sudo $BINDIR/mcexec $OSTESTDIR/bin/test_mck -s procfs -n 6 2>&1 | tee ./RT_${tid}.txt
if grep -v "RESULT: TP failed" ./RT_${tid}.txt > /dev/null 2>&1 ; then
echo "*** RT_$tid: PASSED"
else
echo "*** RT_$tid: FAILED"
fi
echo ""

81
test/issues/1164/CT_001.c Normal file
View File

@ -0,0 +1,81 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "./test_chk.h"
#define TEST_NAME "CT_001"
#define PROCFILE_LEN 128
#define MAP_LEN 4096
#define DEV_NAME "/dev/test_mck/mmap_dev2"
int main(int argc, char *argv[])
{
int dev_fd = 0, fd = 0, i = 0;
pid_t pid = getpid();
char pfname[PROCFILE_LEN];
void *dev_map = NULL;
unsigned long *read_buf = NULL;
off_t ret = 0;
printf("*** %s start *******************************\n", TEST_NAME);
/* open device file */
dev_fd = open(DEV_NAME, O_RDONLY);
OKNG(dev_fd < 0, "open test_device_file:%s", DEV_NAME);
/* mmap device file */
dev_map = mmap(NULL, MAP_LEN, PROT_READ, MAP_SHARED, dev_fd, 0);
OKNG(dev_map == MAP_FAILED, "mmap device file");
printf(" map dev_file to %p\n", dev_map);
/* allocate read_buf */
read_buf = malloc(MAP_LEN);
CHKANDJUMP(read_buf == NULL, "malloc read_buf");
/* generate proc_mem path */
sprintf(pfname, "/proc/%d/mem", pid);
/* open proc_mem */
fd = open(pfname, O_RDONLY);
CHKANDJUMP(fd < 0, "open proc_mem");
/* lseek */
ret = lseek(fd, (off_t)dev_map, SEEK_SET);
CHKANDJUMP(ret == -1, "lseek");
/* read */
ret = read(fd, read_buf, MAP_LEN);
OKNG(ret != -1 || errno != EIO, "failed to read host's phys_memory");
free(read_buf);
close(dev_fd);
close(fd);
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
if (read_buf) {
free(read_buf);
}
if (dev_fd > 0) {
close(dev_fd);
}
if (fd > 0) {
close(fd);
}
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

17
test/issues/1164/Makefile Normal file
View File

@ -0,0 +1,17 @@
CC = gcc
TARGET=CT_001
CPPFLAGS =
LDFLAGS =
all: $(TARGET)
CT_001: CT_001.c
$(CC) -o $@ $^ $(LDFLAGS)
test: all
@sh ./C1164.sh
clean:
rm -f $(TARGET) *.o

35
test/issues/1164/README Normal file
View File

@ -0,0 +1,35 @@
【Issue#1164 動作確認】
□ テスト内容
1. Issueで報告された再現プログラムでの確認
CT_001: Linux管理メモリ領域への/proc/<PID>/mem のread
Linux管理メモリ領域を持つデバイスファイルをマップする
対象領域に対して/proc/<PID>/mem を介してreadし、
readが失敗し、errnoにEIOが設定されていることを確認する
2. 既存のprocfs機能に影響がないことをOSTESTを用いて確認
RT_001: ostest_procfs.000
/proc/<PID>/auxv の内容を取得できることを確認
RT_002: ostest_procfs.001
/proc/<PID>/mem の内容を取得できることを確認
RT_003: ostest_procfs.003
/proc/<PID>/stat の内容を取得できることを確認
RT_004: ostest_procfs.006
/proc/<PID>/cpuinfo の内容を取得できることを確認
□ 実行手順
McKernelのインストール先や、OSTEST, LTPの配置場所は、
$HOME/mck_test_config を参照している
mck_test_config は、McKernelをビルドした際に生成される
mck_test_config.sample ファイルを$HOMEにコピーし、適宜編集する
$ make test
実行できない場合は、C1164.shの以下の行を適切に書き換えた後に実行。
BIN= mcexec が存在するパス
SBIN= mcreboot.sh が存在するパス
OSTEST= OSTESTが存在するパス
LTP= LTPが存在するパス
□ 実行結果
result.log 参照。
すべての項目をPASSしていることを確認。

169
test/issues/1164/result.log Normal file
View File

@ -0,0 +1,169 @@
insmod /home/satoken/ostest/util/../bin/test_mck.ko
mknod: /dev/test_mck/mmap_dev: File exists
create character device /dev/test_mck/mmap_dev(244:0)
mknod: /dev/test_mck/mmap_dev2: File exists
create character device /dev/test_mck/mmap_dev2(244:1)
*** CT_001 start *******************************
[OK] open test_device_file:/dev/test_mck/mmap_dev2
[OK] mmap device file
map dev_file to 0x2aaaab014000
[OK] failed to read host's phys_memory
*** CT_001 PASSED
remove /dev/test_mck
rmmod /home/satoken/ostest/util/../bin/test_mck.ko
*** RT_001 start *******************************
TEST_SUITE: procfs
TEST_NUMBER: 0
ARGS:
dump /proc/17731/auxv:
0x00000000000021 0x002aaaaac24000 (AT_SYSINFO_EHDR)
0x00000000000019 0x00547fffffffe0 (AT_RANDOM)
0x00000000000011 0x00000000000064 (AT_CLKTCK)
0x00000000000006 0x00000000001000 (AT_PAGESZ)
0x00000000000003 0x00000000400040 (AT_PHDR)
0x00000000000004 0x00000000000038 (AT_PHENT)
0x00000000000005 0x0000000000000a (AT_PHNUM)
0x00000000000009 0x00000000403430 (AT_ENTRY)
0000000000000000 0000000000000000 (AT_NULL)
RESULT: you need check AUXV value
*** RT_001: PASSED
*** RT_002 start *******************************
TEST_SUITE: procfs
TEST_NUMBER: 1
ARGS:
allocated: 0x00000000800010
dump /proc/17765/mem(offset:0x00000000800010):
0x00000000800010: 0000000000000000 0000000000000001 0000000000000002 0000000000000003
0x00000000800030: 0000000000000004 0000000000000005 0000000000000006 0000000000000007
0x00000000800050: 0000000000000008 0000000000000009 000000000000000a 000000000000000b
0x00000000800070: 000000000000000c 000000000000000d 000000000000000e 000000000000000f
0x00000000800090: 0000000000000010 0000000000000011 0000000000000012 0000000000000013
0x000000008000b0: 0000000000000014 0000000000000015 0000000000000016 0000000000000017
0x000000008000d0: 0000000000000018 0000000000000019 000000000000001a 000000000000001b
0x000000008000f0: 000000000000001c 000000000000001d 000000000000001e 000000000000001f
RESULT: you need check MEM value
*** RT_002: PASSED
*** RT_003 start *******************************
TEST_SUITE: procfs
TEST_NUMBER: 3
ARGS:
output /proc/17799/task/17829/stat
0 (exe) R 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
RESULT: you need check STAT value
*** RT_003: PASSED
*** RT_004 start *******************************
TEST_SUITE: procfs
TEST_NUMBER: 6
ARGS:
output: /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 62
model name : Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz
stepping : 4
microcode : 0x428
cpu MHz : 2600.000
cache size : 20480 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 1
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm ida arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms xsaveopt
bogomips : 5200.17
clflush size : 64
cache_alignment : 64
address sizes : 46 bits physical, 48 bits virtual
power management:
processor : 8
vendor_id : GenuineIntel
cpu family : 6
model : 62
model name : Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz
stepping : 4
microcode : 0x428
cpu MHz : 2599.898
cache size : 20480 KB
physical id : 1
siblings : 2
core id : 0
cpu cores : 1
apicid : 32
initial apicid : 32
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm ida arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms xsaveopt
bogomips : 5205.44
clflush size : 64
cache_alignment : 64
address sizes : 46 bits physical, 48 bits virtual
power management:
processor : 16
vendor_id : GenuineIntel
cpu family : 6
model : 62
model name : Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz
stepping : 4
microcode : 0x428
cpu MHz : 2599.898
cache size : 20480 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 1
apicid : 1
initial apicid : 1
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm ida arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms xsaveopt
bogomips : 5200.17
clflush size : 64
cache_alignment : 64
address sizes : 46 bits physical, 48 bits virtual
power management:
processor : 24
vendor_id : GenuineIntel
cpu family : 6
model : 62
model name : Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz
stepping : 4
microcode : 0x428
cpu MHz : 2600.000
cache size : 20480 KB
physical id : 1
siblings : 2
core id : 0
cpu cores : 1
apicid : 33
initial apicid : 33
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm ida arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms xsaveopt
bogomips : 5205.44
clflush size : 64
cache_alignment : 64
address sizes : 46 bits physical, 48 bits virtual
power management:
RESULT: you need check CPUINFO
*** RT_004: PASSED

View File

@ -0,0 +1,23 @@
#ifndef HEADER_TEST_CHK_H
#define HEADER_TEST_CHK_H
#define CHKANDJUMP(cond, ...) do {\
if (cond) {\
fprintf(stderr, " [NG] ");\
fprintf(stderr, __VA_ARGS__);\
fprintf(stderr, " failed\n");\
goto fn_fail;\
} \
} while (0)
#define OKNG(cond, ...) do {\
if (cond) {\
CHKANDJUMP(cond, __VA_ARGS__);\
} else {\
fprintf(stdout, " [OK] ");\
fprintf(stdout, __VA_ARGS__);\
fprintf(stdout, "\n");\
} \
} while (0)
#endif