//============================================================================
// Name        : bfdTest.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <bfd.h>

using namespace std;

#define PRINT(var) if (fflag & var) printf((#var"\t"));

void processSymbols(bfd*abfd)
{
	size_t storage_needed  = bfd_get_dynamic_symtab_upper_bound( abfd );
	if (storage_needed  > 0)
	{
		asymbol **symbol_table = NULL;
		symbol_table = (asymbol **)malloc (storage_needed);
		if (symbol_table)
		{
			long number_of_symbols = 0;
			number_of_symbols = bfd_canonicalize_dynamic_symtab (abfd, symbol_table);
			if (number_of_symbols > 0)
			{
				for (int i = 0; i < number_of_symbols; i++)
				{
					printf("symbol name: %s\n", symbol_table[i]->name);
					printf("symbol value: %lu\n", symbol_table[i]->value);
					flagword fflag = symbol_table[i]->flags;



					if (!(fflag & BSF_SECTION_SYM) && symbol_table[i]->value != 0)
					{
						PRINT(BSF_LOCAL);
						PRINT(BSF_GLOBAL);
						PRINT(BSF_EXPORT);
						PRINT(BSF_DEBUGGING);
						PRINT(BSF_FUNCTION);
						PRINT(BSF_KEEP);
						PRINT(BSF_WEAK);
						PRINT(BSF_SECTION_SYM);
						PRINT(BSF_CONSTRUCTOR);
						PRINT(BSF_WARNING);
						PRINT(BSF_INDIRECT);
						PRINT(BSF_FILE);
						PRINT(BSF_DYNAMIC);
						PRINT(BSF_OBJECT);
						PRINT(BSF_DEBUGGING_RELOC);
						PRINT(BSF_THREAD_LOCAL);
						PRINT(BSF_RELC);
						PRINT(BSF_SRELC);
						PRINT(BSF_SYNTHETIC);
						PRINT(BSF_GNU_INDIRECT_FUNCTION);
						PRINT(BSF_GNU_UNIQUE);
					}
					printf("\n**********************************\n");
				}
			}
			free(symbol_table);
		}
	}
}

