static void test_resolve_metrolyrics (void) { GrlSource *source; guint i; struct { gchar *title; gchar *artist; gchar *lyrics_file; } audios[] = { { "ring of fire", "johnny cash", LYRICS_RING_OF_FIRE }, { "back it up", "caro emerald", LYRICS_BACK_IT_UP }, { "bohemian rhapsody", "queen", LYRICS_BOHEMIAN_RHAPSODY }, { "nobodys perfect", "jessie j", LYRICS_NOBODYS_PERFECT }, { "100% pure love", "crystal waters", NULL }, }; source = test_lua_factory_get_source (METROLYRICS_ID, METROLYRICS_OPS); for (i = 0; i < G_N_ELEMENTS (audios); i++) { gchar *lyrics, *data; GFile *file; gsize size; GError *error = NULL; lyrics = get_lyrics (source, audios[i].artist, audios[i].title); if (audios[i].lyrics_file == NULL) { /* We are not interested in comparing this lyrics */ g_clear_pointer (&lyrics, g_free); continue; } g_assert_nonnull (lyrics); file = g_file_new_for_uri (audios[i].lyrics_file); g_file_load_contents (file, NULL, &data, &size, NULL, &error); g_assert_no_error (error); g_clear_pointer (&file, g_object_unref); if (g_ascii_strncasecmp (lyrics, data, size - 1) != 0) { g_warning ("Lyrics of '%s' from '%s' changed. Check if metrolyrics.com changed", audios[i].title, audios[i].artist); } g_clear_pointer (&lyrics, g_free); g_clear_pointer (&data, g_free); } }
static void test_resolve_metrolyrics_bad_request (void) { GrlSource *source; guint i; struct { gchar *title; gchar *artist; gchar *lyrics_file; } audios[] = { { "GNOME", "grilo framework", NULL }, }; source = test_lua_factory_get_source (METROLYRICS_ID, METROLYRICS_OPS); for (i = 0; i < G_N_ELEMENTS (audios); i++) { gchar *lyrics; g_test_expect_message("Grilo", G_LOG_LEVEL_WARNING, "*Can't fetch element*"); lyrics = get_lyrics (source, audios[i].artist, audios[i].title); g_assert_null (lyrics); } }
int main(int argc, char **argv) { FILE *file; char instruction; char* filename; struct vector instruction_stream; if(argc != 2) { /* wrong number of args */ fprintf(stderr, "Error: exactly 1 HQ9+ source file as arg required\n"); exit(EXIT_FAILURE); } /* open file */ filename = argv[1]; file = fopen(filename, "r"); if (file == NULL) { /* could not open file */ perror("Error opening file"); exit(EXIT_FAILURE); } /*** prologue ***/ vector_create(&instruction_stream, 100); char prologue [] = { 0x55, // push %rbp 0x48, 0x89, 0xE5, // mov %rsp, %rbp // backup %r12 (callee saved register) 0x41, 0x54, // pushq %r12 // store %rdi content (putchar) in %r12 as callee saved 0x49, 0x89, 0xFC, // movq %rdi, %r12 // push accumulator on stack 0x6a, 0x00, // pushq $0 }; vector_push(&instruction_stream, prologue, sizeof(prologue)); int stack_offset = -0x10; // offset from %rbp int offset_accumulator = stack_offset; // accumulator address: -0x10(%rbp) // hello world write_to_stack(&instruction_stream, "Hello World\n", &stack_offset); int offset_hello_world = stack_offset; // source code char* source_code = get_source_code(filename); write_to_stack(&instruction_stream, source_code, &stack_offset); free(source_code); int offset_source = stack_offset; // lyrics char* lyrics = get_lyrics(99); write_to_stack(&instruction_stream, lyrics, &stack_offset); free(lyrics); int offset_bottles = stack_offset; // everything after accumulator is text bytes int text_bytes_on_stack = -(stack_offset - offset_accumulator); /*** parse file ***/ while((instruction = fgetc(file)) != EOF) { switch (instruction) { case 'H': { // access single chars of int char *hw = (char*) &offset_hello_world; char opcodes [] = { 0xB0, 00, // movb $0, %al 0x48, 0x8D, 0xBD, hw[0], hw[1], hw[2], hw[3], // leaq -0x<offset>(%rbp),%rdi 0x41, 0xFF, 0xD4 // callq *%r12 }; vector_push(&instruction_stream, opcodes, sizeof(opcodes)); } break; case 'Q': { // access single chars of int char *s = (char*) &offset_source; char opcodes [] = { 0xB0, 00, // movb $0, %al 0x48, 0x8D, 0xBD, s[0], s[1], s[2], s[3], // leaq -0x<offset>(%rbp),%rdi 0x41, 0xFF, 0xD4 // callq *%r12 }; vector_push(&instruction_stream, opcodes, sizeof(opcodes)); } break; case '9': { // access single chars of int char *b = (char*) &offset_bottles; char opcodes [] = { 0xB0, 00, // movb $0, %al 0x48, 0x8D, 0xBD, b[0], b[1], b[2], b[3], // leaq -0x<offset>(%rbp),%rdi // 0xBF, 0x39, 0x00, 0x00, 0x00, // mov $0x39, %edi 0x41, 0xFF, 0xD4 // callq *%r12 }; vector_push(&instruction_stream, opcodes, sizeof(opcodes)); } break; case '+': { char *acc = (char*) &offset_accumulator; char opcodes [] = { // increment the accumulator // TODO from variable instead of constant offset 0x48, 0xFF, 0x45, 0xF0, // incq -0x10(%rbp) }; vector_push(&instruction_stream, opcodes, sizeof(opcodes)); } break; } } if (!feof(file)) { perror("Error reading file"); } fclose(file); /*** epilogue ***/ // access single chars of long char *t = (char*) &text_bytes_on_stack; char epilogue [] = { // free strings 0x48, 0x81, 0xC4, t[0], t[1], t[2], t[3], // addq $<x>, %rsp // free accumulator 0x48, 0x83, 0xC4, 0x08, // addq $8, %rsp // restore callee saved register 0x41, 0x5C, // popq %r12 0x5d, // pop rbp 0xC3 // ret }; vector_push(&instruction_stream, epilogue, sizeof(epilogue)); /*** invoke generated code ***/ /* allocate and copy instruction stream into executable memory */ void* mem = mmap(NULL, instruction_stream.size, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); memcpy(mem, instruction_stream.data, instruction_stream.size); /* typecast memory to a function pointer and call the dynamically created executable code */ void (*hq9p_program) (fn_printf) = mem; hq9p_program(printf); /* clear up */ munmap(mem, instruction_stream.size); vector_destroy(&instruction_stream); exit(EXIT_SUCCESS); }