int main()
{
	bfd_init();
	const char** pptr = bfd_target_list();
	while (pptr != NULL && *pptr != NULL)
	{
		printf("targetList: %s\n", *pptr);
		pptr ++;
	}
	bfd* abfd = bfd_openr("/home/nick/Downloads/jad/library/libjavacdromwrapper.so", NULL);
	if (abfd != NULL)
	{
		if (bfd_check_format(abfd, bfd_object))
		{
			bfd_flavour flavor;
			if  ( (flavor= bfd_get_flavour( abfd ))!= bfd_target_unknown_flavour )
			{
				printf("bfd: %s\n", bfd_printable_name(abfd));
				printf("flavor: %d\n", flavor);
				//printf("flavor name:%s\n", bfd_flavour_name(flavor));
				printf("filename:%s\n", bfd_get_filename(abfd));
				printf("fileformat:%d\n", bfd_get_format(abfd));
				printf("format string:%s\n", bfd_format_string(bfd_get_format(abfd)));
				printf("target: %s\n", bfd_get_target(abfd));
				printf("little endian:%d\n", bfd_little_endian(abfd));
				printf("symcount: %d\n", bfd_get_symcount(abfd));
				printf("section count:%d\n", bfd_count_sections(abfd));
				flagword fflag = BFD_NO_FLAGS;

				fflag = bfd_applicable_file_flags(abfd);
				printf("fileflag HAS_RELOC: %d\n", fflag&HAS_RELOC);
				printf("fileflag EXEC_P: %d\n", fflag&EXEC_P);
				printf("fileflag HAS_LINENO: %d\n", fflag&HAS_LINENO);
				printf("fileflag HAS_DEBUG: %d\n", fflag&HAS_DEBUG);
				printf("fileflag HAS_SYMS: %d\n", fflag&HAS_SYMS);
				printf("fileflag HAS_LOCALS: %d\n", fflag&HAS_LOCALS);
				printf("fileflag DYNAMIC: %d\n", fflag&DYNAMIC);
				printf("fileflag BFD_LINKER_CREATED: %d\n", fflag&BFD_LINKER_CREATED);
				printf("fileflag BFD_COMPRESS: %d\n", fflag&BFD_COMPRESS);

				printf("fileflag D_PAGED: %d\n", fflag&D_PAGED);
				printf("fileflag BFD_IS_RELAXABLE: %d\n", fflag&BFD_IS_RELAXABLE);
				printf("fileflag BFD_TRADITIONAL_FORMAT: %d\n", fflag&BFD_TRADITIONAL_FORMAT);
				printf("fileflag BFD_IN_MEMORY: %d\n", fflag&BFD_IN_MEMORY);
				printf("fileflag BFD_DETERMINISTIC_OUTPUT: %d\n", fflag&BFD_DETERMINISTIC_OUTPUT);
				printf("fileflag BFD_PLUGIN: %d\n", fflag&BFD_PLUGIN);
				printf("fileflag BFD_FLAGS_SAVED: %d\n", fflag&BFD_FLAGS_SAVED);
				printf("fileflag BFD_FLAGS_FOR_BFD_USE_MASK: %d\n", fflag&BFD_FLAGS_FOR_BFD_USE_MASK);


				fflag = bfd_applicable_section_flags(abfd);
				printf("fileflag HAS_RELOC: %d\n", fflag&HAS_RELOC);
				printf("fileflag EXEC_P: %d\n", fflag&EXEC_P);
				printf("fileflag HAS_LINENO: %d\n", fflag&HAS_LINENO);
				printf("fileflag HAS_DEBUG: %d\n", fflag&HAS_DEBUG);
				printf("fileflag HAS_SYMS: %d\n", fflag&HAS_SYMS);
				printf("fileflag HAS_LOCALS: %d\n", fflag&HAS_LOCALS);
				printf("fileflag DYNAMIC: %d\n", fflag&DYNAMIC);
				printf("fileflag BFD_LINKER_CREATED: %d\n", fflag&BFD_LINKER_CREATED);
				printf("fileflag BFD_COMPRESS: %d\n", fflag&BFD_COMPRESS);

				printf("fileflag D_PAGED: %d\n", fflag&D_PAGED);
				printf("fileflag BFD_IS_RELAXABLE: %d\n", fflag&BFD_IS_RELAXABLE);
				printf("fileflag BFD_TRADITIONAL_FORMAT: %d\n", fflag&BFD_TRADITIONAL_FORMAT);
				printf("fileflag BFD_IN_MEMORY: %d\n", fflag&BFD_IN_MEMORY);
				printf("fileflag BFD_DETERMINISTIC_OUTPUT: %d\n", fflag&BFD_DETERMINISTIC_OUTPUT);
				printf("fileflag BFD_PLUGIN: %d\n", fflag&BFD_PLUGIN);
				printf("fileflag BFD_FLAGS_SAVED: %d\n", fflag&BFD_FLAGS_SAVED);
				printf("fileflag BFD_FLAGS_FOR_BFD_USE_MASK: %d\n", fflag&BFD_FLAGS_FOR_BFD_USE_MASK);

				if ( bfd_get_file_flags(abfd) & HAS_SYMS )
				{
					//processSymbols(abfd);
					//printf("next section id: %d\n", bfd_get_next_section_id());
					asection* asec = abfd->sections;
					while  (asec)
					{
						printf("name: %s\n", asec->name);
						printf("id: %d\n", asec->id);
						printf("index: %d\n", asec->index);
						printf("entsize: %u\n", asec->entsize);
						flagword fflag = asec->flags;
						PRINT(SEC_ALLOC);
						PRINT(SEC_LOAD);
						PRINT(SEC_RELOC);
						PRINT(SEC_READONLY);
						PRINT(SEC_CODE);
						PRINT(SEC_DATA);
						PRINT(SEC_ROM);
						PRINT(SEC_CONSTRUCTOR);
						PRINT(SEC_HAS_CONTENTS);
						PRINT(SEC_NEVER_LOAD);
						PRINT(SEC_THREAD_LOCAL);
						PRINT(SEC_HAS_GOT_REF);
						PRINT(SEC_IS_COMMON);
						PRINT(SEC_DEBUGGING);
						PRINT(SEC_IN_MEMORY);
						PRINT(SEC_EXCLUDE);
						PRINT(SEC_SORT_ENTRIES);
						PRINT(SEC_LINK_ONCE);
						PRINT(SEC_LINK_DUPLICATES);
						PRINT(SEC_LINK_DUPLICATES_DISCARD);
						PRINT(SEC_LINK_DUPLICATES_ONE_ONLY);
						PRINT(SEC_LINK_DUPLICATES_SAME_SIZE);
						PRINT(SEC_LINK_DUPLICATES_SAME_CONTENTS);
						PRINT(SEC_LINKER_CREATED);
						PRINT(SEC_KEEP);
						PRINT(SEC_SMALL_DATA);
						PRINT(SEC_MERGE);
						PRINT(SEC_STRINGS);
						PRINT(SEC_GROUP);
						PRINT(SEC_COFF_SHARED_LIBRARY);
						PRINT(SEC_ELF_REVERSE_COPY);
						PRINT(SEC_COFF_SHARED);
						PRINT(SEC_TIC54X_BLOCK);
						PRINT(SEC_COFF_NOREAD);
						printf("\n******************\n");
						asec = asec->next;
					}
				}
			}
		}
		bfd_close(abfd);
		abfd = NULL;
	}

	return 0;
}
